Merge branch 'main' of https://github.com/embassy-rs/embassy into can
This commit is contained in:
commit
aaad906815
44
.github/ci/doc.sh
vendored
Executable file
44
.github/ci/doc.sh
vendored
Executable file
@ -0,0 +1,44 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
## on push branch=main
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
export RUSTUP_HOME=/ci/cache/rustup
|
||||||
|
export CARGO_HOME=/ci/cache/cargo
|
||||||
|
export CARGO_TARGET_DIR=/ci/cache/target
|
||||||
|
export BUILDER_THREADS=6
|
||||||
|
export BUILDER_COMPRESS=true
|
||||||
|
|
||||||
|
# force rustup to download the toolchain before starting building.
|
||||||
|
# Otherwise, the docs builder is running multiple instances of cargo rustdoc concurrently.
|
||||||
|
# They all see the toolchain is not installed and try to install it in parallel
|
||||||
|
# which makes rustup very sad
|
||||||
|
rustc --version > /dev/null
|
||||||
|
|
||||||
|
docserver-builder -i ./embassy-stm32 -o crates/embassy-stm32/git.zup
|
||||||
|
docserver-builder -i ./embassy-boot/boot -o crates/embassy-boot/git.zup
|
||||||
|
docserver-builder -i ./embassy-boot/nrf -o crates/embassy-boot-nrf/git.zup
|
||||||
|
docserver-builder -i ./embassy-boot/rp -o crates/embassy-boot-rp/git.zup
|
||||||
|
docserver-builder -i ./embassy-boot/stm32 -o crates/embassy-boot-stm32/git.zup
|
||||||
|
docserver-builder -i ./embassy-embedded-hal -o crates/embassy-embedded-hal/git.zup
|
||||||
|
docserver-builder -i ./embassy-executor -o crates/embassy-executor/git.zup
|
||||||
|
docserver-builder -i ./embassy-futures -o crates/embassy-futures/git.zup
|
||||||
|
docserver-builder -i ./embassy-lora -o crates/embassy-lora/git.zup
|
||||||
|
docserver-builder -i ./embassy-net -o crates/embassy-net/git.zup
|
||||||
|
docserver-builder -i ./embassy-net-driver -o crates/embassy-net-driver/git.zup
|
||||||
|
docserver-builder -i ./embassy-net-driver-channel -o crates/embassy-net-driver-channel/git.zup
|
||||||
|
docserver-builder -i ./embassy-nrf -o crates/embassy-nrf/git.zup
|
||||||
|
docserver-builder -i ./embassy-rp -o crates/embassy-rp/git.zup
|
||||||
|
docserver-builder -i ./embassy-sync -o crates/embassy-sync/git.zup
|
||||||
|
docserver-builder -i ./embassy-time -o crates/embassy-time/git.zup
|
||||||
|
docserver-builder -i ./embassy-usb -o crates/embassy-usb/git.zup
|
||||||
|
docserver-builder -i ./embassy-usb-driver -o crates/embassy-usb-driver/git.zup
|
||||||
|
docserver-builder -i ./embassy-usb-logger -o crates/embassy-usb-logger/git.zup
|
||||||
|
docserver-builder -i ./cyw43 -o crates/cyw43/git.zup
|
||||||
|
docserver-builder -i ./cyw43-pio -o crates/cyw43-pio/git.zup
|
||||||
|
docserver-builder -i ./embassy-net-w5500 -o crates/embassy-net-w5500/git.zup
|
||||||
|
docserver-builder -i ./embassy-stm32-wpan -o crates/embassy-stm32-wpan/git.zup
|
||||||
|
|
||||||
|
export KUBECONFIG=/ci/secrets/kubeconfig.yml
|
||||||
|
POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name})
|
||||||
|
kubectl cp crates $POD:/data
|
87
.github/workflows/doc.yml
vendored
87
.github/workflows/doc.yml
vendored
@ -1,87 +0,0 @@
|
|||||||
name: Docs
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [main]
|
|
||||||
|
|
||||||
env:
|
|
||||||
BUILDER_THREADS: '1'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
doc:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
# Since stm32 crates take SO LONG to build, we split them
|
|
||||||
# into a separate job. This way it doesn't slow down updating
|
|
||||||
# the rest.
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
crates:
|
|
||||||
#- stm32 # runs out of disk space...
|
|
||||||
- rest
|
|
||||||
|
|
||||||
# This will ensure at most one doc build job is running at a time
|
|
||||||
# (for stm32 and non-stm32 independently).
|
|
||||||
# If another job is already running, the new job will wait.
|
|
||||||
# If another job is already waiting, it'll be canceled.
|
|
||||||
# This means some commits will be skipped, but that's fine because
|
|
||||||
# we only care that the latest gets built.
|
|
||||||
concurrency: doc-${{ matrix.crates }}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
- name: Install Rust targets
|
|
||||||
run: |
|
|
||||||
rustup target add x86_64-unknown-linux-gnu
|
|
||||||
rustup target add wasm32-unknown-unknown
|
|
||||||
rustup target add thumbv6m-none-eabi
|
|
||||||
rustup target add thumbv7m-none-eabi
|
|
||||||
rustup target add thumbv7em-none-eabi
|
|
||||||
rustup target add thumbv7em-none-eabihf
|
|
||||||
rustup target add thumbv8m.base-none-eabi
|
|
||||||
rustup target add thumbv8m.main-none-eabi
|
|
||||||
rustup target add thumbv8m.main-none-eabihf
|
|
||||||
|
|
||||||
- name: Install docserver
|
|
||||||
run: |
|
|
||||||
wget -q -O /usr/local/bin/builder "https://github.com/embassy-rs/docserver/releases/download/v0.4/builder"
|
|
||||||
chmod +x /usr/local/bin/builder
|
|
||||||
|
|
||||||
- name: build-stm32
|
|
||||||
if: ${{ matrix.crates=='stm32' }}
|
|
||||||
run: |
|
|
||||||
mkdir crates
|
|
||||||
builder ./embassy-stm32 crates/embassy-stm32/git.zup
|
|
||||||
|
|
||||||
- name: build-rest
|
|
||||||
if: ${{ matrix.crates=='rest' }}
|
|
||||||
run: |
|
|
||||||
mkdir crates
|
|
||||||
builder ./embassy-boot/boot crates/embassy-boot/git.zup
|
|
||||||
builder ./embassy-boot/nrf crates/embassy-boot-nrf/git.zup
|
|
||||||
builder ./embassy-boot/rp crates/embassy-boot-rp/git.zup
|
|
||||||
builder ./embassy-boot/stm32 crates/embassy-boot-stm32/git.zup
|
|
||||||
builder ./embassy-cortex-m crates/embassy-cortex-m/git.zup
|
|
||||||
builder ./embassy-embedded-hal crates/embassy-embedded-hal/git.zup
|
|
||||||
builder ./embassy-executor crates/embassy-executor/git.zup
|
|
||||||
builder ./embassy-futures crates/embassy-futures/git.zup
|
|
||||||
builder ./embassy-lora crates/embassy-lora/git.zup
|
|
||||||
builder ./embassy-net crates/embassy-net/git.zup
|
|
||||||
builder ./embassy-net-driver crates/embassy-net-driver/git.zup
|
|
||||||
builder ./embassy-net-driver-channel crates/embassy-net-driver-channel/git.zup
|
|
||||||
builder ./embassy-nrf crates/embassy-nrf/git.zup
|
|
||||||
builder ./embassy-rp crates/embassy-rp/git.zup
|
|
||||||
builder ./embassy-sync crates/embassy-sync/git.zup
|
|
||||||
builder ./embassy-time crates/embassy-time/git.zup
|
|
||||||
builder ./embassy-usb crates/embassy-usb/git.zup
|
|
||||||
builder ./embassy-usb-driver crates/embassy-usb-driver/git.zup
|
|
||||||
builder ./embassy-usb-logger crates/embassy-usb-logger/git.zup
|
|
||||||
|
|
||||||
- name: upload
|
|
||||||
run: |
|
|
||||||
mkdir -p ~/.kube
|
|
||||||
echo "${{secrets.KUBECONFIG}}" > ~/.kube/config
|
|
||||||
POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name})
|
|
||||||
kubectl cp crates $POD:/data
|
|
14
ci.sh
14
ci.sh
@ -3,7 +3,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
export RUSTFLAGS=-Dwarnings
|
export RUSTFLAGS=-Dwarnings
|
||||||
export DEFMT_LOG=trace
|
export DEFMT_LOG=trace,cyw43=info,cyw43_pio=info,smoltcp=info
|
||||||
|
|
||||||
# needed by wifi examples
|
# needed by wifi examples
|
||||||
export WIFI_NETWORK=x
|
export WIFI_NETWORK=x
|
||||||
@ -25,11 +25,19 @@ cargo batch \
|
|||||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
|
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
|
||||||
--- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
|
--- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
|
||||||
--- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits,defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \
|
--- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits,defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,medium-ethernet \
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits \
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits \
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,nightly \
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,nightly \
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits,nightly \
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits,nightly \
|
||||||
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \
|
||||||
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,unstable-traits \
|
||||||
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,nightly \
|
||||||
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,unstable-traits,nightly \
|
||||||
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet \
|
||||||
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet,unstable-traits \
|
||||||
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet,nightly \
|
||||||
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet,unstable-traits,nightly \
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52805,gpiote,time-driver-rtc1 \
|
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52805,gpiote,time-driver-rtc1 \
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52810,gpiote,time-driver-rtc1 \
|
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52810,gpiote,time-driver-rtc1 \
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52811,gpiote,time-driver-rtc1 \
|
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52811,gpiote,time-driver-rtc1 \
|
||||||
@ -71,6 +79,7 @@ cargo batch \
|
|||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,unstable-traits \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l422cb,defmt,exti,time-driver-any,unstable-traits \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wb15cc,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wb15cc,defmt,exti,time-driver-any,unstable-traits \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l072cz,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l072cz,defmt,exti,time-driver-any,unstable-traits \
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l041f6,defmt,exti,time-driver-any,unstable-traits \
|
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l041f6,defmt,exti,time-driver-any,unstable-traits \
|
||||||
@ -103,6 +112,7 @@ cargo batch \
|
|||||||
--- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-irq/Cargo.toml --target thumbv7em-none-eabi \
|
--- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-irq/Cargo.toml --target thumbv7em-none-eabi \
|
||||||
--- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml --target thumbv7em-none-eabi \
|
--- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml --target thumbv7em-none-eabi \
|
||||||
--- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \
|
--- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \
|
||||||
|
--- build --release --manifest-path examples/nrf52840-rtic/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840-rtic \
|
||||||
--- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \
|
--- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \
|
||||||
--- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \
|
--- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \
|
||||||
--- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \
|
--- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \
|
||||||
|
@ -14,9 +14,11 @@ cargo batch \
|
|||||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features log \
|
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features log \
|
||||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features defmt \
|
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features defmt \
|
||||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt \
|
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt \
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,medium-ethernet \
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits \
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,unstable-traits \
|
||||||
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \
|
||||||
|
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,unstable-traits \
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52805,gpiote,time-driver-rtc1 \
|
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52805,gpiote,time-driver-rtc1 \
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52810,gpiote,time-driver-rtc1 \
|
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52810,gpiote,time-driver-rtc1 \
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52811,gpiote,time-driver-rtc1 \
|
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52811,gpiote,time-driver-rtc1 \
|
||||||
|
@ -15,3 +15,8 @@ pio-proc = "0.2"
|
|||||||
pio = "0.2.1"
|
pio = "0.2.1"
|
||||||
fixed = "1.23.1"
|
fixed = "1.23.1"
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
|
|
||||||
|
[package.metadata.embassy_docs]
|
||||||
|
src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-pio-v$VERSION/cyw43-pio/src/"
|
||||||
|
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43-pio/src/"
|
||||||
|
target = "thumbv6m-none-eabi"
|
||||||
|
@ -26,3 +26,9 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa
|
|||||||
|
|
||||||
embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.10" }
|
embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.10" }
|
||||||
num_enum = { version = "0.5.7", default-features = false }
|
num_enum = { version = "0.5.7", default-features = false }
|
||||||
|
|
||||||
|
[package.metadata.embassy_docs]
|
||||||
|
src_base = "https://github.com/embassy-rs/embassy/blob/cyw43-v$VERSION/cyw43/src/"
|
||||||
|
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/cyw43/src/"
|
||||||
|
target = "thumbv6m-none-eabi"
|
||||||
|
features = ["defmt", "firmware-logs"]
|
@ -381,10 +381,7 @@ impl<'a> Control<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let ioctl = CancelOnDrop(self.ioctl_state);
|
let ioctl = CancelOnDrop(self.ioctl_state);
|
||||||
|
let resp_len = ioctl.0.do_ioctl(kind, cmd, iface, buf).await;
|
||||||
ioctl.0.do_ioctl(kind, cmd, iface, buf).await;
|
|
||||||
let resp_len = ioctl.0.wait_complete().await;
|
|
||||||
|
|
||||||
ioctl.defuse();
|
ioctl.defuse();
|
||||||
|
|
||||||
resp_len
|
resp_len
|
||||||
|
@ -197,9 +197,6 @@ macro_rules! unwrap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "defmt-timestamp-uptime")]
|
|
||||||
defmt::timestamp! {"{=u64:us}", crate::time::Instant::now().as_micros() }
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
pub struct NoneError;
|
pub struct NoneError;
|
||||||
|
|
||||||
|
@ -20,13 +20,13 @@ fn main() -> ! {
|
|||||||
let led = Output::new(p.PB14, Level::Low, Speed::Low);
|
let led = Output::new(p.PB14, Level::Low, Speed::Low);
|
||||||
let mut button = Input::new(p.PC13, Pull::Up);
|
let mut button = Input::new(p.PC13, Pull::Up);
|
||||||
|
|
||||||
cortex_m::interrupt::free(|cs| unsafe {
|
cortex_m::interrupt::free(|cs| {
|
||||||
enable_interrupt(&mut button);
|
enable_interrupt(&mut button);
|
||||||
|
|
||||||
LED.borrow(cs).borrow_mut().replace(led);
|
LED.borrow(cs).borrow_mut().replace(led);
|
||||||
BUTTON.borrow(cs).borrow_mut().replace(button);
|
BUTTON.borrow(cs).borrow_mut().replace(button);
|
||||||
|
|
||||||
NVIC::unmask(pac::Interrupt::EXTI15_10);
|
unsafe { NVIC::unmask(pac::Interrupt::EXTI15_10) };
|
||||||
});
|
});
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@ -64,25 +64,21 @@ const PORT: u8 = 2;
|
|||||||
const PIN: usize = 13;
|
const PIN: usize = 13;
|
||||||
fn check_interrupt<P: Pin>(_pin: &mut Input<'static, P>) -> bool {
|
fn check_interrupt<P: Pin>(_pin: &mut Input<'static, P>) -> bool {
|
||||||
let exti = pac::EXTI;
|
let exti = pac::EXTI;
|
||||||
unsafe {
|
|
||||||
let pin = PIN;
|
let pin = PIN;
|
||||||
let lines = exti.pr(0).read();
|
let lines = exti.pr(0).read();
|
||||||
lines.line(pin)
|
lines.line(pin)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_interrupt<P: Pin>(_pin: &mut Input<'static, P>) {
|
fn clear_interrupt<P: Pin>(_pin: &mut Input<'static, P>) {
|
||||||
let exti = pac::EXTI;
|
let exti = pac::EXTI;
|
||||||
unsafe {
|
|
||||||
let pin = PIN;
|
let pin = PIN;
|
||||||
let mut lines = exti.pr(0).read();
|
let mut lines = exti.pr(0).read();
|
||||||
lines.set_line(pin, true);
|
lines.set_line(pin, true);
|
||||||
exti.pr(0).write_value(lines);
|
exti.pr(0).write_value(lines);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enable_interrupt<P: Pin>(_pin: &mut Input<'static, P>) {
|
fn enable_interrupt<P: Pin>(_pin: &mut Input<'static, P>) {
|
||||||
cortex_m::interrupt::free(|_| unsafe {
|
cortex_m::interrupt::free(|_| {
|
||||||
let rcc = pac::RCC;
|
let rcc = pac::RCC;
|
||||||
rcc.apb2enr().modify(|w| w.set_syscfgen(true));
|
rcc.apb2enr().modify(|w| w.set_syscfgen(true));
|
||||||
|
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "embassy-cortex-m"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
license = "MIT OR Apache-2.0"
|
|
||||||
|
|
||||||
[package.metadata.embassy_docs]
|
|
||||||
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-cortex-m-v$VERSION/embassy-cortex-m/src/"
|
|
||||||
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-cortex-m/src/"
|
|
||||||
features = ["prio-bits-3"]
|
|
||||||
flavors = [
|
|
||||||
{ name = "thumbv6m-none-eabi", target = "thumbv6m-none-eabi", features = [] },
|
|
||||||
{ name = "thumbv7m-none-eabi", target = "thumbv7m-none-eabi", features = [] },
|
|
||||||
{ name = "thumbv7em-none-eabi", target = "thumbv7em-none-eabi", features = [] },
|
|
||||||
{ name = "thumbv7em-none-eabihf", target = "thumbv7em-none-eabihf", features = [] },
|
|
||||||
{ name = "thumbv8m.base-none-eabi", target = "thumbv8m.base-none-eabi", features = [] },
|
|
||||||
{ name = "thumbv8m.main-none-eabi", target = "thumbv8m.main-none-eabi", features = [] },
|
|
||||||
{ name = "thumbv8m.main-none-eabihf", target = "thumbv8m.main-none-eabihf", features = [] },
|
|
||||||
]
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = []
|
|
||||||
|
|
||||||
# Define the number of NVIC priority bits.
|
|
||||||
prio-bits-0 = []
|
|
||||||
prio-bits-1 = []
|
|
||||||
prio-bits-2 = []
|
|
||||||
prio-bits-3 = []
|
|
||||||
prio-bits-4 = []
|
|
||||||
prio-bits-5 = []
|
|
||||||
prio-bits-6 = []
|
|
||||||
prio-bits-7 = []
|
|
||||||
prio-bits-8 = []
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
defmt = { version = "0.3", optional = true }
|
|
||||||
log = { version = "0.4.14", optional = true }
|
|
||||||
|
|
||||||
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
|
|
||||||
embassy-executor = { version = "0.2.0", path = "../embassy-executor"}
|
|
||||||
embassy-macros = { version = "0.2.0", path = "../embassy-macros"}
|
|
||||||
embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common"}
|
|
||||||
atomic-polyfill = "1.0.1"
|
|
||||||
critical-section = "1.1"
|
|
||||||
cfg-if = "1.0.0"
|
|
||||||
cortex-m = "0.7.6"
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
|||||||
//! Embassy executor and interrupt handling specific to cortex-m devices.
|
|
||||||
#![no_std]
|
|
||||||
#![warn(missing_docs)]
|
|
||||||
|
|
||||||
// This mod MUST go first, so that the others see its macros.
|
|
||||||
pub(crate) mod fmt;
|
|
||||||
|
|
||||||
pub use embassy_executor as executor;
|
|
||||||
pub mod interrupt;
|
|
||||||
pub mod peripheral;
|
|
@ -1,144 +0,0 @@
|
|||||||
//! Peripheral interrupt handling specific to cortex-m devices.
|
|
||||||
use core::mem::MaybeUninit;
|
|
||||||
|
|
||||||
use cortex_m::peripheral::scb::VectActive;
|
|
||||||
use cortex_m::peripheral::{NVIC, SCB};
|
|
||||||
use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
|
|
||||||
|
|
||||||
use crate::interrupt::{Interrupt, InterruptExt, Priority};
|
|
||||||
|
|
||||||
/// A type which can be used as state with `PeripheralMutex`.
|
|
||||||
///
|
|
||||||
/// It needs to be `Send` because `&mut` references are sent back and forth between the 'thread' which owns the `PeripheralMutex` and the interrupt,
|
|
||||||
/// and `&mut T` is only `Send` where `T: Send`.
|
|
||||||
pub trait PeripheralState: Send {
|
|
||||||
/// The interrupt that is used for this peripheral.
|
|
||||||
type Interrupt: Interrupt;
|
|
||||||
|
|
||||||
/// The interrupt handler that should be invoked for the peripheral. Implementations need to clear the appropriate interrupt flags to ensure the handle will not be called again.
|
|
||||||
fn on_interrupt(&mut self);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A type for storing the state of a peripheral that can be stored in a static.
|
|
||||||
pub struct StateStorage<S>(MaybeUninit<S>);
|
|
||||||
|
|
||||||
impl<S> StateStorage<S> {
|
|
||||||
/// Create a new instance for storing peripheral state.
|
|
||||||
pub const fn new() -> Self {
|
|
||||||
Self(MaybeUninit::uninit())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A type for a peripheral that keeps the state of a peripheral that can be accessed from thread mode and an interrupt handler in
|
|
||||||
/// a safe way.
|
|
||||||
pub struct PeripheralMutex<'a, S: PeripheralState> {
|
|
||||||
state: *mut S,
|
|
||||||
irq: PeripheralRef<'a, S::Interrupt>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Whether `irq` can be preempted by the current interrupt.
|
|
||||||
pub(crate) fn can_be_preempted(irq: &impl Interrupt) -> bool {
|
|
||||||
match SCB::vect_active() {
|
|
||||||
// Thread mode can't preempt anything.
|
|
||||||
VectActive::ThreadMode => false,
|
|
||||||
// Exceptions don't always preempt interrupts,
|
|
||||||
// but there isn't much of a good reason to be keeping a `PeripheralMutex` in an exception anyway.
|
|
||||||
VectActive::Exception(_) => true,
|
|
||||||
VectActive::Interrupt { irqn } => {
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
struct NrWrap(u16);
|
|
||||||
unsafe impl cortex_m::interrupt::InterruptNumber for NrWrap {
|
|
||||||
fn number(self) -> u16 {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NVIC::get_priority(NrWrap(irqn.into())) < irq.get_priority().into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, S: PeripheralState> PeripheralMutex<'a, S> {
|
|
||||||
/// Create a new `PeripheralMutex` wrapping `irq`, with `init` initializing the initial state.
|
|
||||||
///
|
|
||||||
/// Registers `on_interrupt` as the `irq`'s handler, and enables it.
|
|
||||||
pub fn new(
|
|
||||||
irq: impl Peripheral<P = S::Interrupt> + 'a,
|
|
||||||
storage: &'a mut StateStorage<S>,
|
|
||||||
init: impl FnOnce() -> S,
|
|
||||||
) -> Self {
|
|
||||||
into_ref!(irq);
|
|
||||||
|
|
||||||
if can_be_preempted(&*irq) {
|
|
||||||
panic!(
|
|
||||||
"`PeripheralMutex` cannot be created in an interrupt with higher priority than the interrupt it wraps"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let state_ptr = storage.0.as_mut_ptr();
|
|
||||||
|
|
||||||
// Safety: The pointer is valid and not used by anyone else
|
|
||||||
// because we have the `&mut StateStorage`.
|
|
||||||
unsafe { state_ptr.write(init()) };
|
|
||||||
|
|
||||||
irq.disable();
|
|
||||||
irq.set_handler(|p| unsafe {
|
|
||||||
// Safety: it's OK to get a &mut to the state, since
|
|
||||||
// - We checked that the thread owning the `PeripheralMutex` can't preempt us in `new`.
|
|
||||||
// Interrupts' priorities can only be changed with raw embassy `Interrupts`,
|
|
||||||
// which can't safely store a `PeripheralMutex` across invocations.
|
|
||||||
// - We can't have preempted a with() call because the irq is disabled during it.
|
|
||||||
let state = &mut *(p as *mut S);
|
|
||||||
state.on_interrupt();
|
|
||||||
});
|
|
||||||
irq.set_handler_context(state_ptr as *mut ());
|
|
||||||
irq.enable();
|
|
||||||
|
|
||||||
Self { irq, state: state_ptr }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Access the peripheral state ensuring interrupts are disabled so that the state can be
|
|
||||||
/// safely accessed.
|
|
||||||
pub fn with<R>(&mut self, f: impl FnOnce(&mut S) -> R) -> R {
|
|
||||||
self.irq.disable();
|
|
||||||
|
|
||||||
// Safety: it's OK to get a &mut to the state, since the irq is disabled.
|
|
||||||
let state = unsafe { &mut *self.state };
|
|
||||||
let r = f(state);
|
|
||||||
|
|
||||||
self.irq.enable();
|
|
||||||
|
|
||||||
r
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether the wrapped interrupt is currently in a pending state.
|
|
||||||
pub fn is_pending(&self) -> bool {
|
|
||||||
self.irq.is_pending()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Forces the wrapped interrupt into a pending state.
|
|
||||||
pub fn pend(&self) {
|
|
||||||
self.irq.pend()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Forces the wrapped interrupt out of a pending state.
|
|
||||||
pub fn unpend(&self) {
|
|
||||||
self.irq.unpend()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the priority of the wrapped interrupt.
|
|
||||||
pub fn priority(&self) -> Priority {
|
|
||||||
self.irq.get_priority()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, S: PeripheralState> Drop for PeripheralMutex<'a, S> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.irq.disable();
|
|
||||||
self.irq.remove_handler();
|
|
||||||
|
|
||||||
// safety:
|
|
||||||
// - we initialized the state in `new`, so we know it's initialized.
|
|
||||||
// - the irq is disabled, so it won't preempt us while dropping.
|
|
||||||
unsafe { self.state.drop_in_place() }
|
|
||||||
}
|
|
||||||
}
|
|
@ -65,7 +65,7 @@ embassy-macros = { version = "0.2.0", path = "../embassy-macros" }
|
|||||||
embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true}
|
embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true}
|
||||||
atomic-polyfill = "1.0.1"
|
atomic-polyfill = "1.0.1"
|
||||||
critical-section = "1.1"
|
critical-section = "1.1"
|
||||||
static_cell = "1.0"
|
static_cell = "1.1"
|
||||||
|
|
||||||
# arch-cortex-m dependencies
|
# arch-cortex-m dependencies
|
||||||
cortex-m = { version = "0.7.6", optional = true }
|
cortex-m = { version = "0.7.6", optional = true }
|
||||||
|
@ -205,5 +205,20 @@ mod interrupt {
|
|||||||
|
|
||||||
executor.spawner().make_send()
|
executor.spawner().make_send()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a SendSpawner for this executor
|
||||||
|
///
|
||||||
|
/// This returns a [`SendSpawner`] you can use to spawn tasks on this
|
||||||
|
/// executor.
|
||||||
|
///
|
||||||
|
/// This MUST only be called on an executor that has already been spawned.
|
||||||
|
/// The function will panic otherwise.
|
||||||
|
pub fn spawner(&'static self) -> crate::SendSpawner {
|
||||||
|
if !self.started.load(Ordering::Acquire) {
|
||||||
|
panic!("InterruptExecutor::spawner() called on uninitialized executor.");
|
||||||
|
}
|
||||||
|
let executor = unsafe { (&*self.executor.get()).assume_init_ref() };
|
||||||
|
executor.spawner().make_send()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,3 +31,15 @@ pub fn block_on<F: Future>(mut fut: F) -> F::Output {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Poll a future once.
|
||||||
|
pub fn poll_once<F: Future>(mut fut: F) -> Poll<F::Output> {
|
||||||
|
// safety: we don't move the future after this line.
|
||||||
|
let mut fut = unsafe { Pin::new_unchecked(&mut fut) };
|
||||||
|
|
||||||
|
let raw_waker = RawWaker::new(ptr::null(), &VTABLE);
|
||||||
|
let waker = unsafe { Waker::from_raw(raw_waker) };
|
||||||
|
let mut cx = Context::from_waker(&waker);
|
||||||
|
|
||||||
|
fut.as_mut().poll(&mut cx)
|
||||||
|
}
|
||||||
|
@ -195,9 +195,6 @@ macro_rules! unwrap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "defmt-timestamp-uptime")]
|
|
||||||
defmt::timestamp! {"{=u64:us}", crate::time::Instant::now().as_micros() }
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
pub struct NoneError;
|
pub struct NoneError;
|
||||||
|
|
||||||
|
@ -6,8 +6,24 @@ license = "MIT OR Apache-2.0"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
||||||
|
# Define the number of NVIC priority bits.
|
||||||
|
prio-bits-0 = []
|
||||||
|
prio-bits-1 = []
|
||||||
|
prio-bits-2 = []
|
||||||
|
prio-bits-3 = []
|
||||||
|
prio-bits-4 = []
|
||||||
|
prio-bits-5 = []
|
||||||
|
prio-bits-6 = []
|
||||||
|
prio-bits-7 = []
|
||||||
|
prio-bits-8 = []
|
||||||
|
|
||||||
|
cortex-m = ["dep:cortex-m", "dep:critical-section"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
log = { version = "0.4.14", optional = true }
|
log = { version = "0.4.14", optional = true }
|
||||||
|
|
||||||
num-traits = { version = "0.2.14", default-features = false }
|
num-traits = { version = "0.2.14", default-features = false }
|
||||||
|
|
||||||
|
cortex-m = { version = "0.7.6", optional = true }
|
||||||
|
critical-section = { version = "1", optional = true }
|
@ -1,24 +1,115 @@
|
|||||||
//! Interrupt handling for cortex-m devices.
|
//! Interrupt handling for cortex-m devices.
|
||||||
use core::{mem, ptr};
|
use core::mem;
|
||||||
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
|
|
||||||
use atomic_polyfill::{compiler_fence, AtomicPtr, Ordering};
|
use cortex_m::interrupt::InterruptNumber;
|
||||||
use cortex_m::peripheral::NVIC;
|
use cortex_m::peripheral::NVIC;
|
||||||
use embassy_hal_common::Peripheral;
|
|
||||||
pub use embassy_macros::cortex_m_interrupt_take as take;
|
|
||||||
|
|
||||||
/// Do not use. Used for macros and HALs only. Not covered by semver guarantees.
|
/// Generate a standard `mod interrupt` for a HAL.
|
||||||
#[doc(hidden)]
|
#[macro_export]
|
||||||
pub mod _export {
|
macro_rules! interrupt_mod {
|
||||||
pub use atomic_polyfill as atomic;
|
($($irqs:ident),* $(,)?) => {
|
||||||
pub use embassy_macros::{cortex_m_interrupt as interrupt, cortex_m_interrupt_declare as declare};
|
#[cfg(feature = "rt")]
|
||||||
}
|
pub use cortex_m_rt::interrupt;
|
||||||
|
|
||||||
/// Interrupt handler trait.
|
/// Interrupt definitions.
|
||||||
///
|
pub mod interrupt {
|
||||||
/// Drivers that need to handle interrupts implement this trait.
|
pub use $crate::interrupt::{InterruptExt, Priority};
|
||||||
/// The user must ensure `on_interrupt()` is called every time the interrupt fires.
|
pub use crate::pac::Interrupt::*;
|
||||||
/// Drivers must use use [`Binding`] to assert at compile time that the user has done so.
|
pub use crate::pac::Interrupt;
|
||||||
pub trait Handler<I: Interrupt> {
|
|
||||||
|
/// Type-level interrupt infrastructure.
|
||||||
|
///
|
||||||
|
/// This module contains one *type* per interrupt. This is used for checking at compile time that
|
||||||
|
/// the interrupts are correctly bound to HAL drivers.
|
||||||
|
///
|
||||||
|
/// As an end user, you shouldn't need to use this module directly. Use the [`crate::bind_interrupts!`] macro
|
||||||
|
/// to bind interrupts, and the [`crate::interrupt`] module to manually register interrupt handlers and manipulate
|
||||||
|
/// interrupts directly (pending/unpending, enabling/disabling, setting the priority, etc...)
|
||||||
|
pub mod typelevel {
|
||||||
|
use super::InterruptExt;
|
||||||
|
|
||||||
|
mod sealed {
|
||||||
|
pub trait Interrupt {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Type-level interrupt.
|
||||||
|
///
|
||||||
|
/// This trait is implemented for all typelevel interrupt types in this module.
|
||||||
|
pub trait Interrupt: sealed::Interrupt {
|
||||||
|
|
||||||
|
/// Interrupt enum variant.
|
||||||
|
///
|
||||||
|
/// This allows going from typelevel interrupts (one type per interrupt) to
|
||||||
|
/// non-typelevel interrupts (a single `Interrupt` enum type, with one variant per interrupt).
|
||||||
|
const IRQ: super::Interrupt;
|
||||||
|
|
||||||
|
/// Enable the interrupt.
|
||||||
|
#[inline]
|
||||||
|
unsafe fn enable() {
|
||||||
|
Self::IRQ.enable()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Disable the interrupt.
|
||||||
|
#[inline]
|
||||||
|
fn disable() {
|
||||||
|
Self::IRQ.disable()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if interrupt is enabled.
|
||||||
|
#[inline]
|
||||||
|
fn is_enabled() -> bool {
|
||||||
|
Self::IRQ.is_enabled()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if interrupt is pending.
|
||||||
|
#[inline]
|
||||||
|
fn is_pending() -> bool {
|
||||||
|
Self::IRQ.is_pending()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set interrupt pending.
|
||||||
|
#[inline]
|
||||||
|
fn pend() {
|
||||||
|
Self::IRQ.pend()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unset interrupt pending.
|
||||||
|
#[inline]
|
||||||
|
fn unpend() {
|
||||||
|
Self::IRQ.unpend()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the priority of the interrupt.
|
||||||
|
#[inline]
|
||||||
|
fn get_priority() -> crate::interrupt::Priority {
|
||||||
|
Self::IRQ.get_priority()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the interrupt priority.
|
||||||
|
#[inline]
|
||||||
|
fn set_priority(prio: crate::interrupt::Priority) {
|
||||||
|
Self::IRQ.set_priority(prio)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$(
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
#[doc=stringify!($irqs)]
|
||||||
|
#[doc=" typelevel interrupt."]
|
||||||
|
pub enum $irqs {}
|
||||||
|
impl sealed::Interrupt for $irqs{}
|
||||||
|
impl Interrupt for $irqs {
|
||||||
|
const IRQ: super::Interrupt = super::Interrupt::$irqs;
|
||||||
|
}
|
||||||
|
)*
|
||||||
|
|
||||||
|
/// Interrupt handler trait.
|
||||||
|
///
|
||||||
|
/// Drivers that need to handle interrupts implement this trait.
|
||||||
|
/// The user must ensure `on_interrupt()` is called every time the interrupt fires.
|
||||||
|
/// Drivers must use use [`Binding`] to assert at compile time that the user has done so.
|
||||||
|
pub trait Handler<I: Interrupt> {
|
||||||
/// Interrupt handler function.
|
/// Interrupt handler function.
|
||||||
///
|
///
|
||||||
/// Must be called every time the `I` interrupt fires, synchronously from
|
/// Must be called every time the `I` interrupt fires, synchronously from
|
||||||
@ -28,188 +119,91 @@ pub trait Handler<I: Interrupt> {
|
|||||||
///
|
///
|
||||||
/// This function must ONLY be called from the interrupt handler for `I`.
|
/// This function must ONLY be called from the interrupt handler for `I`.
|
||||||
unsafe fn on_interrupt();
|
unsafe fn on_interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compile-time assertion that an interrupt has been bound to a handler.
|
/// Compile-time assertion that an interrupt has been bound to a handler.
|
||||||
///
|
///
|
||||||
/// For the vast majority of cases, you should use the `bind_interrupts!`
|
/// For the vast majority of cases, you should use the `bind_interrupts!`
|
||||||
/// macro instead of writing `unsafe impl`s of this trait.
|
/// macro instead of writing `unsafe impl`s of this trait.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// By implementing this trait, you are asserting that you have arranged for `H::on_interrupt()`
|
/// By implementing this trait, you are asserting that you have arranged for `H::on_interrupt()`
|
||||||
/// to be called every time the `I` interrupt fires.
|
/// to be called every time the `I` interrupt fires.
|
||||||
///
|
///
|
||||||
/// This allows drivers to check bindings at compile-time.
|
/// This allows drivers to check bindings at compile-time.
|
||||||
pub unsafe trait Binding<I: Interrupt, H: Handler<I>> {}
|
pub unsafe trait Binding<I: Interrupt, H: Handler<I>> {}
|
||||||
|
|
||||||
/// Implementation detail, do not use outside embassy crates.
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub struct DynHandler {
|
|
||||||
pub func: AtomicPtr<()>,
|
|
||||||
pub ctx: AtomicPtr<()>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DynHandler {
|
|
||||||
pub const fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
func: AtomicPtr::new(ptr::null_mut()),
|
|
||||||
ctx: AtomicPtr::new(ptr::null_mut()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub(crate) struct NrWrap(pub(crate) u16);
|
|
||||||
unsafe impl cortex_m::interrupt::InterruptNumber for NrWrap {
|
|
||||||
fn number(self) -> u16 {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents an interrupt type that can be configured by embassy to handle
|
/// Represents an interrupt type that can be configured by embassy to handle
|
||||||
/// interrupts.
|
/// interrupts.
|
||||||
pub unsafe trait Interrupt: Peripheral<P = Self> {
|
pub unsafe trait InterruptExt: InterruptNumber + Copy {
|
||||||
/// Return the NVIC interrupt number for this interrupt.
|
/// Enable the interrupt.
|
||||||
fn number(&self) -> u16;
|
#[inline]
|
||||||
/// Steal an instance of this interrupt
|
unsafe fn enable(self) {
|
||||||
///
|
compiler_fence(Ordering::SeqCst);
|
||||||
/// # Safety
|
NVIC::unmask(self)
|
||||||
///
|
}
|
||||||
/// This may panic if the interrupt has already been stolen and configured.
|
|
||||||
unsafe fn steal() -> Self;
|
|
||||||
|
|
||||||
/// Implementation detail, do not use outside embassy crates.
|
|
||||||
#[doc(hidden)]
|
|
||||||
unsafe fn __handler(&self) -> &'static DynHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Represents additional behavior for all interrupts.
|
|
||||||
pub trait InterruptExt: Interrupt {
|
|
||||||
/// Configure the interrupt handler for this interrupt.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// It is the responsibility of the caller to ensure the handler
|
|
||||||
/// points to a valid handler as long as interrupts are enabled.
|
|
||||||
fn set_handler(&self, func: unsafe fn(*mut ()));
|
|
||||||
|
|
||||||
/// Remove the interrupt handler for this interrupt.
|
|
||||||
fn remove_handler(&self);
|
|
||||||
|
|
||||||
/// Set point to a context that is passed to the interrupt handler when
|
|
||||||
/// an interrupt is pending.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// It is the responsibility of the caller to ensure the context
|
|
||||||
/// points to a valid handler as long as interrupts are enabled.
|
|
||||||
fn set_handler_context(&self, ctx: *mut ());
|
|
||||||
|
|
||||||
/// Enable the interrupt. Once enabled, the interrupt handler may
|
|
||||||
/// be called "any time".
|
|
||||||
fn enable(&self);
|
|
||||||
|
|
||||||
/// Disable the interrupt.
|
/// Disable the interrupt.
|
||||||
fn disable(&self);
|
#[inline]
|
||||||
|
fn disable(self) {
|
||||||
|
NVIC::mask(self);
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if interrupt is being handled.
|
/// Check if interrupt is being handled.
|
||||||
|
#[inline]
|
||||||
#[cfg(not(armv6m))]
|
#[cfg(not(armv6m))]
|
||||||
fn is_active(&self) -> bool;
|
fn is_active(self) -> bool {
|
||||||
|
NVIC::is_active(self)
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if interrupt is enabled.
|
/// Check if interrupt is enabled.
|
||||||
fn is_enabled(&self) -> bool;
|
#[inline]
|
||||||
|
fn is_enabled(self) -> bool {
|
||||||
|
NVIC::is_enabled(self)
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if interrupt is pending.
|
/// Check if interrupt is pending.
|
||||||
fn is_pending(&self) -> bool;
|
#[inline]
|
||||||
|
fn is_pending(self) -> bool {
|
||||||
|
NVIC::is_pending(self)
|
||||||
|
}
|
||||||
|
|
||||||
/// Set interrupt pending.
|
/// Set interrupt pending.
|
||||||
fn pend(&self);
|
#[inline]
|
||||||
|
fn pend(self) {
|
||||||
|
NVIC::pend(self)
|
||||||
|
}
|
||||||
|
|
||||||
/// Unset interrupt pending.
|
/// Unset interrupt pending.
|
||||||
fn unpend(&self);
|
#[inline]
|
||||||
|
fn unpend(self) {
|
||||||
|
NVIC::unpend(self)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the priority of the interrupt.
|
/// Get the priority of the interrupt.
|
||||||
fn get_priority(&self) -> Priority;
|
#[inline]
|
||||||
|
fn get_priority(self) -> Priority {
|
||||||
|
Priority::from(NVIC::get_priority(self))
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the interrupt priority.
|
/// Set the interrupt priority.
|
||||||
fn set_priority(&self, prio: Priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Interrupt + ?Sized> InterruptExt for T {
|
|
||||||
fn set_handler(&self, func: unsafe fn(*mut ())) {
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
|
||||||
let handler = unsafe { self.__handler() };
|
|
||||||
handler.func.store(func as *mut (), Ordering::Relaxed);
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_handler(&self) {
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
|
||||||
let handler = unsafe { self.__handler() };
|
|
||||||
handler.func.store(ptr::null_mut(), Ordering::Relaxed);
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_handler_context(&self, ctx: *mut ()) {
|
|
||||||
let handler = unsafe { self.__handler() };
|
|
||||||
handler.ctx.store(ctx, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn enable(&self) {
|
fn set_priority(self, prio: Priority) {
|
||||||
compiler_fence(Ordering::SeqCst);
|
critical_section::with(|_| unsafe {
|
||||||
unsafe {
|
|
||||||
NVIC::unmask(NrWrap(self.number()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn disable(&self) {
|
|
||||||
NVIC::mask(NrWrap(self.number()));
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[cfg(not(armv6m))]
|
|
||||||
fn is_active(&self) -> bool {
|
|
||||||
NVIC::is_active(NrWrap(self.number()))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn is_enabled(&self) -> bool {
|
|
||||||
NVIC::is_enabled(NrWrap(self.number()))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn is_pending(&self) -> bool {
|
|
||||||
NVIC::is_pending(NrWrap(self.number()))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn pend(&self) {
|
|
||||||
NVIC::pend(NrWrap(self.number()))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn unpend(&self) {
|
|
||||||
NVIC::unpend(NrWrap(self.number()))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn get_priority(&self) -> Priority {
|
|
||||||
Priority::from(NVIC::get_priority(NrWrap(self.number())))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn set_priority(&self, prio: Priority) {
|
|
||||||
unsafe {
|
|
||||||
let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(());
|
let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(());
|
||||||
nvic.set_priority(NrWrap(self.number()), prio.into())
|
nvic.set_priority(self, prio.into())
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: InterruptNumber + Copy> InterruptExt for T {}
|
||||||
|
|
||||||
impl From<u8> for Priority {
|
impl From<u8> for Priority {
|
||||||
fn from(priority: u8) -> Self {
|
fn from(priority: u8) -> Self {
|
||||||
unsafe { mem::transmute(priority & PRIO_MASK) }
|
unsafe { mem::transmute(priority & PRIO_MASK) }
|
@ -11,3 +11,6 @@ mod peripheral;
|
|||||||
pub mod ratio;
|
pub mod ratio;
|
||||||
pub mod ring_buffer;
|
pub mod ring_buffer;
|
||||||
pub use peripheral::{Peripheral, PeripheralRef};
|
pub use peripheral::{Peripheral, PeripheralRef};
|
||||||
|
|
||||||
|
#[cfg(feature = "cortex-m")]
|
||||||
|
pub mod interrupt;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#[cfg(feature = "stm32wl")]
|
#[cfg(feature = "stm32wl")]
|
||||||
use embassy_stm32::interrupt;
|
use embassy_stm32::interrupt;
|
||||||
#[cfg(feature = "stm32wl")]
|
#[cfg(feature = "stm32wl")]
|
||||||
use embassy_stm32::interrupt::*;
|
use embassy_stm32::interrupt::InterruptExt;
|
||||||
#[cfg(feature = "stm32wl")]
|
#[cfg(feature = "stm32wl")]
|
||||||
use embassy_stm32::pac;
|
use embassy_stm32::pac;
|
||||||
#[cfg(feature = "stm32wl")]
|
#[cfg(feature = "stm32wl")]
|
||||||
@ -20,9 +20,9 @@ use lora_phy::mod_traits::InterfaceVariant;
|
|||||||
pub struct InterruptHandler {}
|
pub struct InterruptHandler {}
|
||||||
|
|
||||||
#[cfg(feature = "stm32wl")]
|
#[cfg(feature = "stm32wl")]
|
||||||
impl interrupt::Handler<interrupt::SUBGHZ_RADIO> for InterruptHandler {
|
impl interrupt::typelevel::Handler<interrupt::typelevel::SUBGHZ_RADIO> for InterruptHandler {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
unsafe { SUBGHZ_RADIO::steal() }.disable();
|
interrupt::SUBGHZ_RADIO.disable();
|
||||||
IRQ_SIGNAL.signal(());
|
IRQ_SIGNAL.signal(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -45,11 +45,11 @@ where
|
|||||||
{
|
{
|
||||||
/// Create an InterfaceVariant instance for an stm32wl/sx1262 combination
|
/// Create an InterfaceVariant instance for an stm32wl/sx1262 combination
|
||||||
pub fn new(
|
pub fn new(
|
||||||
_irq: impl interrupt::Binding<interrupt::SUBGHZ_RADIO, InterruptHandler>,
|
_irq: impl interrupt::typelevel::Binding<interrupt::typelevel::SUBGHZ_RADIO, InterruptHandler>,
|
||||||
rf_switch_rx: Option<CTRL>,
|
rf_switch_rx: Option<CTRL>,
|
||||||
rf_switch_tx: Option<CTRL>,
|
rf_switch_tx: Option<CTRL>,
|
||||||
) -> Result<Self, RadioError> {
|
) -> Result<Self, RadioError> {
|
||||||
unsafe { interrupt::SUBGHZ_RADIO::steal() }.disable();
|
interrupt::SUBGHZ_RADIO.disable();
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
board_type: BoardType::Stm32wlSx1262, // updated when associated with a specific LoRa board
|
board_type: BoardType::Stm32wlSx1262, // updated when associated with a specific LoRa board
|
||||||
rf_switch_rx,
|
rf_switch_rx,
|
||||||
@ -68,34 +68,28 @@ where
|
|||||||
}
|
}
|
||||||
async fn set_nss_low(&mut self) -> Result<(), RadioError> {
|
async fn set_nss_low(&mut self) -> Result<(), RadioError> {
|
||||||
let pwr = pac::PWR;
|
let pwr = pac::PWR;
|
||||||
unsafe {
|
|
||||||
pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::LOW));
|
pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::LOW));
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
async fn set_nss_high(&mut self) -> Result<(), RadioError> {
|
async fn set_nss_high(&mut self) -> Result<(), RadioError> {
|
||||||
let pwr = pac::PWR;
|
let pwr = pac::PWR;
|
||||||
unsafe {
|
|
||||||
pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::HIGH));
|
pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::HIGH));
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
async fn reset(&mut self, _delay: &mut impl DelayUs) -> Result<(), RadioError> {
|
async fn reset(&mut self, _delay: &mut impl DelayUs) -> Result<(), RadioError> {
|
||||||
let rcc = pac::RCC;
|
let rcc = pac::RCC;
|
||||||
unsafe {
|
|
||||||
rcc.csr().modify(|w| w.set_rfrst(true));
|
rcc.csr().modify(|w| w.set_rfrst(true));
|
||||||
rcc.csr().modify(|w| w.set_rfrst(false));
|
rcc.csr().modify(|w| w.set_rfrst(false));
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
async fn wait_on_busy(&mut self) -> Result<(), RadioError> {
|
async fn wait_on_busy(&mut self) -> Result<(), RadioError> {
|
||||||
let pwr = pac::PWR;
|
let pwr = pac::PWR;
|
||||||
while unsafe { pwr.sr2().read().rfbusys() == pac::pwr::vals::Rfbusys::BUSY } {}
|
while pwr.sr2().read().rfbusys() == pac::pwr::vals::Rfbusys::BUSY {}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn await_irq(&mut self) -> Result<(), RadioError> {
|
async fn await_irq(&mut self) -> Result<(), RadioError> {
|
||||||
unsafe { interrupt::SUBGHZ_RADIO::steal() }.enable();
|
unsafe { interrupt::SUBGHZ_RADIO.enable() };
|
||||||
IRQ_SIGNAL.wait().await;
|
IRQ_SIGNAL.wait().await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -156,27 +156,3 @@ pub fn main_wasm(args: TokenStream, item: TokenStream) -> TokenStream {
|
|||||||
let f = syn::parse_macro_input!(item as syn::ItemFn);
|
let f = syn::parse_macro_input!(item as syn::ItemFn);
|
||||||
main::run(args, f, main::wasm()).unwrap_or_else(|x| x).into()
|
main::run(args, f, main::wasm()).unwrap_or_else(|x| x).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
|
||||||
pub fn cortex_m_interrupt(args: TokenStream, item: TokenStream) -> TokenStream {
|
|
||||||
let args = syn::parse_macro_input!(args as syn::AttributeArgs);
|
|
||||||
let f = syn::parse_macro_input!(item as syn::ItemFn);
|
|
||||||
cortex_m_interrupt::run(args, f).unwrap_or_else(|x| x).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[proc_macro]
|
|
||||||
pub fn cortex_m_interrupt_declare(item: TokenStream) -> TokenStream {
|
|
||||||
let name = syn::parse_macro_input!(item as syn::Ident);
|
|
||||||
cortex_m_interrupt_declare::run(name).unwrap_or_else(|x| x).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # interrupt_take procedural macro
|
|
||||||
///
|
|
||||||
/// core::panic! is used as a default way to panic in this macro as there is no sensible way of enabling/disabling defmt for macro generation.
|
|
||||||
/// We are aware that this brings bloat in the form of core::fmt, but the bloat is already included with e.g. array indexing panics.
|
|
||||||
/// To get rid of this bloat, use the compiler flags `-Zbuild-std=core -Zbuild-std-features=panic_immediate_abort`.
|
|
||||||
#[proc_macro]
|
|
||||||
pub fn cortex_m_interrupt_take(item: TokenStream) -> TokenStream {
|
|
||||||
let name = syn::parse_macro_input!(item as syn::Ident);
|
|
||||||
cortex_m_interrupt_take::run(name).unwrap_or_else(|x| x).into()
|
|
||||||
}
|
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
use std::iter;
|
|
||||||
|
|
||||||
use darling::FromMeta;
|
|
||||||
use proc_macro2::TokenStream;
|
|
||||||
use quote::quote;
|
|
||||||
use syn::{ReturnType, Type, Visibility};
|
|
||||||
|
|
||||||
use crate::util::ctxt::Ctxt;
|
|
||||||
|
|
||||||
#[derive(Debug, FromMeta)]
|
|
||||||
struct Args {}
|
|
||||||
|
|
||||||
pub fn run(args: syn::AttributeArgs, mut f: syn::ItemFn) -> Result<TokenStream, TokenStream> {
|
|
||||||
let _args = Args::from_list(&args).map_err(|e| e.write_errors())?;
|
|
||||||
|
|
||||||
let ident = f.sig.ident.clone();
|
|
||||||
let ident_s = ident.to_string();
|
|
||||||
|
|
||||||
// XXX should we blacklist other attributes?
|
|
||||||
|
|
||||||
let valid_signature = f.sig.constness.is_none()
|
|
||||||
&& f.vis == Visibility::Inherited
|
|
||||||
&& f.sig.abi.is_none()
|
|
||||||
&& f.sig.inputs.is_empty()
|
|
||||||
&& f.sig.generics.params.is_empty()
|
|
||||||
&& f.sig.generics.where_clause.is_none()
|
|
||||||
&& f.sig.variadic.is_none()
|
|
||||||
&& match f.sig.output {
|
|
||||||
ReturnType::Default => true,
|
|
||||||
ReturnType::Type(_, ref ty) => match **ty {
|
|
||||||
Type::Tuple(ref tuple) => tuple.elems.is_empty(),
|
|
||||||
Type::Never(..) => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let ctxt = Ctxt::new();
|
|
||||||
|
|
||||||
if !valid_signature {
|
|
||||||
ctxt.error_spanned_by(
|
|
||||||
&f.sig,
|
|
||||||
"`#[interrupt]` handlers must have signature `[unsafe] fn() [-> !]`",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctxt.check()?;
|
|
||||||
|
|
||||||
f.block.stmts = iter::once(
|
|
||||||
syn::parse2(quote! {{
|
|
||||||
// Check that this interrupt actually exists
|
|
||||||
let __irq_exists_check: interrupt::#ident;
|
|
||||||
}})
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
.chain(f.block.stmts)
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let result = quote!(
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[export_name = #ident_s]
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
#f
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
use proc_macro2::TokenStream;
|
|
||||||
use quote::{format_ident, quote};
|
|
||||||
|
|
||||||
pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> {
|
|
||||||
let name = format_ident!("{}", name);
|
|
||||||
let name_interrupt = format_ident!("{}", name);
|
|
||||||
let name_handler = format!("__EMBASSY_{}_HANDLER", name);
|
|
||||||
|
|
||||||
let doc = format!("{} interrupt singleton.", name);
|
|
||||||
|
|
||||||
let result = quote! {
|
|
||||||
#[doc = #doc]
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
pub struct #name_interrupt(());
|
|
||||||
unsafe impl ::embassy_cortex_m::interrupt::Interrupt for #name_interrupt {
|
|
||||||
fn number(&self) -> u16 {
|
|
||||||
use cortex_m::interrupt::InterruptNumber;
|
|
||||||
let irq = InterruptEnum::#name;
|
|
||||||
irq.number() as u16
|
|
||||||
}
|
|
||||||
unsafe fn steal() -> Self {
|
|
||||||
Self(())
|
|
||||||
}
|
|
||||||
unsafe fn __handler(&self) -> &'static ::embassy_cortex_m::interrupt::DynHandler {
|
|
||||||
#[export_name = #name_handler]
|
|
||||||
static HANDLER: ::embassy_cortex_m::interrupt::DynHandler = ::embassy_cortex_m::interrupt::DynHandler::new();
|
|
||||||
&HANDLER
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
::embassy_hal_common::impl_peripheral!(#name_interrupt);
|
|
||||||
};
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
use proc_macro2::TokenStream;
|
|
||||||
use quote::{format_ident, quote};
|
|
||||||
|
|
||||||
pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> {
|
|
||||||
let name = format!("{}", name);
|
|
||||||
let name_interrupt = format_ident!("{}", name);
|
|
||||||
let name_handler = format!("__EMBASSY_{}_HANDLER", name);
|
|
||||||
|
|
||||||
#[cfg(feature = "rtos-trace-interrupt")]
|
|
||||||
let (isr_enter, isr_exit) = (
|
|
||||||
quote! {
|
|
||||||
::embassy_executor::rtos_trace_interrupt! {
|
|
||||||
::embassy_executor::_export::trace::isr_enter();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
quote! {
|
|
||||||
::embassy_executor::rtos_trace_interrupt! {
|
|
||||||
::embassy_executor::_export::trace::isr_exit();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
#[cfg(not(feature = "rtos-trace-interrupt"))]
|
|
||||||
let (isr_enter, isr_exit) = (quote! {}, quote! {});
|
|
||||||
|
|
||||||
let result = quote! {
|
|
||||||
{
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
#[export_name = #name]
|
|
||||||
pub unsafe extern "C" fn trampoline() {
|
|
||||||
extern "C" {
|
|
||||||
#[link_name = #name_handler]
|
|
||||||
static HANDLER: interrupt::DynHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
let func = HANDLER.func.load(interrupt::_export::atomic::Ordering::Relaxed);
|
|
||||||
let ctx = HANDLER.ctx.load(interrupt::_export::atomic::Ordering::Relaxed);
|
|
||||||
let func: fn(*mut ()) = ::core::mem::transmute(func);
|
|
||||||
#isr_enter
|
|
||||||
|
|
||||||
func(ctx);
|
|
||||||
#isr_exit
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static TAKEN: interrupt::_export::atomic::AtomicBool = interrupt::_export::atomic::AtomicBool::new(false);
|
|
||||||
|
|
||||||
if TAKEN.compare_exchange(false, true, interrupt::_export::atomic::Ordering::AcqRel, interrupt::_export::atomic::Ordering::Acquire).is_err() {
|
|
||||||
core::panic!("IRQ Already taken");
|
|
||||||
}
|
|
||||||
|
|
||||||
let irq: interrupt::#name_interrupt = unsafe { ::core::mem::transmute(()) };
|
|
||||||
irq
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
@ -1,5 +1,2 @@
|
|||||||
pub mod cortex_m_interrupt;
|
|
||||||
pub mod cortex_m_interrupt_declare;
|
|
||||||
pub mod cortex_m_interrupt_take;
|
|
||||||
pub mod main;
|
pub mod main;
|
||||||
pub mod task;
|
pub mod task;
|
||||||
|
@ -14,3 +14,8 @@ embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-
|
|||||||
embassy-time = { version = "0.1.0" }
|
embassy-time = { version = "0.1.0" }
|
||||||
embassy-futures = { version = "0.1.0" }
|
embassy-futures = { version = "0.1.0" }
|
||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
|
|
||||||
|
[package.metadata.embassy_docs]
|
||||||
|
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-w5500-v$VERSION/embassy-net-w5500/src/"
|
||||||
|
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-w5500/src/"
|
||||||
|
target = "thumbv7em-none-eabi"
|
@ -26,7 +26,8 @@ unstable-traits = []
|
|||||||
udp = ["smoltcp/socket-udp"]
|
udp = ["smoltcp/socket-udp"]
|
||||||
tcp = ["smoltcp/socket-tcp"]
|
tcp = ["smoltcp/socket-tcp"]
|
||||||
dns = ["smoltcp/socket-dns", "smoltcp/proto-dns"]
|
dns = ["smoltcp/socket-dns", "smoltcp/proto-dns"]
|
||||||
dhcpv4 = ["medium-ethernet", "smoltcp/socket-dhcpv4"]
|
dhcpv4 = ["proto-ipv4", "medium-ethernet", "smoltcp/socket-dhcpv4"]
|
||||||
|
proto-ipv4 = ["smoltcp/proto-ipv4"]
|
||||||
proto-ipv6 = ["smoltcp/proto-ipv6"]
|
proto-ipv6 = ["smoltcp/proto-ipv6"]
|
||||||
medium-ethernet = ["smoltcp/medium-ethernet"]
|
medium-ethernet = ["smoltcp/medium-ethernet"]
|
||||||
medium-ip = ["smoltcp/medium-ip"]
|
medium-ip = ["smoltcp/medium-ip"]
|
||||||
@ -38,7 +39,6 @@ defmt = { version = "0.3", optional = true }
|
|||||||
log = { version = "0.4.14", optional = true }
|
log = { version = "0.4.14", optional = true }
|
||||||
|
|
||||||
smoltcp = { version = "0.9.0", default-features = false, features = [
|
smoltcp = { version = "0.9.0", default-features = false, features = [
|
||||||
"proto-ipv4",
|
|
||||||
"socket",
|
"socket",
|
||||||
"async",
|
"async",
|
||||||
]}
|
]}
|
||||||
|
@ -59,7 +59,10 @@ where
|
|||||||
smolcaps.checksum.ipv4 = convert(caps.checksum.ipv4);
|
smolcaps.checksum.ipv4 = convert(caps.checksum.ipv4);
|
||||||
smolcaps.checksum.tcp = convert(caps.checksum.tcp);
|
smolcaps.checksum.tcp = convert(caps.checksum.tcp);
|
||||||
smolcaps.checksum.udp = convert(caps.checksum.udp);
|
smolcaps.checksum.udp = convert(caps.checksum.udp);
|
||||||
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
{
|
||||||
smolcaps.checksum.icmpv4 = convert(caps.checksum.icmpv4);
|
smolcaps.checksum.icmpv4 = convert(caps.checksum.icmpv4);
|
||||||
|
}
|
||||||
#[cfg(feature = "proto-ipv6")]
|
#[cfg(feature = "proto-ipv6")]
|
||||||
{
|
{
|
||||||
smolcaps.checksum.icmpv6 = convert(caps.checksum.icmpv6);
|
smolcaps.checksum.icmpv6 = convert(caps.checksum.icmpv6);
|
||||||
|
@ -88,6 +88,7 @@ where
|
|||||||
let addrs = self.query(host, qtype).await?;
|
let addrs = self.query(host, qtype).await?;
|
||||||
if let Some(first) = addrs.get(0) {
|
if let Some(first) = addrs.get(0) {
|
||||||
Ok(match first {
|
Ok(match first {
|
||||||
|
#[cfg(feature = "proto-ipv4")]
|
||||||
IpAddress::Ipv4(addr) => IpAddr::V4(addr.0.into()),
|
IpAddress::Ipv4(addr) => IpAddr::V4(addr.0.into()),
|
||||||
#[cfg(feature = "proto-ipv6")]
|
#[cfg(feature = "proto-ipv6")]
|
||||||
IpAddress::Ipv6(addr) => IpAddr::V6(addr.0.into()),
|
IpAddress::Ipv6(addr) => IpAddr::V6(addr.0.into()),
|
||||||
|
@ -34,7 +34,9 @@ use smoltcp::socket::dhcpv4::{self, RetryConfig};
|
|||||||
pub use smoltcp::wire::IpListenEndpoint;
|
pub use smoltcp::wire::IpListenEndpoint;
|
||||||
#[cfg(feature = "medium-ethernet")]
|
#[cfg(feature = "medium-ethernet")]
|
||||||
pub use smoltcp::wire::{EthernetAddress, HardwareAddress};
|
pub use smoltcp::wire::{EthernetAddress, HardwareAddress};
|
||||||
pub use smoltcp::wire::{IpAddress, IpCidr, Ipv4Address, Ipv4Cidr};
|
pub use smoltcp::wire::{IpAddress, IpCidr};
|
||||||
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
pub use smoltcp::wire::{Ipv4Address, Ipv4Cidr};
|
||||||
#[cfg(feature = "proto-ipv6")]
|
#[cfg(feature = "proto-ipv6")]
|
||||||
pub use smoltcp::wire::{Ipv6Address, Ipv6Cidr};
|
pub use smoltcp::wire::{Ipv6Address, Ipv6Cidr};
|
||||||
|
|
||||||
@ -67,8 +69,9 @@ impl<const SOCK: usize> StackResources<SOCK> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Static IP address configuration.
|
/// Static IP address configuration.
|
||||||
|
#[cfg(feature = "proto-ipv4")]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct StaticConfig {
|
pub struct StaticConfigV4 {
|
||||||
/// IP address and subnet mask.
|
/// IP address and subnet mask.
|
||||||
pub address: Ipv4Cidr,
|
pub address: Ipv4Cidr,
|
||||||
/// Default gateway.
|
/// Default gateway.
|
||||||
@ -77,6 +80,18 @@ pub struct StaticConfig {
|
|||||||
pub dns_servers: Vec<Ipv4Address, 3>,
|
pub dns_servers: Vec<Ipv4Address, 3>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Static IPv6 address configuration
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct StaticConfigV6 {
|
||||||
|
/// IP address and subnet mask.
|
||||||
|
pub address: Ipv6Cidr,
|
||||||
|
/// Default gateway.
|
||||||
|
pub gateway: Option<Ipv6Address>,
|
||||||
|
/// DNS servers.
|
||||||
|
pub dns_servers: Vec<Ipv6Address, 3>,
|
||||||
|
}
|
||||||
|
|
||||||
/// DHCP configuration.
|
/// DHCP configuration.
|
||||||
#[cfg(feature = "dhcpv4")]
|
#[cfg(feature = "dhcpv4")]
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
@ -112,12 +127,71 @@ impl Default for DhcpConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Network stack configuration.
|
/// Network stack configuration.
|
||||||
pub enum Config {
|
pub struct Config {
|
||||||
/// Use a static IP address configuration.
|
/// IPv4 configuration
|
||||||
Static(StaticConfig),
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
pub ipv4: ConfigV4,
|
||||||
|
/// IPv6 configuration
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
pub ipv6: ConfigV6,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
/// IPv4 configuration with static addressing.
|
||||||
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
pub fn ipv4_static(config: StaticConfigV4) -> Self {
|
||||||
|
Self {
|
||||||
|
ipv4: ConfigV4::Static(config),
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
ipv6: ConfigV6::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// IPv6 configuration with static addressing.
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
pub fn ipv6_static(config: StaticConfigV6) -> Self {
|
||||||
|
Self {
|
||||||
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
ipv4: ConfigV4::None,
|
||||||
|
ipv6: ConfigV6::Static(config),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// IPv6 configuration with dynamic addressing.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```rust
|
||||||
|
/// let _cfg = Config::dhcpv4(Default::default());
|
||||||
|
/// ```
|
||||||
|
#[cfg(feature = "dhcpv4")]
|
||||||
|
pub fn dhcpv4(config: DhcpConfig) -> Self {
|
||||||
|
Self {
|
||||||
|
ipv4: ConfigV4::Dhcp(config),
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
ipv6: ConfigV6::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Network stack IPv4 configuration.
|
||||||
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
pub enum ConfigV4 {
|
||||||
|
/// Use a static IPv4 address configuration.
|
||||||
|
Static(StaticConfigV4),
|
||||||
/// Use DHCP to obtain an IP address configuration.
|
/// Use DHCP to obtain an IP address configuration.
|
||||||
#[cfg(feature = "dhcpv4")]
|
#[cfg(feature = "dhcpv4")]
|
||||||
Dhcp(DhcpConfig),
|
Dhcp(DhcpConfig),
|
||||||
|
/// Do not configure IPv6.
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Network stack IPv6 configuration.
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
pub enum ConfigV6 {
|
||||||
|
/// Use a static IPv6 address configuration.
|
||||||
|
Static(StaticConfigV6),
|
||||||
|
/// Do not configure IPv6.
|
||||||
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A network stack.
|
/// A network stack.
|
||||||
@ -131,7 +205,10 @@ pub struct Stack<D: Driver> {
|
|||||||
struct Inner<D: Driver> {
|
struct Inner<D: Driver> {
|
||||||
device: D,
|
device: D,
|
||||||
link_up: bool,
|
link_up: bool,
|
||||||
config: Option<StaticConfig>,
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
static_v4: Option<StaticConfigV4>,
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
static_v6: Option<StaticConfigV6>,
|
||||||
#[cfg(feature = "dhcpv4")]
|
#[cfg(feature = "dhcpv4")]
|
||||||
dhcp_socket: Option<SocketHandle>,
|
dhcp_socket: Option<SocketHandle>,
|
||||||
#[cfg(feature = "dns")]
|
#[cfg(feature = "dns")]
|
||||||
@ -187,7 +264,10 @@ impl<D: Driver + 'static> Stack<D> {
|
|||||||
let mut inner = Inner {
|
let mut inner = Inner {
|
||||||
device,
|
device,
|
||||||
link_up: false,
|
link_up: false,
|
||||||
config: None,
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
static_v4: None,
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
static_v6: None,
|
||||||
#[cfg(feature = "dhcpv4")]
|
#[cfg(feature = "dhcpv4")]
|
||||||
dhcp_socket: None,
|
dhcp_socket: None,
|
||||||
#[cfg(feature = "dns")]
|
#[cfg(feature = "dns")]
|
||||||
@ -199,17 +279,26 @@ impl<D: Driver + 'static> Stack<D> {
|
|||||||
dns_waker: WakerRegistration::new(),
|
dns_waker: WakerRegistration::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
match config {
|
#[cfg(feature = "proto-ipv4")]
|
||||||
Config::Static(config) => {
|
match config.ipv4 {
|
||||||
inner.apply_config(&mut socket, config);
|
ConfigV4::Static(config) => {
|
||||||
|
inner.apply_config_v4(&mut socket, config);
|
||||||
}
|
}
|
||||||
#[cfg(feature = "dhcpv4")]
|
#[cfg(feature = "dhcpv4")]
|
||||||
Config::Dhcp(config) => {
|
ConfigV4::Dhcp(config) => {
|
||||||
let mut dhcp_socket = smoltcp::socket::dhcpv4::Socket::new();
|
let mut dhcp_socket = smoltcp::socket::dhcpv4::Socket::new();
|
||||||
inner.apply_dhcp_config(&mut dhcp_socket, config);
|
inner.apply_dhcp_config(&mut dhcp_socket, config);
|
||||||
let handle = socket.sockets.add(dhcp_socket);
|
let handle = socket.sockets.add(dhcp_socket);
|
||||||
inner.dhcp_socket = Some(handle);
|
inner.dhcp_socket = Some(handle);
|
||||||
}
|
}
|
||||||
|
ConfigV4::None => {}
|
||||||
|
}
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
match config.ipv6 {
|
||||||
|
ConfigV6::Static(config) => {
|
||||||
|
inner.apply_config_v6(&mut socket, config);
|
||||||
|
}
|
||||||
|
ConfigV6::None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
@ -239,12 +328,40 @@ impl<D: Driver + 'static> Stack<D> {
|
|||||||
/// Get whether the network stack has a valid IP configuration.
|
/// Get whether the network stack has a valid IP configuration.
|
||||||
/// This is true if the network stack has a static IP configuration or if DHCP has completed
|
/// This is true if the network stack has a static IP configuration or if DHCP has completed
|
||||||
pub fn is_config_up(&self) -> bool {
|
pub fn is_config_up(&self) -> bool {
|
||||||
self.with(|_s, i| i.config.is_some())
|
let v4_up;
|
||||||
|
let v6_up;
|
||||||
|
|
||||||
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
{
|
||||||
|
v4_up = self.config_v4().is_some();
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "proto-ipv4"))]
|
||||||
|
{
|
||||||
|
v4_up = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the current IP configuration.
|
#[cfg(feature = "proto-ipv6")]
|
||||||
pub fn config(&self) -> Option<StaticConfig> {
|
{
|
||||||
self.with(|_s, i| i.config.clone())
|
v6_up = self.config_v6().is_some();
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "proto-ipv6"))]
|
||||||
|
{
|
||||||
|
v6_up = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
v4_up || v6_up
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the current IPv4 configuration.
|
||||||
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
pub fn config_v4(&self) -> Option<StaticConfigV4> {
|
||||||
|
self.with(|_s, i| i.static_v4.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the current IPv6 configuration.
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
pub fn config_v6(&self) -> Option<StaticConfigV6> {
|
||||||
|
self.with(|_s, i| i.static_v6.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run the network stack.
|
/// Run the network stack.
|
||||||
@ -264,6 +381,7 @@ impl<D: Driver + 'static> Stack<D> {
|
|||||||
pub async fn dns_query(&self, name: &str, qtype: dns::DnsQueryType) -> Result<Vec<IpAddress, 1>, dns::Error> {
|
pub async fn dns_query(&self, name: &str, qtype: dns::DnsQueryType) -> Result<Vec<IpAddress, 1>, dns::Error> {
|
||||||
// For A and AAAA queries we try detect whether `name` is just an IP address
|
// For A and AAAA queries we try detect whether `name` is just an IP address
|
||||||
match qtype {
|
match qtype {
|
||||||
|
#[cfg(feature = "proto-ipv4")]
|
||||||
dns::DnsQueryType::A => {
|
dns::DnsQueryType::A => {
|
||||||
if let Ok(ip) = name.parse().map(IpAddress::Ipv4) {
|
if let Ok(ip) = name.parse().map(IpAddress::Ipv4) {
|
||||||
return Ok([ip].into_iter().collect());
|
return Ok([ip].into_iter().collect());
|
||||||
@ -374,7 +492,8 @@ impl SocketStack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<D: Driver + 'static> Inner<D> {
|
impl<D: Driver + 'static> Inner<D> {
|
||||||
fn apply_config(&mut self, s: &mut SocketStack, config: StaticConfig) {
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
fn apply_config_v4(&mut self, s: &mut SocketStack, config: StaticConfigV4) {
|
||||||
#[cfg(feature = "medium-ethernet")]
|
#[cfg(feature = "medium-ethernet")]
|
||||||
let medium = self.device.capabilities().medium;
|
let medium = self.device.capabilities().medium;
|
||||||
|
|
||||||
@ -403,14 +522,86 @@ impl<D: Driver + 'static> Inner<D> {
|
|||||||
debug!(" DNS server {}: {}", i, s);
|
debug!(" DNS server {}: {}", i, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.static_v4 = Some(config);
|
||||||
|
|
||||||
#[cfg(feature = "dns")]
|
#[cfg(feature = "dns")]
|
||||||
{
|
{
|
||||||
let socket = s.sockets.get_mut::<smoltcp::socket::dns::Socket>(self.dns_socket);
|
self.update_dns_servers(s)
|
||||||
let servers: Vec<IpAddress, 3> = config.dns_servers.iter().map(|c| IpAddress::Ipv4(*c)).collect();
|
}
|
||||||
socket.update_servers(&servers[..]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.config = Some(config)
|
/// Replaces the current IPv6 static configuration with a newly supplied config.
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
fn apply_config_v6(&mut self, s: &mut SocketStack, config: StaticConfigV6) {
|
||||||
|
#[cfg(feature = "medium-ethernet")]
|
||||||
|
let medium = self.device.capabilities().medium;
|
||||||
|
|
||||||
|
debug!("Acquired IPv6 configuration:");
|
||||||
|
|
||||||
|
debug!(" IP address: {}", config.address);
|
||||||
|
s.iface.update_ip_addrs(|addrs| {
|
||||||
|
if addrs.is_empty() {
|
||||||
|
addrs.push(IpCidr::Ipv6(config.address)).unwrap();
|
||||||
|
} else {
|
||||||
|
addrs[0] = IpCidr::Ipv6(config.address);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
#[cfg(feature = "medium-ethernet")]
|
||||||
|
if Medium::Ethernet == medium {
|
||||||
|
if let Some(gateway) = config.gateway {
|
||||||
|
debug!(" Default gateway: {}", gateway);
|
||||||
|
s.iface.routes_mut().add_default_ipv6_route(gateway).unwrap();
|
||||||
|
} else {
|
||||||
|
debug!(" Default gateway: None");
|
||||||
|
s.iface.routes_mut().remove_default_ipv6_route();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i, s) in config.dns_servers.iter().enumerate() {
|
||||||
|
debug!(" DNS server {}: {}", i, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.static_v6 = Some(config);
|
||||||
|
|
||||||
|
#[cfg(feature = "dns")]
|
||||||
|
{
|
||||||
|
self.update_dns_servers(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "dns")]
|
||||||
|
fn update_dns_servers(&mut self, s: &mut SocketStack) {
|
||||||
|
let socket = s.sockets.get_mut::<smoltcp::socket::dns::Socket>(self.dns_socket);
|
||||||
|
|
||||||
|
let servers_v4;
|
||||||
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
{
|
||||||
|
servers_v4 = self
|
||||||
|
.static_v4
|
||||||
|
.iter()
|
||||||
|
.flat_map(|cfg| cfg.dns_servers.iter().map(|c| IpAddress::Ipv4(*c)));
|
||||||
|
};
|
||||||
|
#[cfg(not(feature = "proto-ipv4"))]
|
||||||
|
{
|
||||||
|
servers_v4 = core::iter::empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
let servers_v6;
|
||||||
|
#[cfg(feature = "proto-ipv6")]
|
||||||
|
{
|
||||||
|
servers_v6 = self
|
||||||
|
.static_v6
|
||||||
|
.iter()
|
||||||
|
.flat_map(|cfg| cfg.dns_servers.iter().map(|c| IpAddress::Ipv6(*c)));
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "proto-ipv6"))]
|
||||||
|
{
|
||||||
|
servers_v6 = core::iter::empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prefer the v6 DNS servers over the v4 servers
|
||||||
|
let servers: Vec<IpAddress, 6> = servers_v6.chain(servers_v4).collect();
|
||||||
|
socket.update_servers(&servers[..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "dhcpv4")]
|
#[cfg(feature = "dhcpv4")]
|
||||||
@ -430,9 +621,15 @@ impl<D: Driver + 'static> Inner<D> {
|
|||||||
s.iface.update_ip_addrs(|ip_addrs| ip_addrs.clear());
|
s.iface.update_ip_addrs(|ip_addrs| ip_addrs.clear());
|
||||||
#[cfg(feature = "medium-ethernet")]
|
#[cfg(feature = "medium-ethernet")]
|
||||||
if medium == Medium::Ethernet {
|
if medium == Medium::Ethernet {
|
||||||
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
{
|
||||||
s.iface.routes_mut().remove_default_ipv4_route();
|
s.iface.routes_mut().remove_default_ipv4_route();
|
||||||
}
|
}
|
||||||
self.config = None
|
}
|
||||||
|
#[cfg(feature = "proto-ipv4")]
|
||||||
|
{
|
||||||
|
self.static_v4 = None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) {
|
fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) {
|
||||||
@ -470,12 +667,12 @@ impl<D: Driver + 'static> Inner<D> {
|
|||||||
None => {}
|
None => {}
|
||||||
Some(dhcpv4::Event::Deconfigured) => self.unapply_config(s),
|
Some(dhcpv4::Event::Deconfigured) => self.unapply_config(s),
|
||||||
Some(dhcpv4::Event::Configured(config)) => {
|
Some(dhcpv4::Event::Configured(config)) => {
|
||||||
let config = StaticConfig {
|
let config = StaticConfigV4 {
|
||||||
address: config.address,
|
address: config.address,
|
||||||
gateway: config.router,
|
gateway: config.router,
|
||||||
dns_servers: config.dns_servers,
|
dns_servers: config.dns_servers,
|
||||||
};
|
};
|
||||||
self.apply_config(s, config)
|
self.apply_config_v4(s, config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if old_link_up {
|
} else if old_link_up {
|
||||||
|
@ -278,10 +278,18 @@ impl<'a> TcpSocket<'a> {
|
|||||||
self.io.with(|s, _| s.may_send())
|
self.io.with(|s, _| s.may_send())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get whether the socket is ready to receive data, i.e. whether there is some pending data in the receive buffer.
|
/// return whether the recieve half of the full-duplex connection is open.
|
||||||
|
/// This function returns true if it’s possible to receive data from the remote endpoint.
|
||||||
|
/// It will return true while there is data in the receive buffer, and if there isn’t,
|
||||||
|
/// as long as the remote endpoint has not closed the connection.
|
||||||
pub fn may_recv(&self) -> bool {
|
pub fn may_recv(&self) -> bool {
|
||||||
self.io.with(|s, _| s.may_recv())
|
self.io.with(|s, _| s.may_recv())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get whether the socket is ready to receive data, i.e. whether there is some pending data in the receive buffer.
|
||||||
|
pub fn can_recv(&self) -> bool {
|
||||||
|
self.io.with(|s, _| s.can_recv())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Drop for TcpSocket<'a> {
|
impl<'a> Drop for TcpSocket<'a> {
|
||||||
@ -472,7 +480,10 @@ pub mod client {
|
|||||||
Self: 'a,
|
Self: 'a,
|
||||||
{
|
{
|
||||||
let addr: crate::IpAddress = match remote.ip() {
|
let addr: crate::IpAddress = match remote.ip() {
|
||||||
|
#[cfg(feature = "proto-ipv4")]
|
||||||
IpAddr::V4(addr) => crate::IpAddress::Ipv4(crate::Ipv4Address::from_bytes(&addr.octets())),
|
IpAddr::V4(addr) => crate::IpAddress::Ipv4(crate::Ipv4Address::from_bytes(&addr.octets())),
|
||||||
|
#[cfg(not(feature = "proto-ipv4"))]
|
||||||
|
IpAddr::V4(_) => panic!("ipv4 support not enabled"),
|
||||||
#[cfg(feature = "proto-ipv6")]
|
#[cfg(feature = "proto-ipv6")]
|
||||||
IpAddr::V6(addr) => crate::IpAddress::Ipv6(crate::Ipv6Address::from_bytes(&addr.octets())),
|
IpAddr::V6(addr) => crate::IpAddress::Ipv6(crate::Ipv6Address::from_bytes(&addr.octets())),
|
||||||
#[cfg(not(feature = "proto-ipv6"))]
|
#[cfg(not(feature = "proto-ipv6"))]
|
||||||
|
@ -16,7 +16,8 @@ flavors = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = [
|
default = ["rt"]
|
||||||
|
rt = [
|
||||||
"nrf52805-pac?/rt",
|
"nrf52805-pac?/rt",
|
||||||
"nrf52810-pac?/rt",
|
"nrf52810-pac?/rt",
|
||||||
"nrf52811-pac?/rt",
|
"nrf52811-pac?/rt",
|
||||||
@ -31,7 +32,7 @@ default = [
|
|||||||
|
|
||||||
time = ["dep:embassy-time"]
|
time = ["dep:embassy-time"]
|
||||||
|
|
||||||
defmt = ["dep:defmt", "embassy-executor/defmt", "embassy-sync/defmt", "embassy-usb-driver?/defmt", "embedded-io?/defmt", "embassy-embedded-hal/defmt"]
|
defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-usb-driver?/defmt", "embedded-io?/defmt", "embassy-embedded-hal/defmt"]
|
||||||
|
|
||||||
# Enable nightly-only features
|
# Enable nightly-only features
|
||||||
nightly = ["embedded-hal-1", "embedded-hal-async", "dep:embassy-usb-driver", "embedded-storage-async", "dep:embedded-io", "embassy-embedded-hal/nightly"]
|
nightly = ["embedded-hal-1", "embedded-hal-async", "dep:embassy-usb-driver", "embedded-storage-async", "dep:embedded-io", "embassy-embedded-hal/nightly"]
|
||||||
@ -90,11 +91,9 @@ _dppi = []
|
|||||||
_gpio-p1 = []
|
_gpio-p1 = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-executor = { version = "0.2.0", path = "../embassy-executor", optional = true }
|
|
||||||
embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true }
|
embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true }
|
||||||
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
|
||||||
embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-3"]}
|
embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common", features = ["cortex-m", "prio-bits-3"] }
|
||||||
embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
|
|
||||||
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||||
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true }
|
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true }
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@ use core::slice;
|
|||||||
use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering};
|
use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use embassy_cortex_m::interrupt::Interrupt;
|
|
||||||
use embassy_hal_common::atomic_ring_buffer::RingBuffer;
|
use embassy_hal_common::atomic_ring_buffer::RingBuffer;
|
||||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
@ -24,13 +23,13 @@ pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Pari
|
|||||||
|
|
||||||
use crate::gpio::sealed::Pin;
|
use crate::gpio::sealed::Pin;
|
||||||
use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
|
use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
|
||||||
use crate::interrupt::{self, InterruptExt};
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
use crate::ppi::{
|
use crate::ppi::{
|
||||||
self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task,
|
self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task,
|
||||||
};
|
};
|
||||||
use crate::timer::{Instance as TimerInstance, Timer};
|
use crate::timer::{Instance as TimerInstance, Timer};
|
||||||
use crate::uarte::{apply_workaround_for_enable_anomaly, Config, Instance as UarteInstance};
|
use crate::uarte::{apply_workaround_for_enable_anomaly, Config, Instance as UarteInstance};
|
||||||
use crate::{pac, Peripheral};
|
use crate::{interrupt, pac, Peripheral};
|
||||||
|
|
||||||
mod sealed {
|
mod sealed {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -77,7 +76,7 @@ pub struct InterruptHandler<U: UarteInstance> {
|
|||||||
_phantom: PhantomData<U>,
|
_phantom: PhantomData<U>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<U: UarteInstance> interrupt::Handler<U::Interrupt> for InterruptHandler<U> {
|
impl<U: UarteInstance> interrupt::typelevel::Handler<U::Interrupt> for InterruptHandler<U> {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
//trace!("irq: start");
|
//trace!("irq: start");
|
||||||
let r = U::regs();
|
let r = U::regs();
|
||||||
@ -202,7 +201,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
|||||||
ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd,
|
ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd,
|
||||||
ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd,
|
ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd,
|
||||||
ppi_group: impl Peripheral<P = impl Group> + 'd,
|
ppi_group: impl Peripheral<P = impl Group> + 'd,
|
||||||
_irq: impl interrupt::Binding<U::Interrupt, InterruptHandler<U>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<U::Interrupt, InterruptHandler<U>> + 'd,
|
||||||
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
@ -237,7 +236,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
|||||||
ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd,
|
ppi_ch1: impl Peripheral<P = impl ConfigurableChannel> + 'd,
|
||||||
ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd,
|
ppi_ch2: impl Peripheral<P = impl ConfigurableChannel> + 'd,
|
||||||
ppi_group: impl Peripheral<P = impl Group> + 'd,
|
ppi_group: impl Peripheral<P = impl Group> + 'd,
|
||||||
_irq: impl interrupt::Binding<U::Interrupt, InterruptHandler<U>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<U::Interrupt, InterruptHandler<U>> + 'd,
|
||||||
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
cts: impl Peripheral<P = impl GpioPin> + 'd,
|
cts: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
@ -362,8 +361,8 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
|||||||
ppi_ch2.disable();
|
ppi_ch2.disable();
|
||||||
ppi_group.add_channel(&ppi_ch2);
|
ppi_group.add_channel(&ppi_ch2);
|
||||||
|
|
||||||
unsafe { U::Interrupt::steal() }.pend();
|
U::Interrupt::pend();
|
||||||
unsafe { U::Interrupt::steal() }.enable();
|
unsafe { U::Interrupt::enable() };
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
_peri: peri,
|
_peri: peri,
|
||||||
@ -375,7 +374,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn pend_irq() {
|
fn pend_irq() {
|
||||||
unsafe { <U::Interrupt as Interrupt>::steal() }.pend()
|
U::Interrupt::pend()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adjust the baud rate to the provided value.
|
/// Adjust the baud rate to the provided value.
|
||||||
|
@ -208,33 +208,29 @@ impl_ppi_channel!(PPI_CH31, 31 => static);
|
|||||||
impl_saadc_input!(P0_04, ANALOG_INPUT2);
|
impl_saadc_input!(P0_04, ANALOG_INPUT2);
|
||||||
impl_saadc_input!(P0_05, ANALOG_INPUT3);
|
impl_saadc_input!(P0_05, ANALOG_INPUT3);
|
||||||
|
|
||||||
pub mod irqs {
|
embassy_hal_common::interrupt_mod!(
|
||||||
use embassy_cortex_m::interrupt::_export::declare;
|
POWER_CLOCK,
|
||||||
|
RADIO,
|
||||||
use crate::pac::Interrupt as InterruptEnum;
|
UARTE0_UART0,
|
||||||
|
TWIM0_TWIS0_TWI0,
|
||||||
declare!(POWER_CLOCK);
|
SPIM0_SPIS0_SPI0,
|
||||||
declare!(RADIO);
|
GPIOTE,
|
||||||
declare!(UARTE0_UART0);
|
SAADC,
|
||||||
declare!(TWIM0_TWIS0_TWI0);
|
TIMER0,
|
||||||
declare!(SPIM0_SPIS0_SPI0);
|
TIMER1,
|
||||||
declare!(GPIOTE);
|
TIMER2,
|
||||||
declare!(SAADC);
|
RTC0,
|
||||||
declare!(TIMER0);
|
TEMP,
|
||||||
declare!(TIMER1);
|
RNG,
|
||||||
declare!(TIMER2);
|
ECB,
|
||||||
declare!(RTC0);
|
CCM_AAR,
|
||||||
declare!(TEMP);
|
WDT,
|
||||||
declare!(RNG);
|
RTC1,
|
||||||
declare!(ECB);
|
QDEC,
|
||||||
declare!(CCM_AAR);
|
SWI0_EGU0,
|
||||||
declare!(WDT);
|
SWI1_EGU1,
|
||||||
declare!(RTC1);
|
SWI2,
|
||||||
declare!(QDEC);
|
SWI3,
|
||||||
declare!(SWI0_EGU0);
|
SWI4,
|
||||||
declare!(SWI1_EGU1);
|
SWI5,
|
||||||
declare!(SWI2);
|
);
|
||||||
declare!(SWI3);
|
|
||||||
declare!(SWI4);
|
|
||||||
declare!(SWI5);
|
|
||||||
}
|
|
||||||
|
@ -234,36 +234,32 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5);
|
|||||||
impl_saadc_input!(P0_30, ANALOG_INPUT6);
|
impl_saadc_input!(P0_30, ANALOG_INPUT6);
|
||||||
impl_saadc_input!(P0_31, ANALOG_INPUT7);
|
impl_saadc_input!(P0_31, ANALOG_INPUT7);
|
||||||
|
|
||||||
pub mod irqs {
|
embassy_hal_common::interrupt_mod!(
|
||||||
use embassy_cortex_m::interrupt::_export::declare;
|
POWER_CLOCK,
|
||||||
|
RADIO,
|
||||||
use crate::pac::Interrupt as InterruptEnum;
|
UARTE0_UART0,
|
||||||
|
TWIM0_TWIS0_TWI0,
|
||||||
declare!(POWER_CLOCK);
|
SPIM0_SPIS0_SPI0,
|
||||||
declare!(RADIO);
|
GPIOTE,
|
||||||
declare!(UARTE0_UART0);
|
SAADC,
|
||||||
declare!(TWIM0_TWIS0_TWI0);
|
TIMER0,
|
||||||
declare!(SPIM0_SPIS0_SPI0);
|
TIMER1,
|
||||||
declare!(GPIOTE);
|
TIMER2,
|
||||||
declare!(SAADC);
|
RTC0,
|
||||||
declare!(TIMER0);
|
TEMP,
|
||||||
declare!(TIMER1);
|
RNG,
|
||||||
declare!(TIMER2);
|
ECB,
|
||||||
declare!(RTC0);
|
CCM_AAR,
|
||||||
declare!(TEMP);
|
WDT,
|
||||||
declare!(RNG);
|
RTC1,
|
||||||
declare!(ECB);
|
QDEC,
|
||||||
declare!(CCM_AAR);
|
COMP,
|
||||||
declare!(WDT);
|
SWI0_EGU0,
|
||||||
declare!(RTC1);
|
SWI1_EGU1,
|
||||||
declare!(QDEC);
|
SWI2,
|
||||||
declare!(COMP);
|
SWI3,
|
||||||
declare!(SWI0_EGU0);
|
SWI4,
|
||||||
declare!(SWI1_EGU1);
|
SWI5,
|
||||||
declare!(SWI2);
|
PWM0,
|
||||||
declare!(SWI3);
|
PDM,
|
||||||
declare!(SWI4);
|
);
|
||||||
declare!(SWI5);
|
|
||||||
declare!(PWM0);
|
|
||||||
declare!(PDM);
|
|
||||||
}
|
|
||||||
|
@ -236,36 +236,32 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5);
|
|||||||
impl_saadc_input!(P0_30, ANALOG_INPUT6);
|
impl_saadc_input!(P0_30, ANALOG_INPUT6);
|
||||||
impl_saadc_input!(P0_31, ANALOG_INPUT7);
|
impl_saadc_input!(P0_31, ANALOG_INPUT7);
|
||||||
|
|
||||||
pub mod irqs {
|
embassy_hal_common::interrupt_mod!(
|
||||||
use embassy_cortex_m::interrupt::_export::declare;
|
POWER_CLOCK,
|
||||||
|
RADIO,
|
||||||
use crate::pac::Interrupt as InterruptEnum;
|
UARTE0_UART0,
|
||||||
|
TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0,
|
||||||
declare!(POWER_CLOCK);
|
SPIM1_SPIS1_SPI1,
|
||||||
declare!(RADIO);
|
GPIOTE,
|
||||||
declare!(UARTE0_UART0);
|
SAADC,
|
||||||
declare!(TWIM0_TWIS0_TWI0_SPIM0_SPIS0_SPI0);
|
TIMER0,
|
||||||
declare!(SPIM1_SPIS1_SPI1);
|
TIMER1,
|
||||||
declare!(GPIOTE);
|
TIMER2,
|
||||||
declare!(SAADC);
|
RTC0,
|
||||||
declare!(TIMER0);
|
TEMP,
|
||||||
declare!(TIMER1);
|
RNG,
|
||||||
declare!(TIMER2);
|
ECB,
|
||||||
declare!(RTC0);
|
CCM_AAR,
|
||||||
declare!(TEMP);
|
WDT,
|
||||||
declare!(RNG);
|
RTC1,
|
||||||
declare!(ECB);
|
QDEC,
|
||||||
declare!(CCM_AAR);
|
COMP,
|
||||||
declare!(WDT);
|
SWI0_EGU0,
|
||||||
declare!(RTC1);
|
SWI1_EGU1,
|
||||||
declare!(QDEC);
|
SWI2,
|
||||||
declare!(COMP);
|
SWI3,
|
||||||
declare!(SWI0_EGU0);
|
SWI4,
|
||||||
declare!(SWI1_EGU1);
|
SWI5,
|
||||||
declare!(SWI2);
|
PWM0,
|
||||||
declare!(SWI3);
|
PDM,
|
||||||
declare!(SWI4);
|
);
|
||||||
declare!(SWI5);
|
|
||||||
declare!(PWM0);
|
|
||||||
declare!(PDM);
|
|
||||||
}
|
|
||||||
|
@ -224,35 +224,31 @@ impl_ppi_channel!(PPI_CH29, 29 => static);
|
|||||||
impl_ppi_channel!(PPI_CH30, 30 => static);
|
impl_ppi_channel!(PPI_CH30, 30 => static);
|
||||||
impl_ppi_channel!(PPI_CH31, 31 => static);
|
impl_ppi_channel!(PPI_CH31, 31 => static);
|
||||||
|
|
||||||
pub mod irqs {
|
embassy_hal_common::interrupt_mod!(
|
||||||
use embassy_cortex_m::interrupt::_export::declare;
|
POWER_CLOCK,
|
||||||
|
RADIO,
|
||||||
use crate::pac::Interrupt as InterruptEnum;
|
UARTE0_UART0,
|
||||||
|
SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0,
|
||||||
declare!(POWER_CLOCK);
|
SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1,
|
||||||
declare!(RADIO);
|
GPIOTE,
|
||||||
declare!(UARTE0_UART0);
|
TIMER0,
|
||||||
declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
|
TIMER1,
|
||||||
declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
|
TIMER2,
|
||||||
declare!(GPIOTE);
|
RTC0,
|
||||||
declare!(TIMER0);
|
TEMP,
|
||||||
declare!(TIMER1);
|
RNG,
|
||||||
declare!(TIMER2);
|
ECB,
|
||||||
declare!(RTC0);
|
CCM_AAR,
|
||||||
declare!(TEMP);
|
WDT,
|
||||||
declare!(RNG);
|
RTC1,
|
||||||
declare!(ECB);
|
QDEC,
|
||||||
declare!(CCM_AAR);
|
COMP,
|
||||||
declare!(WDT);
|
SWI0_EGU0,
|
||||||
declare!(RTC1);
|
SWI1_EGU1,
|
||||||
declare!(QDEC);
|
SWI2_EGU2,
|
||||||
declare!(COMP);
|
SWI3_EGU3,
|
||||||
declare!(SWI0_EGU0);
|
SWI4_EGU4,
|
||||||
declare!(SWI1_EGU1);
|
SWI5_EGU5,
|
||||||
declare!(SWI2_EGU2);
|
TIMER3,
|
||||||
declare!(SWI3_EGU3);
|
USBD,
|
||||||
declare!(SWI4_EGU4);
|
);
|
||||||
declare!(SWI5_EGU5);
|
|
||||||
declare!(TIMER3);
|
|
||||||
declare!(USBD);
|
|
||||||
}
|
|
||||||
|
@ -263,46 +263,42 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7);
|
|||||||
|
|
||||||
impl_i2s!(I2S, I2S, I2S);
|
impl_i2s!(I2S, I2S, I2S);
|
||||||
|
|
||||||
pub mod irqs {
|
embassy_hal_common::interrupt_mod!(
|
||||||
use embassy_cortex_m::interrupt::_export::declare;
|
POWER_CLOCK,
|
||||||
|
RADIO,
|
||||||
use crate::pac::Interrupt as InterruptEnum;
|
UARTE0_UART0,
|
||||||
|
SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0,
|
||||||
declare!(POWER_CLOCK);
|
SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1,
|
||||||
declare!(RADIO);
|
NFCT,
|
||||||
declare!(UARTE0_UART0);
|
GPIOTE,
|
||||||
declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
|
SAADC,
|
||||||
declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
|
TIMER0,
|
||||||
declare!(NFCT);
|
TIMER1,
|
||||||
declare!(GPIOTE);
|
TIMER2,
|
||||||
declare!(SAADC);
|
RTC0,
|
||||||
declare!(TIMER0);
|
TEMP,
|
||||||
declare!(TIMER1);
|
RNG,
|
||||||
declare!(TIMER2);
|
ECB,
|
||||||
declare!(RTC0);
|
CCM_AAR,
|
||||||
declare!(TEMP);
|
WDT,
|
||||||
declare!(RNG);
|
RTC1,
|
||||||
declare!(ECB);
|
QDEC,
|
||||||
declare!(CCM_AAR);
|
COMP_LPCOMP,
|
||||||
declare!(WDT);
|
SWI0_EGU0,
|
||||||
declare!(RTC1);
|
SWI1_EGU1,
|
||||||
declare!(QDEC);
|
SWI2_EGU2,
|
||||||
declare!(COMP_LPCOMP);
|
SWI3_EGU3,
|
||||||
declare!(SWI0_EGU0);
|
SWI4_EGU4,
|
||||||
declare!(SWI1_EGU1);
|
SWI5_EGU5,
|
||||||
declare!(SWI2_EGU2);
|
TIMER3,
|
||||||
declare!(SWI3_EGU3);
|
TIMER4,
|
||||||
declare!(SWI4_EGU4);
|
PWM0,
|
||||||
declare!(SWI5_EGU5);
|
PDM,
|
||||||
declare!(TIMER3);
|
MWU,
|
||||||
declare!(TIMER4);
|
PWM1,
|
||||||
declare!(PWM0);
|
PWM2,
|
||||||
declare!(PDM);
|
SPIM2_SPIS2_SPI2,
|
||||||
declare!(MWU);
|
RTC2,
|
||||||
declare!(PWM1);
|
FPU,
|
||||||
declare!(PWM2);
|
I2S,
|
||||||
declare!(SPIM2_SPIS2_SPI2);
|
);
|
||||||
declare!(RTC2);
|
|
||||||
declare!(FPU);
|
|
||||||
declare!(I2S);
|
|
||||||
}
|
|
||||||
|
@ -306,50 +306,46 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7);
|
|||||||
|
|
||||||
impl_i2s!(I2S, I2S, I2S);
|
impl_i2s!(I2S, I2S, I2S);
|
||||||
|
|
||||||
pub mod irqs {
|
embassy_hal_common::interrupt_mod!(
|
||||||
use embassy_cortex_m::interrupt::_export::declare;
|
POWER_CLOCK,
|
||||||
|
RADIO,
|
||||||
use crate::pac::Interrupt as InterruptEnum;
|
UARTE0_UART0,
|
||||||
|
SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0,
|
||||||
declare!(POWER_CLOCK);
|
SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1,
|
||||||
declare!(RADIO);
|
NFCT,
|
||||||
declare!(UARTE0_UART0);
|
GPIOTE,
|
||||||
declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
|
SAADC,
|
||||||
declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
|
TIMER0,
|
||||||
declare!(NFCT);
|
TIMER1,
|
||||||
declare!(GPIOTE);
|
TIMER2,
|
||||||
declare!(SAADC);
|
RTC0,
|
||||||
declare!(TIMER0);
|
TEMP,
|
||||||
declare!(TIMER1);
|
RNG,
|
||||||
declare!(TIMER2);
|
ECB,
|
||||||
declare!(RTC0);
|
CCM_AAR,
|
||||||
declare!(TEMP);
|
WDT,
|
||||||
declare!(RNG);
|
RTC1,
|
||||||
declare!(ECB);
|
QDEC,
|
||||||
declare!(CCM_AAR);
|
COMP_LPCOMP,
|
||||||
declare!(WDT);
|
SWI0_EGU0,
|
||||||
declare!(RTC1);
|
SWI1_EGU1,
|
||||||
declare!(QDEC);
|
SWI2_EGU2,
|
||||||
declare!(COMP_LPCOMP);
|
SWI3_EGU3,
|
||||||
declare!(SWI0_EGU0);
|
SWI4_EGU4,
|
||||||
declare!(SWI1_EGU1);
|
SWI5_EGU5,
|
||||||
declare!(SWI2_EGU2);
|
TIMER3,
|
||||||
declare!(SWI3_EGU3);
|
TIMER4,
|
||||||
declare!(SWI4_EGU4);
|
PWM0,
|
||||||
declare!(SWI5_EGU5);
|
PDM,
|
||||||
declare!(TIMER3);
|
MWU,
|
||||||
declare!(TIMER4);
|
PWM1,
|
||||||
declare!(PWM0);
|
PWM2,
|
||||||
declare!(PDM);
|
SPIM2_SPIS2_SPI2,
|
||||||
declare!(MWU);
|
RTC2,
|
||||||
declare!(PWM1);
|
FPU,
|
||||||
declare!(PWM2);
|
USBD,
|
||||||
declare!(SPIM2_SPIS2_SPI2);
|
UARTE1,
|
||||||
declare!(RTC2);
|
PWM3,
|
||||||
declare!(FPU);
|
SPIM3,
|
||||||
declare!(USBD);
|
I2S,
|
||||||
declare!(UARTE1);
|
);
|
||||||
declare!(PWM3);
|
|
||||||
declare!(SPIM3);
|
|
||||||
declare!(I2S);
|
|
||||||
}
|
|
||||||
|
@ -311,52 +311,48 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7);
|
|||||||
|
|
||||||
impl_i2s!(I2S, I2S, I2S);
|
impl_i2s!(I2S, I2S, I2S);
|
||||||
|
|
||||||
pub mod irqs {
|
embassy_hal_common::interrupt_mod!(
|
||||||
use embassy_cortex_m::interrupt::_export::declare;
|
POWER_CLOCK,
|
||||||
|
RADIO,
|
||||||
use crate::pac::Interrupt as InterruptEnum;
|
UARTE0_UART0,
|
||||||
|
SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0,
|
||||||
declare!(POWER_CLOCK);
|
SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1,
|
||||||
declare!(RADIO);
|
NFCT,
|
||||||
declare!(UARTE0_UART0);
|
GPIOTE,
|
||||||
declare!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
|
SAADC,
|
||||||
declare!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
|
TIMER0,
|
||||||
declare!(NFCT);
|
TIMER1,
|
||||||
declare!(GPIOTE);
|
TIMER2,
|
||||||
declare!(SAADC);
|
RTC0,
|
||||||
declare!(TIMER0);
|
TEMP,
|
||||||
declare!(TIMER1);
|
RNG,
|
||||||
declare!(TIMER2);
|
ECB,
|
||||||
declare!(RTC0);
|
CCM_AAR,
|
||||||
declare!(TEMP);
|
WDT,
|
||||||
declare!(RNG);
|
RTC1,
|
||||||
declare!(ECB);
|
QDEC,
|
||||||
declare!(CCM_AAR);
|
COMP_LPCOMP,
|
||||||
declare!(WDT);
|
SWI0_EGU0,
|
||||||
declare!(RTC1);
|
SWI1_EGU1,
|
||||||
declare!(QDEC);
|
SWI2_EGU2,
|
||||||
declare!(COMP_LPCOMP);
|
SWI3_EGU3,
|
||||||
declare!(SWI0_EGU0);
|
SWI4_EGU4,
|
||||||
declare!(SWI1_EGU1);
|
SWI5_EGU5,
|
||||||
declare!(SWI2_EGU2);
|
TIMER3,
|
||||||
declare!(SWI3_EGU3);
|
TIMER4,
|
||||||
declare!(SWI4_EGU4);
|
PWM0,
|
||||||
declare!(SWI5_EGU5);
|
PDM,
|
||||||
declare!(TIMER3);
|
MWU,
|
||||||
declare!(TIMER4);
|
PWM1,
|
||||||
declare!(PWM0);
|
PWM2,
|
||||||
declare!(PDM);
|
SPIM2_SPIS2_SPI2,
|
||||||
declare!(MWU);
|
RTC2,
|
||||||
declare!(PWM1);
|
FPU,
|
||||||
declare!(PWM2);
|
USBD,
|
||||||
declare!(SPIM2_SPIS2_SPI2);
|
UARTE1,
|
||||||
declare!(RTC2);
|
QSPI,
|
||||||
declare!(FPU);
|
CRYPTOCELL,
|
||||||
declare!(USBD);
|
PWM3,
|
||||||
declare!(UARTE1);
|
SPIM3,
|
||||||
declare!(QSPI);
|
I2S,
|
||||||
declare!(CRYPTOCELL);
|
);
|
||||||
declare!(PWM3);
|
|
||||||
declare!(SPIM3);
|
|
||||||
declare!(I2S);
|
|
||||||
}
|
|
||||||
|
@ -5,6 +5,8 @@ pub mod pac {
|
|||||||
// The nRF5340 has a secure and non-secure (NS) mode.
|
// The nRF5340 has a secure and non-secure (NS) mode.
|
||||||
// To avoid cfg spam, we remove _ns or _s suffixes here.
|
// To avoid cfg spam, we remove _ns or _s suffixes here.
|
||||||
|
|
||||||
|
pub use nrf5340_app_pac::NVIC_PRIO_BITS;
|
||||||
|
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use nrf5340_app_pac::{
|
pub use nrf5340_app_pac::{
|
||||||
interrupt,
|
interrupt,
|
||||||
@ -504,50 +506,46 @@ impl_saadc_input!(P0_18, ANALOG_INPUT5);
|
|||||||
impl_saadc_input!(P0_19, ANALOG_INPUT6);
|
impl_saadc_input!(P0_19, ANALOG_INPUT6);
|
||||||
impl_saadc_input!(P0_20, ANALOG_INPUT7);
|
impl_saadc_input!(P0_20, ANALOG_INPUT7);
|
||||||
|
|
||||||
pub mod irqs {
|
embassy_hal_common::interrupt_mod!(
|
||||||
use embassy_cortex_m::interrupt::_export::declare;
|
FPU,
|
||||||
|
CACHE,
|
||||||
use crate::pac::Interrupt as InterruptEnum;
|
SPU,
|
||||||
|
CLOCK_POWER,
|
||||||
declare!(FPU);
|
SERIAL0,
|
||||||
declare!(CACHE);
|
SERIAL1,
|
||||||
declare!(SPU);
|
SPIM4,
|
||||||
declare!(CLOCK_POWER);
|
SERIAL2,
|
||||||
declare!(SERIAL0);
|
SERIAL3,
|
||||||
declare!(SERIAL1);
|
GPIOTE0,
|
||||||
declare!(SPIM4);
|
SAADC,
|
||||||
declare!(SERIAL2);
|
TIMER0,
|
||||||
declare!(SERIAL3);
|
TIMER1,
|
||||||
declare!(GPIOTE0);
|
TIMER2,
|
||||||
declare!(SAADC);
|
RTC0,
|
||||||
declare!(TIMER0);
|
RTC1,
|
||||||
declare!(TIMER1);
|
WDT0,
|
||||||
declare!(TIMER2);
|
WDT1,
|
||||||
declare!(RTC0);
|
COMP_LPCOMP,
|
||||||
declare!(RTC1);
|
EGU0,
|
||||||
declare!(WDT0);
|
EGU1,
|
||||||
declare!(WDT1);
|
EGU2,
|
||||||
declare!(COMP_LPCOMP);
|
EGU3,
|
||||||
declare!(EGU0);
|
EGU4,
|
||||||
declare!(EGU1);
|
EGU5,
|
||||||
declare!(EGU2);
|
PWM0,
|
||||||
declare!(EGU3);
|
PWM1,
|
||||||
declare!(EGU4);
|
PWM2,
|
||||||
declare!(EGU5);
|
PWM3,
|
||||||
declare!(PWM0);
|
PDM0,
|
||||||
declare!(PWM1);
|
I2S0,
|
||||||
declare!(PWM2);
|
IPC,
|
||||||
declare!(PWM3);
|
QSPI,
|
||||||
declare!(PDM0);
|
NFCT,
|
||||||
declare!(I2S0);
|
GPIOTE1,
|
||||||
declare!(IPC);
|
QDEC0,
|
||||||
declare!(QSPI);
|
QDEC1,
|
||||||
declare!(NFCT);
|
USBD,
|
||||||
declare!(GPIOTE1);
|
USBREGULATOR,
|
||||||
declare!(QDEC0);
|
KMU,
|
||||||
declare!(QDEC1);
|
CRYPTOCELL,
|
||||||
declare!(USBD);
|
);
|
||||||
declare!(USBREGULATOR);
|
|
||||||
declare!(KMU);
|
|
||||||
declare!(CRYPTOCELL);
|
|
||||||
}
|
|
||||||
|
@ -5,6 +5,8 @@ pub mod pac {
|
|||||||
// The nRF5340 has a secure and non-secure (NS) mode.
|
// The nRF5340 has a secure and non-secure (NS) mode.
|
||||||
// To avoid cfg spam, we remove _ns or _s suffixes here.
|
// To avoid cfg spam, we remove _ns or _s suffixes here.
|
||||||
|
|
||||||
|
pub use nrf5340_net_pac::NVIC_PRIO_BITS;
|
||||||
|
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use nrf5340_net_pac::{
|
pub use nrf5340_net_pac::{
|
||||||
interrupt,
|
interrupt,
|
||||||
@ -340,29 +342,25 @@ impl_ppi_channel!(PPI_CH29, 29 => configurable);
|
|||||||
impl_ppi_channel!(PPI_CH30, 30 => configurable);
|
impl_ppi_channel!(PPI_CH30, 30 => configurable);
|
||||||
impl_ppi_channel!(PPI_CH31, 31 => configurable);
|
impl_ppi_channel!(PPI_CH31, 31 => configurable);
|
||||||
|
|
||||||
pub mod irqs {
|
embassy_hal_common::interrupt_mod!(
|
||||||
use embassy_cortex_m::interrupt::_export::declare;
|
CLOCK_POWER,
|
||||||
|
RADIO,
|
||||||
use crate::pac::Interrupt as InterruptEnum;
|
RNG,
|
||||||
|
GPIOTE,
|
||||||
declare!(CLOCK_POWER);
|
WDT,
|
||||||
declare!(RADIO);
|
TIMER0,
|
||||||
declare!(RNG);
|
ECB,
|
||||||
declare!(GPIOTE);
|
AAR_CCM,
|
||||||
declare!(WDT);
|
TEMP,
|
||||||
declare!(TIMER0);
|
RTC0,
|
||||||
declare!(ECB);
|
IPC,
|
||||||
declare!(AAR_CCM);
|
SERIAL0,
|
||||||
declare!(TEMP);
|
EGU0,
|
||||||
declare!(RTC0);
|
RTC1,
|
||||||
declare!(IPC);
|
TIMER1,
|
||||||
declare!(SERIAL0);
|
TIMER2,
|
||||||
declare!(EGU0);
|
SWI0,
|
||||||
declare!(RTC1);
|
SWI1,
|
||||||
declare!(TIMER1);
|
SWI2,
|
||||||
declare!(TIMER2);
|
SWI3,
|
||||||
declare!(SWI0);
|
);
|
||||||
declare!(SWI1);
|
|
||||||
declare!(SWI2);
|
|
||||||
declare!(SWI3);
|
|
||||||
}
|
|
||||||
|
@ -5,6 +5,8 @@ pub mod pac {
|
|||||||
// The nRF9160 has a secure and non-secure (NS) mode.
|
// The nRF9160 has a secure and non-secure (NS) mode.
|
||||||
// To avoid cfg spam, we remove _ns or _s suffixes here.
|
// To avoid cfg spam, we remove _ns or _s suffixes here.
|
||||||
|
|
||||||
|
pub use nrf9160_pac::NVIC_PRIO_BITS;
|
||||||
|
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use nrf9160_pac::{
|
pub use nrf9160_pac::{
|
||||||
interrupt,
|
interrupt,
|
||||||
@ -366,40 +368,36 @@ impl_saadc_input!(P0_18, ANALOG_INPUT5);
|
|||||||
impl_saadc_input!(P0_19, ANALOG_INPUT6);
|
impl_saadc_input!(P0_19, ANALOG_INPUT6);
|
||||||
impl_saadc_input!(P0_20, ANALOG_INPUT7);
|
impl_saadc_input!(P0_20, ANALOG_INPUT7);
|
||||||
|
|
||||||
pub mod irqs {
|
embassy_hal_common::interrupt_mod!(
|
||||||
use embassy_cortex_m::interrupt::_export::declare;
|
SPU,
|
||||||
|
CLOCK_POWER,
|
||||||
use crate::pac::Interrupt as InterruptEnum;
|
UARTE0_SPIM0_SPIS0_TWIM0_TWIS0,
|
||||||
|
UARTE1_SPIM1_SPIS1_TWIM1_TWIS1,
|
||||||
declare!(SPU);
|
UARTE2_SPIM2_SPIS2_TWIM2_TWIS2,
|
||||||
declare!(CLOCK_POWER);
|
UARTE3_SPIM3_SPIS3_TWIM3_TWIS3,
|
||||||
declare!(UARTE0_SPIM0_SPIS0_TWIM0_TWIS0);
|
GPIOTE0,
|
||||||
declare!(UARTE1_SPIM1_SPIS1_TWIM1_TWIS1);
|
SAADC,
|
||||||
declare!(UARTE2_SPIM2_SPIS2_TWIM2_TWIS2);
|
TIMER0,
|
||||||
declare!(UARTE3_SPIM3_SPIS3_TWIM3_TWIS3);
|
TIMER1,
|
||||||
declare!(GPIOTE0);
|
TIMER2,
|
||||||
declare!(SAADC);
|
RTC0,
|
||||||
declare!(TIMER0);
|
RTC1,
|
||||||
declare!(TIMER1);
|
WDT,
|
||||||
declare!(TIMER2);
|
EGU0,
|
||||||
declare!(RTC0);
|
EGU1,
|
||||||
declare!(RTC1);
|
EGU2,
|
||||||
declare!(WDT);
|
EGU3,
|
||||||
declare!(EGU0);
|
EGU4,
|
||||||
declare!(EGU1);
|
EGU5,
|
||||||
declare!(EGU2);
|
PWM0,
|
||||||
declare!(EGU3);
|
PWM1,
|
||||||
declare!(EGU4);
|
PWM2,
|
||||||
declare!(EGU5);
|
PDM,
|
||||||
declare!(PWM0);
|
PWM3,
|
||||||
declare!(PWM1);
|
I2S,
|
||||||
declare!(PWM2);
|
IPC,
|
||||||
declare!(PDM);
|
FPU,
|
||||||
declare!(PWM3);
|
GPIOTE1,
|
||||||
declare!(I2S);
|
KMU,
|
||||||
declare!(IPC);
|
CRYPTOCELL,
|
||||||
declare!(FPU);
|
);
|
||||||
declare!(GPIOTE1);
|
|
||||||
declare!(KMU);
|
|
||||||
declare!(CRYPTOCELL);
|
|
||||||
}
|
|
||||||
|
@ -9,7 +9,7 @@ use embassy_sync::waitqueue::AtomicWaker;
|
|||||||
|
|
||||||
use crate::gpio::sealed::Pin as _;
|
use crate::gpio::sealed::Pin as _;
|
||||||
use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin};
|
use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin};
|
||||||
use crate::interrupt::{Interrupt, InterruptExt};
|
use crate::interrupt::InterruptExt;
|
||||||
use crate::ppi::{Event, Task};
|
use crate::ppi::{Event, Task};
|
||||||
use crate::{interrupt, pac, peripherals};
|
use crate::{interrupt, pac, peripherals};
|
||||||
|
|
||||||
@ -74,42 +74,41 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Enable interrupts
|
// Enable interrupts
|
||||||
cfg_if::cfg_if! {
|
#[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s"))]
|
||||||
if #[cfg(any(feature="nrf5340-app-s", feature="nrf9160-s"))] {
|
let irq = interrupt::GPIOTE0;
|
||||||
let irq = unsafe { interrupt::GPIOTE0::steal() };
|
#[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns"))]
|
||||||
} else if #[cfg(any(feature="nrf5340-app-ns", feature="nrf9160-ns"))] {
|
let irq = interrupt::GPIOTE1;
|
||||||
let irq = unsafe { interrupt::GPIOTE1::steal() };
|
#[cfg(any(feature = "_nrf52", feature = "nrf5340-net"))]
|
||||||
} else {
|
let irq = interrupt::GPIOTE;
|
||||||
let irq = unsafe { interrupt::GPIOTE::steal() };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
irq.unpend();
|
irq.unpend();
|
||||||
irq.set_priority(irq_prio);
|
irq.set_priority(irq_prio);
|
||||||
irq.enable();
|
unsafe { irq.enable() };
|
||||||
|
|
||||||
let g = regs();
|
let g = regs();
|
||||||
g.events_port.write(|w| w);
|
g.events_port.write(|w| w);
|
||||||
g.intenset.write(|w| w.port().set());
|
g.intenset.write(|w| w.port().set());
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg_if::cfg_if! {
|
#[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s"))]
|
||||||
if #[cfg(any(feature="nrf5340-app-s", feature="nrf9160-s"))] {
|
#[cfg(feature = "rt")]
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
fn GPIOTE0() {
|
fn GPIOTE0() {
|
||||||
unsafe { handle_gpiote_interrupt() };
|
unsafe { handle_gpiote_interrupt() };
|
||||||
}
|
}
|
||||||
} else if #[cfg(any(feature="nrf5340-app-ns", feature="nrf9160-ns"))] {
|
|
||||||
#[interrupt]
|
#[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns"))]
|
||||||
fn GPIOTE1() {
|
#[cfg(feature = "rt")]
|
||||||
|
#[interrupt]
|
||||||
|
fn GPIOTE1() {
|
||||||
unsafe { handle_gpiote_interrupt() };
|
unsafe { handle_gpiote_interrupt() };
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
#[interrupt]
|
#[cfg(any(feature = "_nrf52", feature = "nrf5340-net"))]
|
||||||
fn GPIOTE() {
|
#[cfg(feature = "rt")]
|
||||||
|
#[interrupt]
|
||||||
|
fn GPIOTE() {
|
||||||
unsafe { handle_gpiote_interrupt() };
|
unsafe { handle_gpiote_interrupt() };
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn handle_gpiote_interrupt() {
|
unsafe fn handle_gpiote_interrupt() {
|
||||||
|
@ -9,15 +9,14 @@ use core::ops::{Deref, DerefMut};
|
|||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use embassy_cortex_m::interrupt::InterruptExt;
|
|
||||||
use embassy_hal_common::drop::OnDrop;
|
use embassy_hal_common::drop::OnDrop;
|
||||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||||
|
|
||||||
use crate::gpio::{AnyPin, Pin as GpioPin};
|
use crate::gpio::{AnyPin, Pin as GpioPin};
|
||||||
use crate::interrupt::{self, Interrupt};
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
use crate::pac::i2s::RegisterBlock;
|
use crate::pac::i2s::RegisterBlock;
|
||||||
use crate::util::{slice_in_ram_or, slice_ptr_parts};
|
use crate::util::{slice_in_ram_or, slice_ptr_parts};
|
||||||
use crate::{Peripheral, EASY_DMA_SIZE};
|
use crate::{interrupt, Peripheral, EASY_DMA_SIZE};
|
||||||
|
|
||||||
/// Type alias for `MultiBuffering` with 2 buffers.
|
/// Type alias for `MultiBuffering` with 2 buffers.
|
||||||
pub type DoubleBuffering<S, const NS: usize> = MultiBuffering<S, 2, NS>;
|
pub type DoubleBuffering<S, const NS: usize> = MultiBuffering<S, 2, NS>;
|
||||||
@ -368,7 +367,7 @@ pub struct InterruptHandler<T: Instance> {
|
|||||||
_phantom: PhantomData<T>,
|
_phantom: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
let device = Device::<T>::new();
|
let device = Device::<T>::new();
|
||||||
let s = T::state();
|
let s = T::state();
|
||||||
@ -409,7 +408,7 @@ impl<'d, T: Instance> I2S<'d, T> {
|
|||||||
/// Create a new I2S in master mode
|
/// Create a new I2S in master mode
|
||||||
pub fn new_master(
|
pub fn new_master(
|
||||||
i2s: impl Peripheral<P = T> + 'd,
|
i2s: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
mck: impl Peripheral<P = impl GpioPin> + 'd,
|
mck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
lrck: impl Peripheral<P = impl GpioPin> + 'd,
|
lrck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
@ -432,7 +431,7 @@ impl<'d, T: Instance> I2S<'d, T> {
|
|||||||
/// Create a new I2S in slave mode
|
/// Create a new I2S in slave mode
|
||||||
pub fn new_slave(
|
pub fn new_slave(
|
||||||
i2s: impl Peripheral<P = T> + 'd,
|
i2s: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
lrck: impl Peripheral<P = impl GpioPin> + 'd,
|
lrck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
@ -564,8 +563,8 @@ impl<'d, T: Instance> I2S<'d, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn setup_interrupt(&self) {
|
fn setup_interrupt(&self) {
|
||||||
unsafe { T::Interrupt::steal() }.unpend();
|
T::Interrupt::unpend();
|
||||||
unsafe { T::Interrupt::steal() }.enable();
|
unsafe { T::Interrupt::enable() };
|
||||||
|
|
||||||
let device = Device::<T>::new();
|
let device = Device::<T>::new();
|
||||||
device.disable_tx_ptr_interrupt();
|
device.disable_tx_ptr_interrupt();
|
||||||
@ -1174,7 +1173,7 @@ pub(crate) mod sealed {
|
|||||||
/// I2S peripheral instance.
|
/// I2S peripheral instance.
|
||||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
|
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
|
||||||
/// Interrupt for this peripheral.
|
/// Interrupt for this peripheral.
|
||||||
type Interrupt: Interrupt;
|
type Interrupt: interrupt::typelevel::Interrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_i2s {
|
macro_rules! impl_i2s {
|
||||||
@ -1189,7 +1188,7 @@ macro_rules! impl_i2s {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl crate::i2s::Instance for peripherals::$type {
|
impl crate::i2s::Instance for peripherals::$type {
|
||||||
type Interrupt = crate::interrupt::$irq;
|
type Interrupt = crate::interrupt::typelevel::$irq;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -93,21 +93,14 @@ pub mod wdt;
|
|||||||
#[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")]
|
#[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")]
|
||||||
mod chip;
|
mod chip;
|
||||||
|
|
||||||
pub mod interrupt {
|
/// Macro to bind interrupts to handlers.
|
||||||
//! Interrupt definitions and macros to bind them.
|
///
|
||||||
pub use cortex_m::interrupt::{CriticalSection, Mutex};
|
/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
|
||||||
pub use embassy_cortex_m::interrupt::{Binding, Handler, Interrupt, InterruptExt, Priority};
|
/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
|
||||||
|
/// prove at compile-time that the right interrupts have been bound.
|
||||||
pub use crate::chip::irqs::*;
|
// developer note: this macro can't be in `embassy-hal-common` due to the use of `$crate`.
|
||||||
|
#[macro_export]
|
||||||
/// Macro to bind interrupts to handlers.
|
macro_rules! bind_interrupts {
|
||||||
///
|
|
||||||
/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
|
|
||||||
/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
|
|
||||||
/// prove at compile-time that the right interrupts have been bound.
|
|
||||||
// developer note: this macro can't be in `embassy-cortex-m` due to the use of `$crate`.
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! bind_interrupts {
|
|
||||||
($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
|
($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
|
||||||
$vis struct $name;
|
$vis struct $name;
|
||||||
|
|
||||||
@ -116,17 +109,16 @@ pub mod interrupt {
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
unsafe extern "C" fn $irq() {
|
unsafe extern "C" fn $irq() {
|
||||||
$(
|
$(
|
||||||
<$handler as $crate::interrupt::Handler<$crate::interrupt::$irq>>::on_interrupt();
|
<$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt();
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
|
|
||||||
$(
|
$(
|
||||||
unsafe impl $crate::interrupt::Binding<$crate::interrupt::$irq, $handler> for $name {}
|
unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {}
|
||||||
)*
|
)*
|
||||||
)*
|
)*
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Reexports
|
// Reexports
|
||||||
|
|
||||||
@ -135,10 +127,11 @@ pub use chip::pac;
|
|||||||
#[cfg(not(feature = "unstable-pac"))]
|
#[cfg(not(feature = "unstable-pac"))]
|
||||||
pub(crate) use chip::pac;
|
pub(crate) use chip::pac;
|
||||||
pub use chip::{peripherals, Peripherals, EASY_DMA_SIZE};
|
pub use chip::{peripherals, Peripherals, EASY_DMA_SIZE};
|
||||||
pub use embassy_cortex_m::executor;
|
|
||||||
pub use embassy_cortex_m::interrupt::_export::interrupt;
|
|
||||||
pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
|
pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
|
||||||
|
|
||||||
|
pub use crate::chip::interrupt;
|
||||||
|
pub use crate::pac::NVIC_PRIO_BITS;
|
||||||
|
|
||||||
pub mod config {
|
pub mod config {
|
||||||
//! Configuration options used when initializing the HAL.
|
//! Configuration options used when initializing the HAL.
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ use core::marker::PhantomData;
|
|||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use embassy_cortex_m::interrupt::Interrupt;
|
|
||||||
use embassy_hal_common::drop::OnDrop;
|
use embassy_hal_common::drop::OnDrop;
|
||||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||||
use futures::future::poll_fn;
|
use futures::future::poll_fn;
|
||||||
@ -14,15 +13,15 @@ use futures::future::poll_fn;
|
|||||||
use crate::chip::EASY_DMA_SIZE;
|
use crate::chip::EASY_DMA_SIZE;
|
||||||
use crate::gpio::sealed::Pin;
|
use crate::gpio::sealed::Pin;
|
||||||
use crate::gpio::{AnyPin, Pin as GpioPin};
|
use crate::gpio::{AnyPin, Pin as GpioPin};
|
||||||
use crate::interrupt::{self, InterruptExt};
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
use crate::Peripheral;
|
use crate::{interrupt, Peripheral};
|
||||||
|
|
||||||
/// Interrupt handler.
|
/// Interrupt handler.
|
||||||
pub struct InterruptHandler<T: Instance> {
|
pub struct InterruptHandler<T: Instance> {
|
||||||
_phantom: PhantomData<T>,
|
_phantom: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
T::regs().intenclr.write(|w| w.end().clear());
|
T::regs().intenclr.write(|w| w.end().clear());
|
||||||
T::state().waker.wake();
|
T::state().waker.wake();
|
||||||
@ -53,7 +52,7 @@ impl<'d, T: Instance> Pdm<'d, T> {
|
|||||||
/// Create PDM driver
|
/// Create PDM driver
|
||||||
pub fn new(
|
pub fn new(
|
||||||
pdm: impl Peripheral<P = T> + 'd,
|
pdm: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
clk: impl Peripheral<P = impl GpioPin> + 'd,
|
clk: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
din: impl Peripheral<P = impl GpioPin> + 'd,
|
din: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
@ -94,8 +93,8 @@ impl<'d, T: Instance> Pdm<'d, T> {
|
|||||||
r.gainr.write(|w| w.gainr().default_gain());
|
r.gainr.write(|w| w.gainr().default_gain());
|
||||||
|
|
||||||
// IRQ
|
// IRQ
|
||||||
unsafe { T::Interrupt::steal() }.unpend();
|
T::Interrupt::unpend();
|
||||||
unsafe { T::Interrupt::steal() }.enable();
|
unsafe { T::Interrupt::enable() };
|
||||||
|
|
||||||
r.enable.write(|w| w.enable().set_bit());
|
r.enable.write(|w| w.enable().set_bit());
|
||||||
|
|
||||||
@ -274,7 +273,7 @@ pub(crate) mod sealed {
|
|||||||
/// PDM peripheral instance.
|
/// PDM peripheral instance.
|
||||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
|
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
|
||||||
/// Interrupt for this peripheral.
|
/// Interrupt for this peripheral.
|
||||||
type Interrupt: Interrupt;
|
type Interrupt: interrupt::typelevel::Interrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_pdm {
|
macro_rules! impl_pdm {
|
||||||
@ -289,7 +288,7 @@ macro_rules! impl_pdm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl crate::pdm::Instance for peripherals::$type {
|
impl crate::pdm::Instance for peripherals::$type {
|
||||||
type Interrupt = crate::interrupt::$irq;
|
type Interrupt = crate::interrupt::typelevel::$irq;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,9 @@ use embassy_hal_common::{into_ref, PeripheralRef};
|
|||||||
|
|
||||||
use crate::gpio::sealed::Pin as _;
|
use crate::gpio::sealed::Pin as _;
|
||||||
use crate::gpio::{AnyPin, Pin as GpioPin, PselBits};
|
use crate::gpio::{AnyPin, Pin as GpioPin, PselBits};
|
||||||
use crate::interrupt::Interrupt;
|
|
||||||
use crate::ppi::{Event, Task};
|
use crate::ppi::{Event, Task};
|
||||||
use crate::util::slice_in_ram_or;
|
use crate::util::slice_in_ram_or;
|
||||||
use crate::{pac, Peripheral};
|
use crate::{interrupt, pac, Peripheral};
|
||||||
|
|
||||||
/// SimplePwm is the traditional pwm interface you're probably used to, allowing
|
/// SimplePwm is the traditional pwm interface you're probably used to, allowing
|
||||||
/// to simply set a duty cycle across up to four channels.
|
/// to simply set a duty cycle across up to four channels.
|
||||||
@ -843,7 +842,7 @@ pub(crate) mod sealed {
|
|||||||
/// PWM peripheral instance.
|
/// PWM peripheral instance.
|
||||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
|
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
|
||||||
/// Interrupt for this peripheral.
|
/// Interrupt for this peripheral.
|
||||||
type Interrupt: Interrupt;
|
type Interrupt: interrupt::typelevel::Interrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_pwm {
|
macro_rules! impl_pwm {
|
||||||
@ -854,7 +853,7 @@ macro_rules! impl_pwm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl crate::pwm::Instance for peripherals::$type {
|
impl crate::pwm::Instance for peripherals::$type {
|
||||||
type Interrupt = crate::interrupt::$irq;
|
type Interrupt = crate::interrupt::typelevel::$irq;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,11 @@ use core::future::poll_fn;
|
|||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use embassy_cortex_m::interrupt::Interrupt;
|
|
||||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||||
|
|
||||||
use crate::gpio::sealed::Pin as _;
|
use crate::gpio::sealed::Pin as _;
|
||||||
use crate::gpio::{AnyPin, Pin as GpioPin};
|
use crate::gpio::{AnyPin, Pin as GpioPin};
|
||||||
use crate::interrupt::InterruptExt;
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
use crate::{interrupt, Peripheral};
|
use crate::{interrupt, Peripheral};
|
||||||
|
|
||||||
/// Quadrature decoder driver.
|
/// Quadrature decoder driver.
|
||||||
@ -51,7 +50,7 @@ pub struct InterruptHandler<T: Instance> {
|
|||||||
_phantom: PhantomData<T>,
|
_phantom: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
T::regs().intenclr.write(|w| w.reportrdy().clear());
|
T::regs().intenclr.write(|w| w.reportrdy().clear());
|
||||||
T::state().waker.wake();
|
T::state().waker.wake();
|
||||||
@ -62,7 +61,7 @@ impl<'d, T: Instance> Qdec<'d, T> {
|
|||||||
/// Create a new QDEC.
|
/// Create a new QDEC.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
qdec: impl Peripheral<P = T> + 'd,
|
qdec: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
a: impl Peripheral<P = impl GpioPin> + 'd,
|
a: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
b: impl Peripheral<P = impl GpioPin> + 'd,
|
b: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
@ -74,7 +73,7 @@ impl<'d, T: Instance> Qdec<'d, T> {
|
|||||||
/// Create a new QDEC, with a pin for LED output.
|
/// Create a new QDEC, with a pin for LED output.
|
||||||
pub fn new_with_led(
|
pub fn new_with_led(
|
||||||
qdec: impl Peripheral<P = T> + 'd,
|
qdec: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
a: impl Peripheral<P = impl GpioPin> + 'd,
|
a: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
b: impl Peripheral<P = impl GpioPin> + 'd,
|
b: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
led: impl Peripheral<P = impl GpioPin> + 'd,
|
led: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
@ -134,8 +133,8 @@ impl<'d, T: Instance> Qdec<'d, T> {
|
|||||||
SamplePeriod::_131ms => w.sampleper()._131ms(),
|
SamplePeriod::_131ms => w.sampleper()._131ms(),
|
||||||
});
|
});
|
||||||
|
|
||||||
unsafe { T::Interrupt::steal() }.unpend();
|
T::Interrupt::unpend();
|
||||||
unsafe { T::Interrupt::steal() }.enable();
|
unsafe { T::Interrupt::enable() };
|
||||||
|
|
||||||
// Enable peripheral
|
// Enable peripheral
|
||||||
r.enable.write(|w| w.enable().set_bit());
|
r.enable.write(|w| w.enable().set_bit());
|
||||||
@ -272,7 +271,7 @@ pub(crate) mod sealed {
|
|||||||
/// qdec peripheral instance.
|
/// qdec peripheral instance.
|
||||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
|
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
|
||||||
/// Interrupt for this peripheral.
|
/// Interrupt for this peripheral.
|
||||||
type Interrupt: Interrupt;
|
type Interrupt: interrupt::typelevel::Interrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_qdec {
|
macro_rules! impl_qdec {
|
||||||
@ -287,7 +286,7 @@ macro_rules! impl_qdec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl crate::qdec::Instance for peripherals::$type {
|
impl crate::qdec::Instance for peripherals::$type {
|
||||||
type Interrupt = crate::interrupt::$irq;
|
type Interrupt = crate::interrupt::typelevel::$irq;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -12,12 +12,12 @@ use embassy_hal_common::{into_ref, PeripheralRef};
|
|||||||
use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash};
|
use embedded_storage::nor_flash::{ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash};
|
||||||
|
|
||||||
use crate::gpio::{self, Pin as GpioPin};
|
use crate::gpio::{self, Pin as GpioPin};
|
||||||
use crate::interrupt::{self, Interrupt, InterruptExt};
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
pub use crate::pac::qspi::ifconfig0::{
|
pub use crate::pac::qspi::ifconfig0::{
|
||||||
ADDRMODE_A as AddressMode, PPSIZE_A as WritePageSize, READOC_A as ReadOpcode, WRITEOC_A as WriteOpcode,
|
ADDRMODE_A as AddressMode, PPSIZE_A as WritePageSize, READOC_A as ReadOpcode, WRITEOC_A as WriteOpcode,
|
||||||
};
|
};
|
||||||
pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode;
|
pub use crate::pac::qspi::ifconfig1::SPIMODE_A as SpiMode;
|
||||||
use crate::Peripheral;
|
use crate::{interrupt, Peripheral};
|
||||||
|
|
||||||
/// Deep power-down config.
|
/// Deep power-down config.
|
||||||
pub struct DeepPowerDownConfig {
|
pub struct DeepPowerDownConfig {
|
||||||
@ -120,7 +120,7 @@ pub struct InterruptHandler<T: Instance> {
|
|||||||
_phantom: PhantomData<T>,
|
_phantom: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
let s = T::state();
|
let s = T::state();
|
||||||
@ -143,7 +143,7 @@ impl<'d, T: Instance> Qspi<'d, T> {
|
|||||||
/// Create a new QSPI driver.
|
/// Create a new QSPI driver.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
qspi: impl Peripheral<P = T> + 'd,
|
qspi: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
csn: impl Peripheral<P = impl GpioPin> + 'd,
|
csn: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
io0: impl Peripheral<P = impl GpioPin> + 'd,
|
io0: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
@ -207,8 +207,8 @@ impl<'d, T: Instance> Qspi<'d, T> {
|
|||||||
w
|
w
|
||||||
});
|
});
|
||||||
|
|
||||||
unsafe { T::Interrupt::steal() }.unpend();
|
T::Interrupt::unpend();
|
||||||
unsafe { T::Interrupt::steal() }.enable();
|
unsafe { T::Interrupt::enable() };
|
||||||
|
|
||||||
// Enable it
|
// Enable it
|
||||||
r.enable.write(|w| w.enable().enabled());
|
r.enable.write(|w| w.enable().enabled());
|
||||||
@ -644,7 +644,7 @@ pub(crate) mod sealed {
|
|||||||
/// QSPI peripheral instance.
|
/// QSPI peripheral instance.
|
||||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
|
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
|
||||||
/// Interrupt for this peripheral.
|
/// Interrupt for this peripheral.
|
||||||
type Interrupt: Interrupt;
|
type Interrupt: interrupt::typelevel::Interrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_qspi {
|
macro_rules! impl_qspi {
|
||||||
@ -659,7 +659,7 @@ macro_rules! impl_qspi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl crate::qspi::Instance for peripherals::$type {
|
impl crate::qspi::Instance for peripherals::$type {
|
||||||
type Interrupt = crate::interrupt::$irq;
|
type Interrupt = crate::interrupt::typelevel::$irq;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,11 @@ use core::ptr;
|
|||||||
use core::sync::atomic::{AtomicPtr, Ordering};
|
use core::sync::atomic::{AtomicPtr, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use embassy_cortex_m::interrupt::Interrupt;
|
|
||||||
use embassy_hal_common::drop::OnDrop;
|
use embassy_hal_common::drop::OnDrop;
|
||||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
|
|
||||||
use crate::interrupt::InterruptExt;
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
use crate::{interrupt, Peripheral};
|
use crate::{interrupt, Peripheral};
|
||||||
|
|
||||||
/// Interrupt handler.
|
/// Interrupt handler.
|
||||||
@ -21,7 +20,7 @@ pub struct InterruptHandler<T: Instance> {
|
|||||||
_phantom: PhantomData<T>,
|
_phantom: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
let s = T::state();
|
let s = T::state();
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
@ -90,7 +89,7 @@ impl<'d, T: Instance> Rng<'d, T> {
|
|||||||
/// The synchronous API is safe.
|
/// The synchronous API is safe.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
rng: impl Peripheral<P = T> + 'd,
|
rng: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(rng);
|
into_ref!(rng);
|
||||||
|
|
||||||
@ -99,8 +98,8 @@ impl<'d, T: Instance> Rng<'d, T> {
|
|||||||
this.stop();
|
this.stop();
|
||||||
this.disable_irq();
|
this.disable_irq();
|
||||||
|
|
||||||
unsafe { T::Interrupt::steal() }.unpend();
|
T::Interrupt::unpend();
|
||||||
unsafe { T::Interrupt::steal() }.enable();
|
unsafe { T::Interrupt::enable() };
|
||||||
|
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
@ -256,7 +255,7 @@ pub(crate) mod sealed {
|
|||||||
/// RNG peripheral instance.
|
/// RNG peripheral instance.
|
||||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
|
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
|
||||||
/// Interrupt for this peripheral.
|
/// Interrupt for this peripheral.
|
||||||
type Interrupt: Interrupt;
|
type Interrupt: interrupt::typelevel::Interrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_rng {
|
macro_rules! impl_rng {
|
||||||
@ -271,7 +270,7 @@ macro_rules! impl_rng {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl crate::rng::Instance for peripherals::$type {
|
impl crate::rng::Instance for peripherals::$type {
|
||||||
type Interrupt = crate::interrupt::$irq;
|
type Interrupt = crate::interrupt::typelevel::$irq;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ use core::future::poll_fn;
|
|||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
|
|
||||||
use embassy_hal_common::drop::OnDrop;
|
use embassy_hal_common::drop::OnDrop;
|
||||||
use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
|
use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
@ -18,6 +17,7 @@ use saadc::oversample::OVERSAMPLE_A;
|
|||||||
use saadc::resolution::VAL_A;
|
use saadc::resolution::VAL_A;
|
||||||
|
|
||||||
use self::sealed::Input as _;
|
use self::sealed::Input as _;
|
||||||
|
use crate::interrupt::InterruptExt;
|
||||||
use crate::ppi::{ConfigurableChannel, Event, Ppi, Task};
|
use crate::ppi::{ConfigurableChannel, Event, Ppi, Task};
|
||||||
use crate::timer::{Frequency, Instance as TimerInstance, Timer};
|
use crate::timer::{Frequency, Instance as TimerInstance, Timer};
|
||||||
use crate::{interrupt, pac, peripherals, Peripheral};
|
use crate::{interrupt, pac, peripherals, Peripheral};
|
||||||
@ -33,7 +33,7 @@ pub struct InterruptHandler {
|
|||||||
_private: (),
|
_private: (),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl interrupt::Handler<interrupt::SAADC> for InterruptHandler {
|
impl interrupt::typelevel::Handler<interrupt::typelevel::SAADC> for InterruptHandler {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
let r = unsafe { &*SAADC::ptr() };
|
let r = unsafe { &*SAADC::ptr() };
|
||||||
|
|
||||||
@ -144,7 +144,7 @@ impl<'d, const N: usize> Saadc<'d, N> {
|
|||||||
/// Create a new SAADC driver.
|
/// Create a new SAADC driver.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
saadc: impl Peripheral<P = peripherals::SAADC> + 'd,
|
saadc: impl Peripheral<P = peripherals::SAADC> + 'd,
|
||||||
_irq: impl interrupt::Binding<interrupt::SAADC, InterruptHandler> + 'd,
|
_irq: impl interrupt::typelevel::Binding<interrupt::typelevel::SAADC, InterruptHandler> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
channel_configs: [ChannelConfig; N],
|
channel_configs: [ChannelConfig; N],
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@ -189,8 +189,8 @@ impl<'d, const N: usize> Saadc<'d, N> {
|
|||||||
// Disable all events interrupts
|
// Disable all events interrupts
|
||||||
r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) });
|
r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) });
|
||||||
|
|
||||||
unsafe { interrupt::SAADC::steal() }.unpend();
|
interrupt::SAADC.unpend();
|
||||||
unsafe { interrupt::SAADC::steal() }.enable();
|
unsafe { interrupt::SAADC.enable() };
|
||||||
|
|
||||||
Self { _p: saadc }
|
Self { _p: saadc }
|
||||||
}
|
}
|
||||||
|
@ -15,9 +15,9 @@ pub use pac::spim0::frequency::FREQUENCY_A as Frequency;
|
|||||||
use crate::chip::FORCE_COPY_BUFFER_SIZE;
|
use crate::chip::FORCE_COPY_BUFFER_SIZE;
|
||||||
use crate::gpio::sealed::Pin as _;
|
use crate::gpio::sealed::Pin as _;
|
||||||
use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
|
use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
|
||||||
use crate::interrupt::{self, Interrupt, InterruptExt};
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut};
|
use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut};
|
||||||
use crate::{pac, Peripheral};
|
use crate::{interrupt, pac, Peripheral};
|
||||||
|
|
||||||
/// SPIM error
|
/// SPIM error
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
@ -63,7 +63,7 @@ pub struct InterruptHandler<T: Instance> {
|
|||||||
_phantom: PhantomData<T>,
|
_phantom: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
let s = T::state();
|
let s = T::state();
|
||||||
@ -84,7 +84,7 @@ impl<'d, T: Instance> Spim<'d, T> {
|
|||||||
/// Create a new SPIM driver.
|
/// Create a new SPIM driver.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
spim: impl Peripheral<P = T> + 'd,
|
spim: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
miso: impl Peripheral<P = impl GpioPin> + 'd,
|
miso: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
mosi: impl Peripheral<P = impl GpioPin> + 'd,
|
mosi: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
@ -103,7 +103,7 @@ impl<'d, T: Instance> Spim<'d, T> {
|
|||||||
/// Create a new SPIM driver, capable of TX only (MOSI only).
|
/// Create a new SPIM driver, capable of TX only (MOSI only).
|
||||||
pub fn new_txonly(
|
pub fn new_txonly(
|
||||||
spim: impl Peripheral<P = T> + 'd,
|
spim: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
mosi: impl Peripheral<P = impl GpioPin> + 'd,
|
mosi: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
@ -115,7 +115,7 @@ impl<'d, T: Instance> Spim<'d, T> {
|
|||||||
/// Create a new SPIM driver, capable of RX only (MISO only).
|
/// Create a new SPIM driver, capable of RX only (MISO only).
|
||||||
pub fn new_rxonly(
|
pub fn new_rxonly(
|
||||||
spim: impl Peripheral<P = T> + 'd,
|
spim: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
miso: impl Peripheral<P = impl GpioPin> + 'd,
|
miso: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
@ -207,8 +207,8 @@ impl<'d, T: Instance> Spim<'d, T> {
|
|||||||
// Disable all events interrupts
|
// Disable all events interrupts
|
||||||
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
||||||
|
|
||||||
unsafe { T::Interrupt::steal() }.unpend();
|
T::Interrupt::unpend();
|
||||||
unsafe { T::Interrupt::steal() }.enable();
|
unsafe { T::Interrupt::enable() };
|
||||||
|
|
||||||
Self { _p: spim }
|
Self { _p: spim }
|
||||||
}
|
}
|
||||||
@ -408,7 +408,7 @@ pub(crate) mod sealed {
|
|||||||
/// SPIM peripheral instance
|
/// SPIM peripheral instance
|
||||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
|
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
|
||||||
/// Interrupt for this peripheral.
|
/// Interrupt for this peripheral.
|
||||||
type Interrupt: Interrupt;
|
type Interrupt: interrupt::typelevel::Interrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_spim {
|
macro_rules! impl_spim {
|
||||||
@ -423,7 +423,7 @@ macro_rules! impl_spim {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl crate::spim::Instance for peripherals::$type {
|
impl crate::spim::Instance for peripherals::$type {
|
||||||
type Interrupt = crate::interrupt::$irq;
|
type Interrupt = crate::interrupt::typelevel::$irq;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -13,9 +13,9 @@ pub use embedded_hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MO
|
|||||||
use crate::chip::FORCE_COPY_BUFFER_SIZE;
|
use crate::chip::FORCE_COPY_BUFFER_SIZE;
|
||||||
use crate::gpio::sealed::Pin as _;
|
use crate::gpio::sealed::Pin as _;
|
||||||
use crate::gpio::{self, AnyPin, Pin as GpioPin};
|
use crate::gpio::{self, AnyPin, Pin as GpioPin};
|
||||||
use crate::interrupt::{self, Interrupt, InterruptExt};
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut};
|
use crate::util::{slice_in_ram_or, slice_ptr_parts, slice_ptr_parts_mut};
|
||||||
use crate::{pac, Peripheral};
|
use crate::{interrupt, pac, Peripheral};
|
||||||
|
|
||||||
/// SPIS error
|
/// SPIS error
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
@ -68,7 +68,7 @@ pub struct InterruptHandler<T: Instance> {
|
|||||||
_phantom: PhantomData<T>,
|
_phantom: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
let s = T::state();
|
let s = T::state();
|
||||||
@ -94,7 +94,7 @@ impl<'d, T: Instance> Spis<'d, T> {
|
|||||||
/// Create a new SPIS driver.
|
/// Create a new SPIS driver.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
spis: impl Peripheral<P = T> + 'd,
|
spis: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
cs: impl Peripheral<P = impl GpioPin> + 'd,
|
cs: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
miso: impl Peripheral<P = impl GpioPin> + 'd,
|
miso: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
@ -115,7 +115,7 @@ impl<'d, T: Instance> Spis<'d, T> {
|
|||||||
/// Create a new SPIS driver, capable of TX only (MISO only).
|
/// Create a new SPIS driver, capable of TX only (MISO only).
|
||||||
pub fn new_txonly(
|
pub fn new_txonly(
|
||||||
spis: impl Peripheral<P = T> + 'd,
|
spis: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
cs: impl Peripheral<P = impl GpioPin> + 'd,
|
cs: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
miso: impl Peripheral<P = impl GpioPin> + 'd,
|
miso: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
@ -128,7 +128,7 @@ impl<'d, T: Instance> Spis<'d, T> {
|
|||||||
/// Create a new SPIS driver, capable of RX only (MOSI only).
|
/// Create a new SPIS driver, capable of RX only (MOSI only).
|
||||||
pub fn new_rxonly(
|
pub fn new_rxonly(
|
||||||
spis: impl Peripheral<P = T> + 'd,
|
spis: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
cs: impl Peripheral<P = impl GpioPin> + 'd,
|
cs: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
sck: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
mosi: impl Peripheral<P = impl GpioPin> + 'd,
|
mosi: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
@ -214,8 +214,8 @@ impl<'d, T: Instance> Spis<'d, T> {
|
|||||||
// Disable all events interrupts.
|
// Disable all events interrupts.
|
||||||
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
||||||
|
|
||||||
unsafe { T::Interrupt::steal() }.unpend();
|
T::Interrupt::unpend();
|
||||||
unsafe { T::Interrupt::steal() }.enable();
|
unsafe { T::Interrupt::enable() };
|
||||||
|
|
||||||
Self { _p: spis }
|
Self { _p: spis }
|
||||||
}
|
}
|
||||||
@ -480,7 +480,7 @@ pub(crate) mod sealed {
|
|||||||
/// SPIS peripheral instance
|
/// SPIS peripheral instance
|
||||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
|
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
|
||||||
/// Interrupt for this peripheral.
|
/// Interrupt for this peripheral.
|
||||||
type Interrupt: Interrupt;
|
type Interrupt: interrupt::typelevel::Interrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_spis {
|
macro_rules! impl_spis {
|
||||||
@ -495,7 +495,7 @@ macro_rules! impl_spis {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl crate::spis::Instance for peripherals::$type {
|
impl crate::spis::Instance for peripherals::$type {
|
||||||
type Interrupt = crate::interrupt::$irq;
|
type Interrupt = crate::interrupt::typelevel::$irq;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
use core::future::poll_fn;
|
use core::future::poll_fn;
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use embassy_cortex_m::interrupt::Interrupt;
|
|
||||||
use embassy_hal_common::drop::OnDrop;
|
use embassy_hal_common::drop::OnDrop;
|
||||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
@ -18,7 +17,7 @@ pub struct InterruptHandler {
|
|||||||
_private: (),
|
_private: (),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl interrupt::Handler<interrupt::TEMP> for InterruptHandler {
|
impl interrupt::typelevel::Handler<interrupt::typelevel::TEMP> for InterruptHandler {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
let r = unsafe { &*pac::TEMP::PTR };
|
let r = unsafe { &*pac::TEMP::PTR };
|
||||||
r.intenclr.write(|w| w.datardy().clear());
|
r.intenclr.write(|w| w.datardy().clear());
|
||||||
@ -37,13 +36,13 @@ impl<'d> Temp<'d> {
|
|||||||
/// Create a new temperature sensor driver.
|
/// Create a new temperature sensor driver.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
_peri: impl Peripheral<P = TEMP> + 'd,
|
_peri: impl Peripheral<P = TEMP> + 'd,
|
||||||
_irq: impl interrupt::Binding<interrupt::TEMP, InterruptHandler> + 'd,
|
_irq: impl interrupt::typelevel::Binding<interrupt::typelevel::TEMP, InterruptHandler> + 'd,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(_peri);
|
into_ref!(_peri);
|
||||||
|
|
||||||
// Enable interrupt that signals temperature values
|
// Enable interrupt that signals temperature values
|
||||||
unsafe { interrupt::TEMP::steal() }.unpend();
|
interrupt::TEMP.unpend();
|
||||||
unsafe { interrupt::TEMP::steal() }.enable();
|
unsafe { interrupt::TEMP.enable() };
|
||||||
|
|
||||||
Self { _peri }
|
Self { _peri }
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
|||||||
use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex;
|
use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex;
|
||||||
use embassy_time::driver::{AlarmHandle, Driver};
|
use embassy_time::driver::{AlarmHandle, Driver};
|
||||||
|
|
||||||
use crate::interrupt::{Interrupt, InterruptExt};
|
use crate::interrupt::InterruptExt;
|
||||||
use crate::{interrupt, pac};
|
use crate::{interrupt, pac};
|
||||||
|
|
||||||
fn rtc() -> &'static pac::rtc0::RegisterBlock {
|
fn rtc() -> &'static pac::rtc0::RegisterBlock {
|
||||||
@ -142,9 +142,8 @@ impl RtcDriver {
|
|||||||
// Wait for clear
|
// Wait for clear
|
||||||
while r.counter.read().bits() != 0 {}
|
while r.counter.read().bits() != 0 {}
|
||||||
|
|
||||||
let irq = unsafe { interrupt::RTC1::steal() };
|
interrupt::RTC1.set_priority(irq_prio);
|
||||||
irq.set_priority(irq_prio);
|
unsafe { interrupt::RTC1.enable() };
|
||||||
irq.enable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_interrupt(&self) {
|
fn on_interrupt(&self) {
|
||||||
@ -296,6 +295,7 @@ impl Driver for RtcDriver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rt")]
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
fn RTC1() {
|
fn RTC1() {
|
||||||
DRIVER.on_interrupt()
|
DRIVER.on_interrupt()
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||||
|
|
||||||
use crate::interrupt::Interrupt;
|
|
||||||
use crate::ppi::{Event, Task};
|
use crate::ppi::{Event, Task};
|
||||||
use crate::{pac, Peripheral};
|
use crate::{pac, Peripheral};
|
||||||
|
|
||||||
@ -29,7 +28,7 @@ pub(crate) mod sealed {
|
|||||||
/// Basic Timer instance.
|
/// Basic Timer instance.
|
||||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
|
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
|
||||||
/// Interrupt for this peripheral.
|
/// Interrupt for this peripheral.
|
||||||
type Interrupt: Interrupt;
|
type Interrupt: crate::interrupt::typelevel::Interrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extended timer instance.
|
/// Extended timer instance.
|
||||||
@ -44,7 +43,7 @@ macro_rules! impl_timer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl crate::timer::Instance for peripherals::$type {
|
impl crate::timer::Instance for peripherals::$type {
|
||||||
type Interrupt = crate::interrupt::$irq;
|
type Interrupt = crate::interrupt::typelevel::$irq;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
($type:ident, $pac_type:ident, $irq:ident) => {
|
($type:ident, $pac_type:ident, $irq:ident) => {
|
||||||
|
@ -16,9 +16,9 @@ use embassy_time::{Duration, Instant};
|
|||||||
|
|
||||||
use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
||||||
use crate::gpio::Pin as GpioPin;
|
use crate::gpio::Pin as GpioPin;
|
||||||
use crate::interrupt::{self, Interrupt, InterruptExt};
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
use crate::util::{slice_in_ram, slice_in_ram_or};
|
use crate::util::{slice_in_ram, slice_in_ram_or};
|
||||||
use crate::{gpio, pac, Peripheral};
|
use crate::{gpio, interrupt, pac, Peripheral};
|
||||||
|
|
||||||
/// TWI frequency
|
/// TWI frequency
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
@ -98,7 +98,7 @@ pub struct InterruptHandler<T: Instance> {
|
|||||||
_phantom: PhantomData<T>,
|
_phantom: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
let s = T::state();
|
let s = T::state();
|
||||||
@ -123,7 +123,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
|||||||
/// Create a new TWI driver.
|
/// Create a new TWI driver.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
twim: impl Peripheral<P = T> + 'd,
|
twim: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
sda: impl Peripheral<P = impl GpioPin> + 'd,
|
sda: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
scl: impl Peripheral<P = impl GpioPin> + 'd,
|
scl: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
@ -174,8 +174,8 @@ impl<'d, T: Instance> Twim<'d, T> {
|
|||||||
// Disable all events interrupts
|
// Disable all events interrupts
|
||||||
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
||||||
|
|
||||||
unsafe { T::Interrupt::steal() }.unpend();
|
T::Interrupt::unpend();
|
||||||
unsafe { T::Interrupt::steal() }.enable();
|
unsafe { T::Interrupt::enable() };
|
||||||
|
|
||||||
Self { _p: twim }
|
Self { _p: twim }
|
||||||
}
|
}
|
||||||
@ -750,7 +750,7 @@ pub(crate) mod sealed {
|
|||||||
/// TWIM peripheral instance.
|
/// TWIM peripheral instance.
|
||||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
|
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
|
||||||
/// Interrupt for this peripheral.
|
/// Interrupt for this peripheral.
|
||||||
type Interrupt: Interrupt;
|
type Interrupt: interrupt::typelevel::Interrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_twim {
|
macro_rules! impl_twim {
|
||||||
@ -765,7 +765,7 @@ macro_rules! impl_twim {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl crate::twim::Instance for peripherals::$type {
|
impl crate::twim::Instance for peripherals::$type {
|
||||||
type Interrupt = crate::interrupt::$irq;
|
type Interrupt = crate::interrupt::typelevel::$irq;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -15,9 +15,9 @@ use embassy_time::{Duration, Instant};
|
|||||||
|
|
||||||
use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
||||||
use crate::gpio::Pin as GpioPin;
|
use crate::gpio::Pin as GpioPin;
|
||||||
use crate::interrupt::{self, Interrupt, InterruptExt};
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
use crate::util::slice_in_ram_or;
|
use crate::util::slice_in_ram_or;
|
||||||
use crate::{gpio, pac, Peripheral};
|
use crate::{gpio, interrupt, pac, Peripheral};
|
||||||
|
|
||||||
/// TWIS config.
|
/// TWIS config.
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
@ -114,7 +114,7 @@ pub struct InterruptHandler<T: Instance> {
|
|||||||
_phantom: PhantomData<T>,
|
_phantom: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
let s = T::state();
|
let s = T::state();
|
||||||
@ -143,7 +143,7 @@ impl<'d, T: Instance> Twis<'d, T> {
|
|||||||
/// Create a new TWIS driver.
|
/// Create a new TWIS driver.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
twis: impl Peripheral<P = T> + 'd,
|
twis: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
sda: impl Peripheral<P = impl GpioPin> + 'd,
|
sda: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
scl: impl Peripheral<P = impl GpioPin> + 'd,
|
scl: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
@ -204,8 +204,8 @@ impl<'d, T: Instance> Twis<'d, T> {
|
|||||||
// Generate suspend on read event
|
// Generate suspend on read event
|
||||||
r.shorts.write(|w| w.read_suspend().enabled());
|
r.shorts.write(|w| w.read_suspend().enabled());
|
||||||
|
|
||||||
unsafe { T::Interrupt::steal() }.unpend();
|
T::Interrupt::unpend();
|
||||||
unsafe { T::Interrupt::steal() }.enable();
|
unsafe { T::Interrupt::enable() };
|
||||||
|
|
||||||
Self { _p: twis }
|
Self { _p: twis }
|
||||||
}
|
}
|
||||||
@ -778,7 +778,7 @@ pub(crate) mod sealed {
|
|||||||
/// TWIS peripheral instance.
|
/// TWIS peripheral instance.
|
||||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
|
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static {
|
||||||
/// Interrupt for this peripheral.
|
/// Interrupt for this peripheral.
|
||||||
type Interrupt: Interrupt;
|
type Interrupt: interrupt::typelevel::Interrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_twis {
|
macro_rules! impl_twis {
|
||||||
@ -793,7 +793,7 @@ macro_rules! impl_twis {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl crate::twis::Instance for peripherals::$type {
|
impl crate::twis::Instance for peripherals::$type {
|
||||||
type Interrupt = crate::interrupt::$irq;
|
type Interrupt = crate::interrupt::typelevel::$irq;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -27,11 +27,11 @@ pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Pari
|
|||||||
use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE};
|
||||||
use crate::gpio::sealed::Pin as _;
|
use crate::gpio::sealed::Pin as _;
|
||||||
use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
|
use crate::gpio::{self, AnyPin, Pin as GpioPin, PselBits};
|
||||||
use crate::interrupt::{self, Interrupt, InterruptExt};
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task};
|
use crate::ppi::{AnyConfigurableChannel, ConfigurableChannel, Event, Ppi, Task};
|
||||||
use crate::timer::{Frequency, Instance as TimerInstance, Timer};
|
use crate::timer::{Frequency, Instance as TimerInstance, Timer};
|
||||||
use crate::util::slice_in_ram_or;
|
use crate::util::slice_in_ram_or;
|
||||||
use crate::{pac, Peripheral};
|
use crate::{interrupt, pac, Peripheral};
|
||||||
|
|
||||||
/// UARTE config.
|
/// UARTE config.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -68,7 +68,7 @@ pub struct InterruptHandler<T: Instance> {
|
|||||||
_phantom: PhantomData<T>,
|
_phantom: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
let s = T::state();
|
let s = T::state();
|
||||||
@ -108,7 +108,7 @@ impl<'d, T: Instance> Uarte<'d, T> {
|
|||||||
/// Create a new UARTE without hardware flow control
|
/// Create a new UARTE without hardware flow control
|
||||||
pub fn new(
|
pub fn new(
|
||||||
uarte: impl Peripheral<P = T> + 'd,
|
uarte: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
@ -120,7 +120,7 @@ impl<'d, T: Instance> Uarte<'d, T> {
|
|||||||
/// Create a new UARTE with hardware flow control (RTS/CTS)
|
/// Create a new UARTE with hardware flow control (RTS/CTS)
|
||||||
pub fn new_with_rtscts(
|
pub fn new_with_rtscts(
|
||||||
uarte: impl Peripheral<P = T> + 'd,
|
uarte: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
cts: impl Peripheral<P = impl GpioPin> + 'd,
|
cts: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
@ -168,8 +168,8 @@ impl<'d, T: Instance> Uarte<'d, T> {
|
|||||||
}
|
}
|
||||||
r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) });
|
r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) });
|
||||||
|
|
||||||
unsafe { T::Interrupt::steal() }.unpend();
|
T::Interrupt::unpend();
|
||||||
unsafe { T::Interrupt::steal() }.enable();
|
unsafe { T::Interrupt::enable() };
|
||||||
|
|
||||||
let hardware_flow_control = match (rts.is_some(), cts.is_some()) {
|
let hardware_flow_control = match (rts.is_some(), cts.is_some()) {
|
||||||
(false, false) => false,
|
(false, false) => false,
|
||||||
@ -205,50 +205,7 @@ impl<'d, T: Instance> Uarte<'d, T> {
|
|||||||
ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
|
ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
|
||||||
ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
|
ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
|
||||||
) -> (UarteTx<'d, T>, UarteRxWithIdle<'d, T, U>) {
|
) -> (UarteTx<'d, T>, UarteRxWithIdle<'d, T, U>) {
|
||||||
let timer = Timer::new(timer);
|
(self.tx, self.rx.with_idle(timer, ppi_ch1, ppi_ch2))
|
||||||
|
|
||||||
into_ref!(ppi_ch1, ppi_ch2);
|
|
||||||
|
|
||||||
let r = T::regs();
|
|
||||||
|
|
||||||
// BAUDRATE register values are `baudrate * 2^32 / 16000000`
|
|
||||||
// source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values
|
|
||||||
//
|
|
||||||
// We want to stop RX if line is idle for 2 bytes worth of time
|
|
||||||
// That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit)
|
|
||||||
// This gives us the amount of 16M ticks for 20 bits.
|
|
||||||
let baudrate = r.baudrate.read().baudrate().variant().unwrap();
|
|
||||||
let timeout = 0x8000_0000 / (baudrate as u32 / 40);
|
|
||||||
|
|
||||||
timer.set_frequency(Frequency::F16MHz);
|
|
||||||
timer.cc(0).write(timeout);
|
|
||||||
timer.cc(0).short_compare_clear();
|
|
||||||
timer.cc(0).short_compare_stop();
|
|
||||||
|
|
||||||
let mut ppi_ch1 = Ppi::new_one_to_two(
|
|
||||||
ppi_ch1.map_into(),
|
|
||||||
Event::from_reg(&r.events_rxdrdy),
|
|
||||||
timer.task_clear(),
|
|
||||||
timer.task_start(),
|
|
||||||
);
|
|
||||||
ppi_ch1.enable();
|
|
||||||
|
|
||||||
let mut ppi_ch2 = Ppi::new_one_to_one(
|
|
||||||
ppi_ch2.map_into(),
|
|
||||||
timer.cc(0).event_compare(),
|
|
||||||
Task::from_reg(&r.tasks_stoprx),
|
|
||||||
);
|
|
||||||
ppi_ch2.enable();
|
|
||||||
|
|
||||||
(
|
|
||||||
self.tx,
|
|
||||||
UarteRxWithIdle {
|
|
||||||
rx: self.rx,
|
|
||||||
timer,
|
|
||||||
ppi_ch1: ppi_ch1,
|
|
||||||
_ppi_ch2: ppi_ch2,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the endtx event for use with PPI
|
/// Return the endtx event for use with PPI
|
||||||
@ -313,7 +270,7 @@ impl<'d, T: Instance> UarteTx<'d, T> {
|
|||||||
/// Create a new tx-only UARTE without hardware flow control
|
/// Create a new tx-only UARTE without hardware flow control
|
||||||
pub fn new(
|
pub fn new(
|
||||||
uarte: impl Peripheral<P = T> + 'd,
|
uarte: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@ -324,7 +281,7 @@ impl<'d, T: Instance> UarteTx<'d, T> {
|
|||||||
/// Create a new tx-only UARTE with hardware flow control (RTS/CTS)
|
/// Create a new tx-only UARTE with hardware flow control (RTS/CTS)
|
||||||
pub fn new_with_rtscts(
|
pub fn new_with_rtscts(
|
||||||
uarte: impl Peripheral<P = T> + 'd,
|
uarte: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
txd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
cts: impl Peripheral<P = impl GpioPin> + 'd,
|
cts: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
@ -358,8 +315,8 @@ impl<'d, T: Instance> UarteTx<'d, T> {
|
|||||||
let hardware_flow_control = cts.is_some();
|
let hardware_flow_control = cts.is_some();
|
||||||
configure(r, config, hardware_flow_control);
|
configure(r, config, hardware_flow_control);
|
||||||
|
|
||||||
unsafe { T::Interrupt::steal() }.unpend();
|
T::Interrupt::unpend();
|
||||||
unsafe { T::Interrupt::steal() }.enable();
|
unsafe { T::Interrupt::enable() };
|
||||||
|
|
||||||
let s = T::state();
|
let s = T::state();
|
||||||
s.tx_rx_refcount.store(1, Ordering::Relaxed);
|
s.tx_rx_refcount.store(1, Ordering::Relaxed);
|
||||||
@ -509,7 +466,7 @@ impl<'d, T: Instance> UarteRx<'d, T> {
|
|||||||
/// Create a new rx-only UARTE without hardware flow control
|
/// Create a new rx-only UARTE without hardware flow control
|
||||||
pub fn new(
|
pub fn new(
|
||||||
uarte: impl Peripheral<P = T> + 'd,
|
uarte: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@ -520,7 +477,7 @@ impl<'d, T: Instance> UarteRx<'d, T> {
|
|||||||
/// Create a new rx-only UARTE with hardware flow control (RTS/CTS)
|
/// Create a new rx-only UARTE with hardware flow control (RTS/CTS)
|
||||||
pub fn new_with_rtscts(
|
pub fn new_with_rtscts(
|
||||||
uarte: impl Peripheral<P = T> + 'd,
|
uarte: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
rxd: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
rts: impl Peripheral<P = impl GpioPin> + 'd,
|
rts: impl Peripheral<P = impl GpioPin> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
@ -551,8 +508,8 @@ impl<'d, T: Instance> UarteRx<'d, T> {
|
|||||||
r.psel.txd.write(|w| w.connect().disconnected());
|
r.psel.txd.write(|w| w.connect().disconnected());
|
||||||
r.psel.cts.write(|w| w.connect().disconnected());
|
r.psel.cts.write(|w| w.connect().disconnected());
|
||||||
|
|
||||||
unsafe { T::Interrupt::steal() }.unpend();
|
T::Interrupt::unpend();
|
||||||
unsafe { T::Interrupt::steal() }.enable();
|
unsafe { T::Interrupt::enable() };
|
||||||
|
|
||||||
let hardware_flow_control = rts.is_some();
|
let hardware_flow_control = rts.is_some();
|
||||||
configure(r, config, hardware_flow_control);
|
configure(r, config, hardware_flow_control);
|
||||||
@ -563,6 +520,56 @@ impl<'d, T: Instance> UarteRx<'d, T> {
|
|||||||
Self { _p: uarte }
|
Self { _p: uarte }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Upgrade to an instance that supports idle line detection.
|
||||||
|
pub fn with_idle<U: TimerInstance>(
|
||||||
|
self,
|
||||||
|
timer: impl Peripheral<P = U> + 'd,
|
||||||
|
ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
|
||||||
|
ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
|
||||||
|
) -> UarteRxWithIdle<'d, T, U> {
|
||||||
|
let timer = Timer::new(timer);
|
||||||
|
|
||||||
|
into_ref!(ppi_ch1, ppi_ch2);
|
||||||
|
|
||||||
|
let r = T::regs();
|
||||||
|
|
||||||
|
// BAUDRATE register values are `baudrate * 2^32 / 16000000`
|
||||||
|
// source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values
|
||||||
|
//
|
||||||
|
// We want to stop RX if line is idle for 2 bytes worth of time
|
||||||
|
// That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit)
|
||||||
|
// This gives us the amount of 16M ticks for 20 bits.
|
||||||
|
let baudrate = r.baudrate.read().baudrate().variant().unwrap();
|
||||||
|
let timeout = 0x8000_0000 / (baudrate as u32 / 40);
|
||||||
|
|
||||||
|
timer.set_frequency(Frequency::F16MHz);
|
||||||
|
timer.cc(0).write(timeout);
|
||||||
|
timer.cc(0).short_compare_clear();
|
||||||
|
timer.cc(0).short_compare_stop();
|
||||||
|
|
||||||
|
let mut ppi_ch1 = Ppi::new_one_to_two(
|
||||||
|
ppi_ch1.map_into(),
|
||||||
|
Event::from_reg(&r.events_rxdrdy),
|
||||||
|
timer.task_clear(),
|
||||||
|
timer.task_start(),
|
||||||
|
);
|
||||||
|
ppi_ch1.enable();
|
||||||
|
|
||||||
|
let mut ppi_ch2 = Ppi::new_one_to_one(
|
||||||
|
ppi_ch2.map_into(),
|
||||||
|
timer.cc(0).event_compare(),
|
||||||
|
Task::from_reg(&r.tasks_stoprx),
|
||||||
|
);
|
||||||
|
ppi_ch2.enable();
|
||||||
|
|
||||||
|
UarteRxWithIdle {
|
||||||
|
rx: self,
|
||||||
|
timer,
|
||||||
|
ppi_ch1: ppi_ch1,
|
||||||
|
_ppi_ch2: ppi_ch2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Read bytes until the buffer is filled.
|
/// Read bytes until the buffer is filled.
|
||||||
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
||||||
if buffer.len() == 0 {
|
if buffer.len() == 0 {
|
||||||
@ -889,7 +896,7 @@ pub(crate) mod sealed {
|
|||||||
/// UARTE peripheral instance.
|
/// UARTE peripheral instance.
|
||||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
|
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
|
||||||
/// Interrupt for this peripheral.
|
/// Interrupt for this peripheral.
|
||||||
type Interrupt: Interrupt;
|
type Interrupt: interrupt::typelevel::Interrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_uarte {
|
macro_rules! impl_uarte {
|
||||||
@ -908,7 +915,7 @@ macro_rules! impl_uarte {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl crate::uarte::Instance for peripherals::$type {
|
impl crate::uarte::Instance for peripherals::$type {
|
||||||
type Interrupt = crate::interrupt::$irq;
|
type Interrupt = crate::interrupt::typelevel::$irq;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -18,9 +18,9 @@ use embassy_usb_driver::{Direction, EndpointAddress, EndpointError, EndpointInfo
|
|||||||
use pac::usbd::RegisterBlock;
|
use pac::usbd::RegisterBlock;
|
||||||
|
|
||||||
use self::vbus_detect::VbusDetect;
|
use self::vbus_detect::VbusDetect;
|
||||||
use crate::interrupt::{self, Interrupt, InterruptExt};
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
use crate::util::slice_in_ram;
|
use crate::util::slice_in_ram;
|
||||||
use crate::{pac, Peripheral};
|
use crate::{interrupt, pac, Peripheral};
|
||||||
|
|
||||||
const NEW_AW: AtomicWaker = AtomicWaker::new();
|
const NEW_AW: AtomicWaker = AtomicWaker::new();
|
||||||
static BUS_WAKER: AtomicWaker = NEW_AW;
|
static BUS_WAKER: AtomicWaker = NEW_AW;
|
||||||
@ -34,7 +34,7 @@ pub struct InterruptHandler<T: Instance> {
|
|||||||
_phantom: PhantomData<T>,
|
_phantom: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
|
|
||||||
@ -98,13 +98,13 @@ impl<'d, T: Instance, V: VbusDetect> Driver<'d, T, V> {
|
|||||||
/// Create a new USB driver.
|
/// Create a new USB driver.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
usb: impl Peripheral<P = T> + 'd,
|
usb: impl Peripheral<P = T> + 'd,
|
||||||
_irq: impl interrupt::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
vbus_detect: V,
|
vbus_detect: V,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(usb);
|
into_ref!(usb);
|
||||||
|
|
||||||
unsafe { T::Interrupt::steal() }.unpend();
|
T::Interrupt::unpend();
|
||||||
unsafe { T::Interrupt::steal() }.enable();
|
unsafe { T::Interrupt::enable() };
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
_p: usb,
|
_p: usb,
|
||||||
@ -804,7 +804,7 @@ pub(crate) mod sealed {
|
|||||||
/// USB peripheral instance.
|
/// USB peripheral instance.
|
||||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
|
pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
|
||||||
/// Interrupt for this peripheral.
|
/// Interrupt for this peripheral.
|
||||||
type Interrupt: Interrupt;
|
type Interrupt: interrupt::typelevel::Interrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_usb {
|
macro_rules! impl_usb {
|
||||||
@ -815,7 +815,7 @@ macro_rules! impl_usb {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl crate::usb::Instance for peripherals::$type {
|
impl crate::usb::Instance for peripherals::$type {
|
||||||
type Interrupt = crate::interrupt::$irq;
|
type Interrupt = crate::interrupt::typelevel::$irq;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,8 @@ use core::task::Poll;
|
|||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
|
|
||||||
use super::BUS_WAKER;
|
use super::BUS_WAKER;
|
||||||
use crate::interrupt::{self, Interrupt, InterruptExt};
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
use crate::pac;
|
use crate::{interrupt, pac};
|
||||||
|
|
||||||
/// Trait for detecting USB VBUS power.
|
/// Trait for detecting USB VBUS power.
|
||||||
///
|
///
|
||||||
@ -29,9 +29,9 @@ pub trait VbusDetect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "_nrf5340"))]
|
#[cfg(not(feature = "_nrf5340"))]
|
||||||
type UsbRegIrq = interrupt::POWER_CLOCK;
|
type UsbRegIrq = interrupt::typelevel::POWER_CLOCK;
|
||||||
#[cfg(feature = "_nrf5340")]
|
#[cfg(feature = "_nrf5340")]
|
||||||
type UsbRegIrq = interrupt::USBREGULATOR;
|
type UsbRegIrq = interrupt::typelevel::USBREGULATOR;
|
||||||
|
|
||||||
#[cfg(not(feature = "_nrf5340"))]
|
#[cfg(not(feature = "_nrf5340"))]
|
||||||
type UsbRegPeri = pac::POWER;
|
type UsbRegPeri = pac::POWER;
|
||||||
@ -43,7 +43,7 @@ pub struct InterruptHandler {
|
|||||||
_private: (),
|
_private: (),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl interrupt::Handler<UsbRegIrq> for InterruptHandler {
|
impl interrupt::typelevel::Handler<UsbRegIrq> for InterruptHandler {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
let regs = unsafe { &*UsbRegPeri::ptr() };
|
let regs = unsafe { &*UsbRegPeri::ptr() };
|
||||||
|
|
||||||
@ -77,11 +77,11 @@ static POWER_WAKER: AtomicWaker = AtomicWaker::new();
|
|||||||
|
|
||||||
impl HardwareVbusDetect {
|
impl HardwareVbusDetect {
|
||||||
/// Create a new `VbusDetectNative`.
|
/// Create a new `VbusDetectNative`.
|
||||||
pub fn new(_irq: impl interrupt::Binding<UsbRegIrq, InterruptHandler> + 'static) -> Self {
|
pub fn new(_irq: impl interrupt::typelevel::Binding<UsbRegIrq, InterruptHandler> + 'static) -> Self {
|
||||||
let regs = unsafe { &*UsbRegPeri::ptr() };
|
let regs = unsafe { &*UsbRegPeri::ptr() };
|
||||||
|
|
||||||
unsafe { UsbRegIrq::steal() }.unpend();
|
UsbRegIrq::unpend();
|
||||||
unsafe { UsbRegIrq::steal() }.enable();
|
unsafe { UsbRegIrq::enable() };
|
||||||
|
|
||||||
regs.intenset
|
regs.intenset
|
||||||
.write(|w| w.usbdetected().set().usbremoved().set().usbpwrrdy().set());
|
.write(|w| w.usbdetected().set().usbremoved().set().usbpwrrdy().set());
|
||||||
|
@ -13,7 +13,8 @@ flavors = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = [ "rp-pac/rt" ]
|
default = [ "rt" ]
|
||||||
|
rt = [ "rp-pac/rt" ]
|
||||||
|
|
||||||
defmt = ["dep:defmt", "embassy-usb-driver?/defmt", "embassy-hal-common/defmt"]
|
defmt = ["dep:defmt", "embassy-usb-driver?/defmt", "embassy-hal-common/defmt"]
|
||||||
|
|
||||||
@ -41,8 +42,13 @@ boot2-ram-memcpy = []
|
|||||||
boot2-w25q080 = []
|
boot2-w25q080 = []
|
||||||
boot2-w25x10cl = []
|
boot2-w25x10cl = []
|
||||||
|
|
||||||
|
# Indicate code is running from RAM.
|
||||||
|
# Set this if all code is in RAM, and the cores never access memory-mapped flash memory through XIP.
|
||||||
|
# This allows the flash driver to not force pausing execution on both cores when doing flash operations.
|
||||||
|
run-from-ram = []
|
||||||
|
|
||||||
# Enable nightly-only features
|
# Enable nightly-only features
|
||||||
nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb-driver", "dep:embedded-io"]
|
nightly = ["embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb-driver", "dep:embedded-io"]
|
||||||
|
|
||||||
# Implement embedded-hal 1.0 alpha traits.
|
# Implement embedded-hal 1.0 alpha traits.
|
||||||
# Implement embedded-hal-async traits if `nightly` is set as well.
|
# Implement embedded-hal-async traits if `nightly` is set as well.
|
||||||
@ -50,11 +56,9 @@ unstable-traits = ["embedded-hal-1", "embedded-hal-nb"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
|
||||||
embassy-executor = { version = "0.2.0", path = "../embassy-executor" }
|
|
||||||
embassy-time = { version = "0.1.0", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] }
|
embassy-time = { version = "0.1.0", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] }
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||||
embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-2"]}
|
embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common", features = ["cortex-m", "prio-bits-2"] }
|
||||||
embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
|
|
||||||
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||||
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true }
|
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true }
|
||||||
atomic-polyfill = "1.0.1"
|
atomic-polyfill = "1.0.1"
|
||||||
@ -72,7 +76,7 @@ embedded-storage = { version = "0.3" }
|
|||||||
rand_core = "0.6.4"
|
rand_core = "0.6.4"
|
||||||
fixed = "1.23.1"
|
fixed = "1.23.1"
|
||||||
|
|
||||||
rp-pac = { version = "4" }
|
rp-pac = { version = "5" }
|
||||||
|
|
||||||
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
|
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
|
||||||
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true}
|
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true}
|
||||||
@ -85,5 +89,5 @@ pio = {version= "0.2.1" }
|
|||||||
rp2040-boot2 = "0.3"
|
rp2040-boot2 = "0.3"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
embassy-executor = { version = "0.2.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] }
|
embassy-executor = { version = "0.2.0", path = "../embassy-executor", features = ["nightly", "arch-std", "executor-thread"] }
|
||||||
static_cell = "1.0"
|
static_cell = "1.1"
|
||||||
|
@ -3,14 +3,14 @@ use core::marker::PhantomData;
|
|||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use embassy_cortex_m::interrupt::{Binding, Interrupt};
|
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
use embedded_hal_02::adc::{Channel, OneShot};
|
use embedded_hal_02::adc::{Channel, OneShot};
|
||||||
|
|
||||||
use crate::gpio::Pin;
|
use crate::gpio::Pin;
|
||||||
use crate::interrupt::{self, InterruptExt, ADC_IRQ_FIFO};
|
use crate::interrupt::typelevel::Binding;
|
||||||
|
use crate::interrupt::InterruptExt;
|
||||||
use crate::peripherals::ADC;
|
use crate::peripherals::ADC;
|
||||||
use crate::{pac, peripherals, Peripheral};
|
use crate::{interrupt, pac, peripherals, Peripheral};
|
||||||
static WAKER: AtomicWaker = AtomicWaker::new();
|
static WAKER: AtomicWaker = AtomicWaker::new();
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
@ -47,10 +47,9 @@ impl<'d> Adc<'d> {
|
|||||||
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
_inner: impl Peripheral<P = ADC> + 'd,
|
_inner: impl Peripheral<P = ADC> + 'd,
|
||||||
_irq: impl Binding<ADC_IRQ_FIFO, InterruptHandler>,
|
_irq: impl Binding<interrupt::typelevel::ADC_IRQ_FIFO, InterruptHandler>,
|
||||||
_config: Config,
|
_config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
unsafe {
|
|
||||||
let reset = Self::reset();
|
let reset = Self::reset();
|
||||||
crate::reset::reset(reset);
|
crate::reset::reset(reset);
|
||||||
crate::reset::unreset_wait(reset);
|
crate::reset::unreset_wait(reset);
|
||||||
@ -59,20 +58,16 @@ impl<'d> Adc<'d> {
|
|||||||
r.cs().write(|w| w.set_en(true));
|
r.cs().write(|w| w.set_en(true));
|
||||||
// Wait for ADC ready
|
// Wait for ADC ready
|
||||||
while !r.cs().read().ready() {}
|
while !r.cs().read().ready() {}
|
||||||
}
|
|
||||||
|
|
||||||
// Setup IRQ
|
// Setup IRQ
|
||||||
unsafe {
|
interrupt::ADC_IRQ_FIFO.unpend();
|
||||||
ADC_IRQ_FIFO::steal().unpend();
|
unsafe { interrupt::ADC_IRQ_FIFO.enable() };
|
||||||
ADC_IRQ_FIFO::steal().enable();
|
|
||||||
};
|
|
||||||
|
|
||||||
Self { phantom: PhantomData }
|
Self { phantom: PhantomData }
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn wait_for_ready() {
|
async fn wait_for_ready() {
|
||||||
let r = Self::regs();
|
let r = Self::regs();
|
||||||
unsafe {
|
|
||||||
r.inte().write(|w| w.set_fifo(true));
|
r.inte().write(|w| w.set_fifo(true));
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
poll_fn(|cx| {
|
poll_fn(|cx| {
|
||||||
@ -84,11 +79,9 @@ impl<'d> Adc<'d> {
|
|||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn read<PIN: Channel<Adc<'d>, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 {
|
pub async fn read<PIN: Channel<Adc<'d>, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 {
|
||||||
let r = Self::regs();
|
let r = Self::regs();
|
||||||
unsafe {
|
|
||||||
// disable pull-down and pull-up resistors
|
// disable pull-down and pull-up resistors
|
||||||
// pull-down resistors are enabled by default
|
// pull-down resistors are enabled by default
|
||||||
pin.pad_ctrl().modify(|w| {
|
pin.pad_ctrl().modify(|w| {
|
||||||
@ -104,11 +97,9 @@ impl<'d> Adc<'d> {
|
|||||||
Self::wait_for_ready().await;
|
Self::wait_for_ready().await;
|
||||||
r.result().read().result().into()
|
r.result().read().result().into()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn read_temperature(&mut self) -> u16 {
|
pub async fn read_temperature(&mut self) -> u16 {
|
||||||
let r = Self::regs();
|
let r = Self::regs();
|
||||||
unsafe {
|
|
||||||
r.cs().modify(|w| w.set_ts_en(true));
|
r.cs().modify(|w| w.set_ts_en(true));
|
||||||
if !r.cs().read().ready() {
|
if !r.cs().read().ready() {
|
||||||
Self::wait_for_ready().await;
|
Self::wait_for_ready().await;
|
||||||
@ -120,11 +111,9 @@ impl<'d> Adc<'d> {
|
|||||||
Self::wait_for_ready().await;
|
Self::wait_for_ready().await;
|
||||||
r.result().read().result().into()
|
r.result().read().result().into()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn blocking_read<PIN: Channel<Adc<'d>, ID = u8>>(&mut self, _pin: &mut PIN) -> u16 {
|
pub fn blocking_read<PIN: Channel<Adc<'d>, ID = u8>>(&mut self, _pin: &mut PIN) -> u16 {
|
||||||
let r = Self::regs();
|
let r = Self::regs();
|
||||||
unsafe {
|
|
||||||
r.cs().modify(|w| {
|
r.cs().modify(|w| {
|
||||||
w.set_ainsel(PIN::channel());
|
w.set_ainsel(PIN::channel());
|
||||||
w.set_start_once(true)
|
w.set_start_once(true)
|
||||||
@ -132,11 +121,9 @@ impl<'d> Adc<'d> {
|
|||||||
while !r.cs().read().ready() {}
|
while !r.cs().read().ready() {}
|
||||||
r.result().read().result().into()
|
r.result().read().result().into()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn blocking_read_temperature(&mut self) -> u16 {
|
pub fn blocking_read_temperature(&mut self) -> u16 {
|
||||||
let r = Self::regs();
|
let r = Self::regs();
|
||||||
unsafe {
|
|
||||||
r.cs().modify(|w| w.set_ts_en(true));
|
r.cs().modify(|w| w.set_ts_en(true));
|
||||||
while !r.cs().read().ready() {}
|
while !r.cs().read().ready() {}
|
||||||
r.cs().modify(|w| {
|
r.cs().modify(|w| {
|
||||||
@ -146,7 +133,6 @@ impl<'d> Adc<'d> {
|
|||||||
while !r.cs().read().ready() {}
|
while !r.cs().read().ready() {}
|
||||||
r.result().read().result().into()
|
r.result().read().result().into()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_pin {
|
macro_rules! impl_pin {
|
||||||
@ -164,7 +150,7 @@ pub struct InterruptHandler {
|
|||||||
_empty: (),
|
_empty: (),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl interrupt::Handler<ADC_IRQ_FIFO> for InterruptHandler {
|
impl interrupt::typelevel::Handler<interrupt::typelevel::ADC_IRQ_FIFO> for InterruptHandler {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
let r = Adc::regs();
|
let r = Adc::regs();
|
||||||
r.inte().write(|w| w.set_fifo(false));
|
r.inte().write(|w| w.set_fifo(false));
|
||||||
|
@ -542,7 +542,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
|
|||||||
reset::unreset_wait(peris);
|
reset::unreset_wait(peris);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn configure_rosc(config: RoscConfig) -> u32 {
|
fn configure_rosc(config: RoscConfig) -> u32 {
|
||||||
let p = pac::ROSC;
|
let p = pac::ROSC;
|
||||||
|
|
||||||
p.freqa().write(|w| {
|
p.freqa().write(|w| {
|
||||||
@ -620,7 +620,7 @@ pub fn clk_rtc_freq() -> u16 {
|
|||||||
CLOCKS.rtc.load(Ordering::Relaxed)
|
CLOCKS.rtc.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn start_xosc(crystal_hz: u32) {
|
fn start_xosc(crystal_hz: u32) {
|
||||||
pac::XOSC
|
pac::XOSC
|
||||||
.ctrl()
|
.ctrl()
|
||||||
.write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ));
|
.write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ));
|
||||||
@ -635,7 +635,7 @@ unsafe fn start_xosc(crystal_hz: u32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 {
|
fn configure_pll(p: pac::pll::Pll, input_freq: u32, config: PllConfig) -> u32 {
|
||||||
let ref_freq = input_freq / config.refdiv as u32;
|
let ref_freq = input_freq / config.refdiv as u32;
|
||||||
assert!(config.fbdiv >= 16 && config.fbdiv <= 320);
|
assert!(config.fbdiv >= 16 && config.fbdiv <= 320);
|
||||||
assert!(config.post_div1 >= 1 && config.post_div1 <= 7);
|
assert!(config.post_div1 >= 1 && config.post_div1 <= 7);
|
||||||
@ -700,9 +700,7 @@ impl<'d, T: Pin> Gpin<'d, T> {
|
|||||||
pub fn new<P: GpinPin>(gpin: impl Peripheral<P = P> + 'd) -> Gpin<'d, P> {
|
pub fn new<P: GpinPin>(gpin: impl Peripheral<P = P> + 'd) -> Gpin<'d, P> {
|
||||||
into_ref!(gpin);
|
into_ref!(gpin);
|
||||||
|
|
||||||
unsafe {
|
|
||||||
gpin.io().ctrl().write(|w| w.set_funcsel(0x08));
|
gpin.io().ctrl().write(|w| w.set_funcsel(0x08));
|
||||||
}
|
|
||||||
|
|
||||||
Gpin {
|
Gpin {
|
||||||
gpin: gpin.map_into(),
|
gpin: gpin.map_into(),
|
||||||
@ -717,13 +715,11 @@ impl<'d, T: Pin> Gpin<'d, T> {
|
|||||||
|
|
||||||
impl<'d, T: Pin> Drop for Gpin<'d, T> {
|
impl<'d, T: Pin> Drop for Gpin<'d, T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
|
||||||
self.gpin
|
self.gpin
|
||||||
.io()
|
.io()
|
||||||
.ctrl()
|
.ctrl()
|
||||||
.write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0));
|
.write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait GpoutPin: crate::gpio::Pin {
|
pub trait GpoutPin: crate::gpio::Pin {
|
||||||
@ -768,53 +764,43 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
|
|||||||
pub fn new(gpout: impl Peripheral<P = T> + 'd) -> Self {
|
pub fn new(gpout: impl Peripheral<P = T> + 'd) -> Self {
|
||||||
into_ref!(gpout);
|
into_ref!(gpout);
|
||||||
|
|
||||||
unsafe {
|
|
||||||
gpout.io().ctrl().write(|w| w.set_funcsel(0x08));
|
gpout.io().ctrl().write(|w| w.set_funcsel(0x08));
|
||||||
}
|
|
||||||
|
|
||||||
Self { gpout }
|
Self { gpout }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_div(&self, int: u32, frac: u8) {
|
pub fn set_div(&self, int: u32, frac: u8) {
|
||||||
unsafe {
|
|
||||||
let c = pac::CLOCKS;
|
let c = pac::CLOCKS;
|
||||||
c.clk_gpout_div(self.gpout.number()).write(|w| {
|
c.clk_gpout_div(self.gpout.number()).write(|w| {
|
||||||
w.set_int(int);
|
w.set_int(int);
|
||||||
w.set_frac(frac);
|
w.set_frac(frac);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_src(&self, src: GpoutSrc) {
|
pub fn set_src(&self, src: GpoutSrc) {
|
||||||
unsafe {
|
|
||||||
let c = pac::CLOCKS;
|
let c = pac::CLOCKS;
|
||||||
c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
|
c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
|
||||||
w.set_auxsrc(ClkGpoutCtrlAuxsrc(src as _));
|
w.set_auxsrc(ClkGpoutCtrlAuxsrc(src as _));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn enable(&self) {
|
pub fn enable(&self) {
|
||||||
unsafe {
|
|
||||||
let c = pac::CLOCKS;
|
let c = pac::CLOCKS;
|
||||||
c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
|
c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
|
||||||
w.set_enable(true);
|
w.set_enable(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn disable(&self) {
|
pub fn disable(&self) {
|
||||||
unsafe {
|
|
||||||
let c = pac::CLOCKS;
|
let c = pac::CLOCKS;
|
||||||
c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
|
c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
|
||||||
w.set_enable(false);
|
w.set_enable(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_freq(&self) -> u32 {
|
pub fn get_freq(&self) -> u32 {
|
||||||
let c = pac::CLOCKS;
|
let c = pac::CLOCKS;
|
||||||
let src = unsafe { c.clk_gpout_ctrl(self.gpout.number()).read().auxsrc() };
|
let src = c.clk_gpout_ctrl(self.gpout.number()).read().auxsrc();
|
||||||
|
|
||||||
let base = match src {
|
let base = match src {
|
||||||
ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(),
|
ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS => pll_sys_freq(),
|
||||||
@ -831,7 +817,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let div = unsafe { c.clk_gpout_div(self.gpout.number()).read() };
|
let div = c.clk_gpout_div(self.gpout.number()).read();
|
||||||
let int = if div.int() == 0 { 65536 } else { div.int() } as u64;
|
let int = if div.int() == 0 { 65536 } else { div.int() } as u64;
|
||||||
let frac = div.frac() as u64;
|
let frac = div.frac() as u64;
|
||||||
|
|
||||||
@ -842,13 +828,11 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
|
|||||||
impl<'d, T: GpoutPin> Drop for Gpout<'d, T> {
|
impl<'d, T: GpoutPin> Drop for Gpout<'d, T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.disable();
|
self.disable();
|
||||||
unsafe {
|
|
||||||
self.gpout
|
self.gpout
|
||||||
.io()
|
.io()
|
||||||
.ctrl()
|
.ctrl()
|
||||||
.write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0));
|
.write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Random number generator based on the ROSC RANDOMBIT register.
|
/// Random number generator based on the ROSC RANDOMBIT register.
|
||||||
@ -864,7 +848,7 @@ impl RoscRng {
|
|||||||
let mut acc = 0;
|
let mut acc = 0;
|
||||||
for _ in 0..u8::BITS {
|
for _ in 0..u8::BITS {
|
||||||
acc <<= 1;
|
acc <<= 1;
|
||||||
acc |= unsafe { random_reg.read().randombit() as u8 };
|
acc |= random_reg.read().randombit() as u8;
|
||||||
}
|
}
|
||||||
acc
|
acc
|
||||||
}
|
}
|
||||||
|
@ -103,8 +103,6 @@ where
|
|||||||
/// Try to claim the spinlock. Will return `Some(Self)` if the lock is obtained, and `None` if the lock is
|
/// Try to claim the spinlock. Will return `Some(Self)` if the lock is obtained, and `None` if the lock is
|
||||||
/// already in use somewhere else.
|
/// already in use somewhere else.
|
||||||
pub fn try_claim() -> Option<Self> {
|
pub fn try_claim() -> Option<Self> {
|
||||||
// Safety: We're only reading from this register
|
|
||||||
unsafe {
|
|
||||||
let lock = pac::SIO.spinlock(N).read();
|
let lock = pac::SIO.spinlock(N).read();
|
||||||
if lock > 0 {
|
if lock > 0 {
|
||||||
Some(Self(core::marker::PhantomData))
|
Some(Self(core::marker::PhantomData))
|
||||||
@ -112,7 +110,6 @@ where
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Clear a locked spin-lock.
|
/// Clear a locked spin-lock.
|
||||||
///
|
///
|
||||||
@ -120,11 +117,9 @@ where
|
|||||||
///
|
///
|
||||||
/// Only call this function if you hold the spin-lock.
|
/// Only call this function if you hold the spin-lock.
|
||||||
pub unsafe fn release() {
|
pub unsafe fn release() {
|
||||||
unsafe {
|
|
||||||
// Write (any value): release the lock
|
// Write (any value): release the lock
|
||||||
pac::SIO.spinlock(N).write_value(1);
|
pac::SIO.spinlock(N).write_value(1);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const N: usize> Drop for Spinlock<N>
|
impl<const N: usize> Drop for Spinlock<N>
|
||||||
|
@ -4,16 +4,17 @@ use core::pin::Pin;
|
|||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
use core::task::{Context, Poll};
|
use core::task::{Context, Poll};
|
||||||
|
|
||||||
use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
|
|
||||||
use embassy_hal_common::{impl_peripheral, into_ref, Peripheral, PeripheralRef};
|
use embassy_hal_common::{impl_peripheral, into_ref, Peripheral, PeripheralRef};
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
use pac::dma::vals::DataSize;
|
use pac::dma::vals::DataSize;
|
||||||
|
|
||||||
|
use crate::interrupt::InterruptExt;
|
||||||
use crate::pac::dma::vals;
|
use crate::pac::dma::vals;
|
||||||
use crate::{interrupt, pac, peripherals};
|
use crate::{interrupt, pac, peripherals};
|
||||||
|
|
||||||
|
#[cfg(feature = "rt")]
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
unsafe fn DMA_IRQ_0() {
|
fn DMA_IRQ_0() {
|
||||||
let ints0 = pac::DMA.ints0().read().ints0();
|
let ints0 = pac::DMA.ints0().read().ints0();
|
||||||
for channel in 0..CHANNEL_COUNT {
|
for channel in 0..CHANNEL_COUNT {
|
||||||
let ctrl_trig = pac::DMA.ch(channel).ctrl_trig().read();
|
let ctrl_trig = pac::DMA.ch(channel).ctrl_trig().read();
|
||||||
@ -29,13 +30,12 @@ unsafe fn DMA_IRQ_0() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn init() {
|
pub(crate) unsafe fn init() {
|
||||||
let irq = interrupt::DMA_IRQ_0::steal();
|
interrupt::DMA_IRQ_0.disable();
|
||||||
irq.disable();
|
interrupt::DMA_IRQ_0.set_priority(interrupt::Priority::P3);
|
||||||
irq.set_priority(interrupt::Priority::P3);
|
|
||||||
|
|
||||||
pac::DMA.inte0().write(|w| w.set_inte0(0xFFFF));
|
pac::DMA.inte0().write(|w| w.set_inte0(0xFFFF));
|
||||||
|
|
||||||
irq.enable();
|
interrupt::DMA_IRQ_0.enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn read<'a, C: Channel, W: Word>(
|
pub unsafe fn read<'a, C: Channel, W: Word>(
|
||||||
@ -76,16 +76,17 @@ pub unsafe fn write<'a, C: Channel, W: Word>(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static DUMMY: u32 = 0;
|
||||||
|
|
||||||
pub unsafe fn write_repeated<'a, C: Channel, W: Word>(
|
pub unsafe fn write_repeated<'a, C: Channel, W: Word>(
|
||||||
ch: impl Peripheral<P = C> + 'a,
|
ch: impl Peripheral<P = C> + 'a,
|
||||||
to: *mut W,
|
to: *mut W,
|
||||||
len: usize,
|
len: usize,
|
||||||
dreq: u8,
|
dreq: u8,
|
||||||
) -> Transfer<'a, C> {
|
) -> Transfer<'a, C> {
|
||||||
let dummy: u32 = 0;
|
|
||||||
copy_inner(
|
copy_inner(
|
||||||
ch,
|
ch,
|
||||||
&dummy as *const u32,
|
&DUMMY as *const u32,
|
||||||
to as *mut u32,
|
to as *mut u32,
|
||||||
len,
|
len,
|
||||||
W::size(),
|
W::size(),
|
||||||
@ -127,7 +128,6 @@ fn copy_inner<'a, C: Channel>(
|
|||||||
) -> Transfer<'a, C> {
|
) -> Transfer<'a, C> {
|
||||||
into_ref!(ch);
|
into_ref!(ch);
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let p = ch.regs();
|
let p = ch.regs();
|
||||||
|
|
||||||
p.read_addr().write_value(from as u32);
|
p.read_addr().write_value(from as u32);
|
||||||
@ -148,7 +148,6 @@ fn copy_inner<'a, C: Channel>(
|
|||||||
});
|
});
|
||||||
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
}
|
|
||||||
Transfer::new(ch)
|
Transfer::new(ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,13 +167,11 @@ impl<'a, C: Channel> Transfer<'a, C> {
|
|||||||
impl<'a, C: Channel> Drop for Transfer<'a, C> {
|
impl<'a, C: Channel> Drop for Transfer<'a, C> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let p = self.channel.regs();
|
let p = self.channel.regs();
|
||||||
unsafe {
|
|
||||||
pac::DMA
|
pac::DMA
|
||||||
.chan_abort()
|
.chan_abort()
|
||||||
.modify(|m| m.set_chan_abort(1 << self.channel.number()));
|
.modify(|m| m.set_chan_abort(1 << self.channel.number()));
|
||||||
while p.ctrl_trig().read().busy() {}
|
while p.ctrl_trig().read().busy() {}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, C: Channel> Unpin for Transfer<'a, C> {}
|
impl<'a, C: Channel> Unpin for Transfer<'a, C> {}
|
||||||
@ -185,7 +182,7 @@ impl<'a, C: Channel> Future for Transfer<'a, C> {
|
|||||||
// calls to wake will deregister the waker.
|
// calls to wake will deregister the waker.
|
||||||
CHANNEL_WAKERS[self.channel.number() as usize].register(cx.waker());
|
CHANNEL_WAKERS[self.channel.number() as usize].register(cx.waker());
|
||||||
|
|
||||||
if unsafe { self.channel.regs().ctrl_trig().read().busy() } {
|
if self.channel.regs().ctrl_trig().read().busy() {
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
} else {
|
} else {
|
||||||
Poll::Ready(())
|
Poll::Ready(())
|
||||||
|
@ -9,7 +9,11 @@ use embedded_storage::nor_flash::{
|
|||||||
use crate::pac;
|
use crate::pac;
|
||||||
use crate::peripherals::FLASH;
|
use crate::peripherals::FLASH;
|
||||||
|
|
||||||
pub const FLASH_BASE: usize = 0x10000000;
|
pub const FLASH_BASE: *const u32 = 0x10000000 as _;
|
||||||
|
|
||||||
|
// If running from RAM, we might have no boot2. Use bootrom `flash_enter_cmd_xip` instead.
|
||||||
|
// TODO: when run-from-ram is set, completely skip the "pause cores and jumpp to RAM" dance.
|
||||||
|
pub const USE_BOOT2: bool = !cfg!(feature = "run-from-ram");
|
||||||
|
|
||||||
// **NOTE**:
|
// **NOTE**:
|
||||||
//
|
//
|
||||||
@ -63,8 +67,8 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
|
|||||||
pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
|
pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
|
||||||
trace!(
|
trace!(
|
||||||
"Reading from 0x{:x} to 0x{:x}",
|
"Reading from 0x{:x} to 0x{:x}",
|
||||||
FLASH_BASE + offset as usize,
|
FLASH_BASE as u32 + offset,
|
||||||
FLASH_BASE + offset as usize + bytes.len()
|
FLASH_BASE as u32 + offset + bytes.len() as u32
|
||||||
);
|
);
|
||||||
check_read(self, offset, bytes.len())?;
|
check_read(self, offset, bytes.len())?;
|
||||||
|
|
||||||
@ -89,7 +93,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
|
|||||||
|
|
||||||
let len = to - from;
|
let len = to - from;
|
||||||
|
|
||||||
unsafe { self.in_ram(|| ram_helpers::flash_range_erase(from, len, true))? };
|
unsafe { self.in_ram(|| ram_helpers::flash_range_erase(from, len))? };
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -114,7 +118,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
|
|||||||
|
|
||||||
let unaligned_offset = offset as usize - start;
|
let unaligned_offset = offset as usize - start;
|
||||||
|
|
||||||
unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf, true))? }
|
unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf))? }
|
||||||
}
|
}
|
||||||
|
|
||||||
let remaining_len = bytes.len() - start_padding;
|
let remaining_len = bytes.len() - start_padding;
|
||||||
@ -132,12 +136,12 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
|
|||||||
if bytes.as_ptr() as usize >= 0x2000_0000 {
|
if bytes.as_ptr() as usize >= 0x2000_0000 {
|
||||||
let aligned_data = &bytes[start_padding..end_padding];
|
let aligned_data = &bytes[start_padding..end_padding];
|
||||||
|
|
||||||
unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, aligned_data, true))? }
|
unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, aligned_data))? }
|
||||||
} else {
|
} else {
|
||||||
for chunk in bytes[start_padding..end_padding].chunks_exact(PAGE_SIZE) {
|
for chunk in bytes[start_padding..end_padding].chunks_exact(PAGE_SIZE) {
|
||||||
let mut ram_buf = [0xFF_u8; PAGE_SIZE];
|
let mut ram_buf = [0xFF_u8; PAGE_SIZE];
|
||||||
ram_buf.copy_from_slice(chunk);
|
ram_buf.copy_from_slice(chunk);
|
||||||
unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, &ram_buf, true))? }
|
unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, &ram_buf))? }
|
||||||
aligned_offset += PAGE_SIZE;
|
aligned_offset += PAGE_SIZE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,7 +156,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
|
|||||||
|
|
||||||
let unaligned_offset = end_offset - (PAGE_SIZE - rem_offset);
|
let unaligned_offset = end_offset - (PAGE_SIZE - rem_offset);
|
||||||
|
|
||||||
unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf, true))? }
|
unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf))? }
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -163,7 +167,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
|
|||||||
/// - DMA must not access flash memory
|
/// - DMA must not access flash memory
|
||||||
unsafe fn in_ram(&mut self, operation: impl FnOnce()) -> Result<(), Error> {
|
unsafe fn in_ram(&mut self, operation: impl FnOnce()) -> Result<(), Error> {
|
||||||
// Make sure we're running on CORE0
|
// Make sure we're running on CORE0
|
||||||
let core_id: u32 = unsafe { pac::SIO.cpuid().read() };
|
let core_id: u32 = pac::SIO.cpuid().read();
|
||||||
if core_id != 0 {
|
if core_id != 0 {
|
||||||
return Err(Error::InvalidCore);
|
return Err(Error::InvalidCore);
|
||||||
}
|
}
|
||||||
@ -190,7 +194,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
|
|||||||
|
|
||||||
/// Read SPI flash unique ID
|
/// Read SPI flash unique ID
|
||||||
pub fn unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> {
|
pub fn unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> {
|
||||||
unsafe { self.in_ram(|| ram_helpers::flash_unique_id(uid, true))? };
|
unsafe { self.in_ram(|| ram_helpers::flash_unique_id(uid))? };
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,7 +203,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
|
|||||||
let mut jedec = None;
|
let mut jedec = None;
|
||||||
unsafe {
|
unsafe {
|
||||||
self.in_ram(|| {
|
self.in_ram(|| {
|
||||||
jedec.replace(ram_helpers::flash_jedec_id(true));
|
jedec.replace(ram_helpers::flash_jedec_id());
|
||||||
})?;
|
})?;
|
||||||
};
|
};
|
||||||
Ok(jedec.unwrap())
|
Ok(jedec.unwrap())
|
||||||
@ -242,6 +246,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> NorFlash for Flash<'d, T, FLASH_S
|
|||||||
mod ram_helpers {
|
mod ram_helpers {
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
use crate::rom_data;
|
use crate::rom_data;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
@ -306,7 +311,7 @@ mod ram_helpers {
|
|||||||
///
|
///
|
||||||
/// `addr` and `len` must be multiples of 4096
|
/// `addr` and `len` must be multiples of 4096
|
||||||
///
|
///
|
||||||
/// If `use_boot2` is `true`, a copy of the 2nd stage boot loader
|
/// If `USE_BOOT2` is `true`, a copy of the 2nd stage boot loader
|
||||||
/// is used to re-initialize the XIP engine after flashing.
|
/// is used to re-initialize the XIP engine after flashing.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
@ -318,10 +323,10 @@ mod ram_helpers {
|
|||||||
/// - DMA must not access flash memory
|
/// - DMA must not access flash memory
|
||||||
///
|
///
|
||||||
/// `addr` and `len` parameters must be valid and are not checked.
|
/// `addr` and `len` parameters must be valid and are not checked.
|
||||||
pub unsafe fn flash_range_erase(addr: u32, len: u32, use_boot2: bool) {
|
pub unsafe fn flash_range_erase(addr: u32, len: u32) {
|
||||||
let mut boot2 = [0u32; 256 / 4];
|
let mut boot2 = [0u32; 256 / 4];
|
||||||
let ptrs = if use_boot2 {
|
let ptrs = if USE_BOOT2 {
|
||||||
rom_data::memcpy44(&mut boot2 as *mut _, super::FLASH_BASE as *const _, 256);
|
rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
|
||||||
flash_function_pointers_with_boot2(true, false, &boot2)
|
flash_function_pointers_with_boot2(true, false, &boot2)
|
||||||
} else {
|
} else {
|
||||||
flash_function_pointers(true, false)
|
flash_function_pointers(true, false)
|
||||||
@ -336,7 +341,7 @@ mod ram_helpers {
|
|||||||
///
|
///
|
||||||
/// `addr` and `data.len()` must be multiples of 4096
|
/// `addr` and `data.len()` must be multiples of 4096
|
||||||
///
|
///
|
||||||
/// If `use_boot2` is `true`, a copy of the 2nd stage boot loader
|
/// If `USE_BOOT2` is `true`, a copy of the 2nd stage boot loader
|
||||||
/// is used to re-initialize the XIP engine after flashing.
|
/// is used to re-initialize the XIP engine after flashing.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
@ -348,10 +353,10 @@ mod ram_helpers {
|
|||||||
/// - DMA must not access flash memory
|
/// - DMA must not access flash memory
|
||||||
///
|
///
|
||||||
/// `addr` and `len` parameters must be valid and are not checked.
|
/// `addr` and `len` parameters must be valid and are not checked.
|
||||||
pub unsafe fn flash_range_erase_and_program(addr: u32, data: &[u8], use_boot2: bool) {
|
pub unsafe fn flash_range_erase_and_program(addr: u32, data: &[u8]) {
|
||||||
let mut boot2 = [0u32; 256 / 4];
|
let mut boot2 = [0u32; 256 / 4];
|
||||||
let ptrs = if use_boot2 {
|
let ptrs = if USE_BOOT2 {
|
||||||
rom_data::memcpy44(&mut boot2 as *mut _, super::FLASH_BASE as *const _, 256);
|
rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
|
||||||
flash_function_pointers_with_boot2(true, true, &boot2)
|
flash_function_pointers_with_boot2(true, true, &boot2)
|
||||||
} else {
|
} else {
|
||||||
flash_function_pointers(true, true)
|
flash_function_pointers(true, true)
|
||||||
@ -371,7 +376,7 @@ mod ram_helpers {
|
|||||||
///
|
///
|
||||||
/// `addr` and `data.len()` must be multiples of 256
|
/// `addr` and `data.len()` must be multiples of 256
|
||||||
///
|
///
|
||||||
/// If `use_boot2` is `true`, a copy of the 2nd stage boot loader
|
/// If `USE_BOOT2` is `true`, a copy of the 2nd stage boot loader
|
||||||
/// is used to re-initialize the XIP engine after flashing.
|
/// is used to re-initialize the XIP engine after flashing.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
@ -383,10 +388,10 @@ mod ram_helpers {
|
|||||||
/// - DMA must not access flash memory
|
/// - DMA must not access flash memory
|
||||||
///
|
///
|
||||||
/// `addr` and `len` parameters must be valid and are not checked.
|
/// `addr` and `len` parameters must be valid and are not checked.
|
||||||
pub unsafe fn flash_range_program(addr: u32, data: &[u8], use_boot2: bool) {
|
pub unsafe fn flash_range_program(addr: u32, data: &[u8]) {
|
||||||
let mut boot2 = [0u32; 256 / 4];
|
let mut boot2 = [0u32; 256 / 4];
|
||||||
let ptrs = if use_boot2 {
|
let ptrs = if USE_BOOT2 {
|
||||||
rom_data::memcpy44(&mut boot2 as *mut _, super::FLASH_BASE as *const _, 256);
|
rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
|
||||||
flash_function_pointers_with_boot2(false, true, &boot2)
|
flash_function_pointers_with_boot2(false, true, &boot2)
|
||||||
} else {
|
} else {
|
||||||
flash_function_pointers(false, true)
|
flash_function_pointers(false, true)
|
||||||
@ -508,10 +513,10 @@ mod ram_helpers {
|
|||||||
/// - DMA must not access flash memory
|
/// - DMA must not access flash memory
|
||||||
///
|
///
|
||||||
/// Credit: taken from `rp2040-flash` (also licensed Apache+MIT)
|
/// Credit: taken from `rp2040-flash` (also licensed Apache+MIT)
|
||||||
pub unsafe fn flash_unique_id(out: &mut [u8], use_boot2: bool) {
|
pub unsafe fn flash_unique_id(out: &mut [u8]) {
|
||||||
let mut boot2 = [0u32; 256 / 4];
|
let mut boot2 = [0u32; 256 / 4];
|
||||||
let ptrs = if use_boot2 {
|
let ptrs = if USE_BOOT2 {
|
||||||
rom_data::memcpy44(&mut boot2 as *mut _, 0x10000000 as *const _, 256);
|
rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
|
||||||
flash_function_pointers_with_boot2(false, false, &boot2)
|
flash_function_pointers_with_boot2(false, false, &boot2)
|
||||||
} else {
|
} else {
|
||||||
flash_function_pointers(false, false)
|
flash_function_pointers(false, false)
|
||||||
@ -536,10 +541,10 @@ mod ram_helpers {
|
|||||||
/// - DMA must not access flash memory
|
/// - DMA must not access flash memory
|
||||||
///
|
///
|
||||||
/// Credit: taken from `rp2040-flash` (also licensed Apache+MIT)
|
/// Credit: taken from `rp2040-flash` (also licensed Apache+MIT)
|
||||||
pub unsafe fn flash_jedec_id(use_boot2: bool) -> u32 {
|
pub unsafe fn flash_jedec_id() -> u32 {
|
||||||
let mut boot2 = [0u32; 256 / 4];
|
let mut boot2 = [0u32; 256 / 4];
|
||||||
let ptrs = if use_boot2 {
|
let ptrs = if USE_BOOT2 {
|
||||||
rom_data::memcpy44(&mut boot2 as *mut _, 0x10000000 as *const _, 256);
|
rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
|
||||||
flash_function_pointers_with_boot2(false, false, &boot2)
|
flash_function_pointers_with_boot2(false, false, &boot2)
|
||||||
} else {
|
} else {
|
||||||
flash_function_pointers(false, false)
|
flash_function_pointers(false, false)
|
||||||
@ -586,7 +591,6 @@ mod ram_helpers {
|
|||||||
"ldr r4, [r5, #4]",
|
"ldr r4, [r5, #4]",
|
||||||
"blx r4", // flash_exit_xip()
|
"blx r4", // flash_exit_xip()
|
||||||
|
|
||||||
"mov r7, r10", // cmd
|
|
||||||
|
|
||||||
"movs r4, #0x18",
|
"movs r4, #0x18",
|
||||||
"lsls r4, r4, #24", // 0x18000000, SSI, RP2040 datasheet 4.10.13
|
"lsls r4, r4, #24", // 0x18000000, SSI, RP2040 datasheet 4.10.13
|
||||||
@ -603,8 +607,9 @@ mod ram_helpers {
|
|||||||
"str r1, [r4, #0]",
|
"str r1, [r4, #0]",
|
||||||
|
|
||||||
// Write ctrlr1 with len-1
|
// Write ctrlr1 with len-1
|
||||||
"ldr r0, [r7, #8]", // dummy_len
|
"mov r3, r10", // cmd
|
||||||
"ldr r1, [r7, #16]", // data_len
|
"ldr r0, [r3, #8]", // dummy_len
|
||||||
|
"ldr r1, [r3, #16]", // data_len
|
||||||
"add r0, r1",
|
"add r0, r1",
|
||||||
"subs r0, #1",
|
"subs r0, #1",
|
||||||
"str r0, [r4, #0x04]", // CTRLR1
|
"str r0, [r4, #0x04]", // CTRLR1
|
||||||
@ -616,8 +621,8 @@ mod ram_helpers {
|
|||||||
// Write cmd/addr phase to DR
|
// Write cmd/addr phase to DR
|
||||||
"mov r2, r4",
|
"mov r2, r4",
|
||||||
"adds r2, 0x60", // &DR
|
"adds r2, 0x60", // &DR
|
||||||
"ldr r0, [r7, #0]", // cmd_addr
|
"ldr r0, [r3, #0]", // cmd_addr
|
||||||
"ldr r1, [r7, #4]", // cmd_addr_len
|
"ldr r1, [r3, #4]", // cmd_addr_len
|
||||||
"10:",
|
"10:",
|
||||||
"ldrb r3, [r0]",
|
"ldrb r3, [r0]",
|
||||||
"strb r3, [r2]", // DR
|
"strb r3, [r2]", // DR
|
||||||
@ -626,7 +631,8 @@ mod ram_helpers {
|
|||||||
"bne 10b",
|
"bne 10b",
|
||||||
|
|
||||||
// Skip any dummy cycles
|
// Skip any dummy cycles
|
||||||
"ldr r1, [r7, #8]", // dummy_len
|
"mov r3, r10", // cmd
|
||||||
|
"ldr r1, [r3, #8]", // dummy_len
|
||||||
"cmp r1, #0",
|
"cmp r1, #0",
|
||||||
"beq 9f",
|
"beq 9f",
|
||||||
"4:",
|
"4:",
|
||||||
@ -643,8 +649,9 @@ mod ram_helpers {
|
|||||||
|
|
||||||
// Read RX fifo
|
// Read RX fifo
|
||||||
"9:",
|
"9:",
|
||||||
"ldr r0, [r7, #12]", // data
|
"mov r2, r10", // cmd
|
||||||
"ldr r1, [r7, #16]", // data_len
|
"ldr r0, [r2, #12]", // data
|
||||||
|
"ldr r1, [r2, #16]", // data_len
|
||||||
|
|
||||||
"2:",
|
"2:",
|
||||||
"ldr r3, [r4, #0x28]", // SR
|
"ldr r3, [r4, #0x28]", // SR
|
||||||
@ -678,13 +685,12 @@ mod ram_helpers {
|
|||||||
out("r2") _,
|
out("r2") _,
|
||||||
out("r3") _,
|
out("r3") _,
|
||||||
out("r4") _,
|
out("r4") _,
|
||||||
|
out("r5") _,
|
||||||
// Registers r8-r10 are used to store values
|
// Registers r8-r10 are used to store values
|
||||||
// from r0-r2 in registers not clobbered by
|
// from r0-r2 in registers not clobbered by
|
||||||
// function calls.
|
// function calls.
|
||||||
// The values can't be passed in using r8-r10 directly
|
// The values can't be passed in using r8-r10 directly
|
||||||
// due to https://github.com/rust-lang/rust/issues/99071
|
// due to https://github.com/rust-lang/rust/issues/99071
|
||||||
out("r8") _,
|
|
||||||
out("r9") _,
|
|
||||||
out("r10") _,
|
out("r10") _,
|
||||||
clobber_abi("C"),
|
clobber_abi("C"),
|
||||||
);
|
);
|
||||||
|
@ -17,7 +17,6 @@ where
|
|||||||
{
|
{
|
||||||
let sio = rp_pac::SIO;
|
let sio = rp_pac::SIO;
|
||||||
|
|
||||||
unsafe {
|
|
||||||
// Since we can't save the signed-ness of the calculation, we have to make
|
// Since we can't save the signed-ness of the calculation, we have to make
|
||||||
// sure that there's at least an 8 cycle delay before we read the result.
|
// sure that there's at least an 8 cycle delay before we read the result.
|
||||||
// The Pico SDK ensures this by using a 6 cycle push and two 1 cycle reads.
|
// The Pico SDK ensures this by using a 6 cycle push and two 1 cycle reads.
|
||||||
@ -55,7 +54,6 @@ where
|
|||||||
sio.div().quotient().write_value(quotient);
|
sio.div().quotient().write_value(quotient);
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save_divider<F, R>(f: F) -> R
|
fn save_divider<F, R>(f: F) -> R
|
||||||
@ -63,7 +61,7 @@ where
|
|||||||
F: FnOnce() -> R,
|
F: FnOnce() -> R,
|
||||||
{
|
{
|
||||||
let sio = rp_pac::SIO;
|
let sio = rp_pac::SIO;
|
||||||
if unsafe { !sio.div().csr().read().dirty() } {
|
if !sio.div().csr().read().dirty() {
|
||||||
// Not dirty, so nothing is waiting for the calculation. So we can just
|
// Not dirty, so nothing is waiting for the calculation. So we can just
|
||||||
// issue it directly without a save/restore.
|
// issue it directly without a save/restore.
|
||||||
f()
|
f()
|
||||||
|
@ -3,10 +3,10 @@ use core::future::Future;
|
|||||||
use core::pin::Pin as FuturePin;
|
use core::pin::Pin as FuturePin;
|
||||||
use core::task::{Context, Poll};
|
use core::task::{Context, Poll};
|
||||||
|
|
||||||
use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
|
|
||||||
use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
|
use embassy_hal_common::{impl_peripheral, into_ref, PeripheralRef};
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
|
|
||||||
|
use crate::interrupt::InterruptExt;
|
||||||
use crate::pac::common::{Reg, RW};
|
use crate::pac::common::{Reg, RW};
|
||||||
use crate::pac::SIO;
|
use crate::pac::SIO;
|
||||||
use crate::{interrupt, pac, peripherals, Peripheral, RegExt};
|
use crate::{interrupt, pac, peripherals, Peripheral, RegExt};
|
||||||
@ -31,9 +31,9 @@ impl From<bool> for Level {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<bool> for Level {
|
impl From<Level> for bool {
|
||||||
fn into(self) -> bool {
|
fn from(level: Level) -> bool {
|
||||||
match self {
|
match level {
|
||||||
Level::Low => false,
|
Level::Low => false,
|
||||||
Level::High => true,
|
Level::High => true,
|
||||||
}
|
}
|
||||||
@ -137,14 +137,14 @@ pub enum InterruptTrigger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn init() {
|
pub(crate) unsafe fn init() {
|
||||||
let irq = interrupt::IO_IRQ_BANK0::steal();
|
interrupt::IO_IRQ_BANK0.disable();
|
||||||
irq.disable();
|
interrupt::IO_IRQ_BANK0.set_priority(interrupt::Priority::P3);
|
||||||
irq.set_priority(interrupt::Priority::P3);
|
interrupt::IO_IRQ_BANK0.enable();
|
||||||
irq.enable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rt")]
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
unsafe fn IO_IRQ_BANK0() {
|
fn IO_IRQ_BANK0() {
|
||||||
let cpu = SIO.cpuid().read() as usize;
|
let cpu = SIO.cpuid().read() as usize;
|
||||||
// There are two sets of interrupt registers, one for cpu0 and one for cpu1
|
// There are two sets of interrupt registers, one for cpu0 and one for cpu1
|
||||||
// and here we are selecting the set that belongs to the currently executing
|
// and here we are selecting the set that belongs to the currently executing
|
||||||
@ -185,7 +185,6 @@ struct InputFuture<'a, T: Pin> {
|
|||||||
impl<'d, T: Pin> InputFuture<'d, T> {
|
impl<'d, T: Pin> InputFuture<'d, T> {
|
||||||
pub fn new(pin: impl Peripheral<P = T> + 'd, level: InterruptTrigger) -> Self {
|
pub fn new(pin: impl Peripheral<P = T> + 'd, level: InterruptTrigger) -> Self {
|
||||||
into_ref!(pin);
|
into_ref!(pin);
|
||||||
unsafe {
|
|
||||||
let pin_group = (pin.pin() % 8) as usize;
|
let pin_group = (pin.pin() % 8) as usize;
|
||||||
// first, clear the INTR register bits. without this INTR will still
|
// first, clear the INTR register bits. without this INTR will still
|
||||||
// contain reports of previous edges, causing the IRQ to fire early
|
// contain reports of previous edges, causing the IRQ to fire early
|
||||||
@ -224,7 +223,6 @@ impl<'d, T: Pin> InputFuture<'d, T> {
|
|||||||
w.set_edge_low(pin_group, true);
|
w.set_edge_low(pin_group, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Self { pin, level }
|
Self { pin, level }
|
||||||
}
|
}
|
||||||
@ -242,7 +240,7 @@ impl<'d, T: Pin> Future for InputFuture<'d, T> {
|
|||||||
// then we want to access the interrupt enable register for our
|
// then we want to access the interrupt enable register for our
|
||||||
// pin (there are 4 of these PROC0_INTE0, PROC0_INTE1, PROC0_INTE2, and
|
// pin (there are 4 of these PROC0_INTE0, PROC0_INTE1, PROC0_INTE2, and
|
||||||
// PROC0_INTE3 per cpu).
|
// PROC0_INTE3 per cpu).
|
||||||
let inte: pac::io::regs::Int = unsafe { self.pin.int_proc().inte((self.pin.pin() / 8) as usize).read() };
|
let inte: pac::io::regs::Int = self.pin.int_proc().inte((self.pin.pin() / 8) as usize).read();
|
||||||
// The register is divided into groups of four, one group for
|
// The register is divided into groups of four, one group for
|
||||||
// each pin. Each group consists of four trigger levels LEVEL_LOW,
|
// each pin. Each group consists of four trigger levels LEVEL_LOW,
|
||||||
// LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin.
|
// LEVEL_HIGH, EDGE_LOW, and EDGE_HIGH for each pin.
|
||||||
@ -449,7 +447,6 @@ impl<'d, T: Pin> Flex<'d, T> {
|
|||||||
pub fn new(pin: impl Peripheral<P = T> + 'd) -> Self {
|
pub fn new(pin: impl Peripheral<P = T> + 'd) -> Self {
|
||||||
into_ref!(pin);
|
into_ref!(pin);
|
||||||
|
|
||||||
unsafe {
|
|
||||||
pin.pad_ctrl().write(|w| {
|
pin.pad_ctrl().write(|w| {
|
||||||
w.set_ie(true);
|
w.set_ie(true);
|
||||||
});
|
});
|
||||||
@ -457,7 +454,6 @@ impl<'d, T: Pin> Flex<'d, T> {
|
|||||||
pin.io().ctrl().write(|w| {
|
pin.io().ctrl().write(|w| {
|
||||||
w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0.0);
|
w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0.0);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Self { pin }
|
Self { pin }
|
||||||
}
|
}
|
||||||
@ -470,7 +466,6 @@ impl<'d, T: Pin> Flex<'d, T> {
|
|||||||
/// Set the pin's pull.
|
/// Set the pin's pull.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_pull(&mut self, pull: Pull) {
|
pub fn set_pull(&mut self, pull: Pull) {
|
||||||
unsafe {
|
|
||||||
self.pin.pad_ctrl().modify(|w| {
|
self.pin.pad_ctrl().modify(|w| {
|
||||||
w.set_ie(true);
|
w.set_ie(true);
|
||||||
let (pu, pd) = match pull {
|
let (pu, pd) = match pull {
|
||||||
@ -482,12 +477,10 @@ impl<'d, T: Pin> Flex<'d, T> {
|
|||||||
w.set_pde(pd);
|
w.set_pde(pd);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the pin's drive strength.
|
/// Set the pin's drive strength.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_drive_strength(&mut self, strength: Drive) {
|
pub fn set_drive_strength(&mut self, strength: Drive) {
|
||||||
unsafe {
|
|
||||||
self.pin.pad_ctrl().modify(|w| {
|
self.pin.pad_ctrl().modify(|w| {
|
||||||
w.set_drive(match strength {
|
w.set_drive(match strength {
|
||||||
Drive::_2mA => pac::pads::vals::Drive::_2MA,
|
Drive::_2mA => pac::pads::vals::Drive::_2MA,
|
||||||
@ -497,24 +490,21 @@ impl<'d, T: Pin> Flex<'d, T> {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Set the pin's slew rate.
|
// Set the pin's slew rate.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_slew_rate(&mut self, slew_rate: SlewRate) {
|
pub fn set_slew_rate(&mut self, slew_rate: SlewRate) {
|
||||||
unsafe {
|
|
||||||
self.pin.pad_ctrl().modify(|w| {
|
self.pin.pad_ctrl().modify(|w| {
|
||||||
w.set_slewfast(slew_rate == SlewRate::Fast);
|
w.set_slewfast(slew_rate == SlewRate::Fast);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Put the pin into input mode.
|
/// Put the pin into input mode.
|
||||||
///
|
///
|
||||||
/// The pull setting is left unchanged.
|
/// The pull setting is left unchanged.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_as_input(&mut self) {
|
pub fn set_as_input(&mut self) {
|
||||||
unsafe { self.pin.sio_oe().value_clr().write_value(self.bit()) }
|
self.pin.sio_oe().value_clr().write_value(self.bit())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Put the pin into output mode.
|
/// Put the pin into output mode.
|
||||||
@ -523,17 +513,17 @@ impl<'d, T: Pin> Flex<'d, T> {
|
|||||||
/// at a specific level, call `set_high`/`set_low` on the pin first.
|
/// at a specific level, call `set_high`/`set_low` on the pin first.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_as_output(&mut self) {
|
pub fn set_as_output(&mut self) {
|
||||||
unsafe { self.pin.sio_oe().value_set().write_value(self.bit()) }
|
self.pin.sio_oe().value_set().write_value(self.bit())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_set_as_output(&self) -> bool {
|
fn is_set_as_output(&self) -> bool {
|
||||||
unsafe { (self.pin.sio_oe().value().read() & self.bit()) != 0 }
|
(self.pin.sio_oe().value().read() & self.bit()) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn toggle_set_as_output(&mut self) {
|
pub fn toggle_set_as_output(&mut self) {
|
||||||
unsafe { self.pin.sio_oe().value_xor().write_value(self.bit()) }
|
self.pin.sio_oe().value_xor().write_value(self.bit())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -543,7 +533,7 @@ impl<'d, T: Pin> Flex<'d, T> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_low(&self) -> bool {
|
pub fn is_low(&self) -> bool {
|
||||||
unsafe { self.pin.sio_in().read() & self.bit() == 0 }
|
self.pin.sio_in().read() & self.bit() == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns current pin level
|
/// Returns current pin level
|
||||||
@ -555,13 +545,13 @@ impl<'d, T: Pin> Flex<'d, T> {
|
|||||||
/// Set the output as high.
|
/// Set the output as high.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_high(&mut self) {
|
pub fn set_high(&mut self) {
|
||||||
unsafe { self.pin.sio_out().value_set().write_value(self.bit()) }
|
self.pin.sio_out().value_set().write_value(self.bit())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the output as low.
|
/// Set the output as low.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_low(&mut self) {
|
pub fn set_low(&mut self) {
|
||||||
unsafe { self.pin.sio_out().value_clr().write_value(self.bit()) }
|
self.pin.sio_out().value_clr().write_value(self.bit())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the output level.
|
/// Set the output level.
|
||||||
@ -576,7 +566,7 @@ impl<'d, T: Pin> Flex<'d, T> {
|
|||||||
/// Is the output level high?
|
/// Is the output level high?
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_set_high(&self) -> bool {
|
pub fn is_set_high(&self) -> bool {
|
||||||
unsafe { (self.pin.sio_out().value().read() & self.bit()) == 0 }
|
(self.pin.sio_out().value().read() & self.bit()) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is the output level low?
|
/// Is the output level low?
|
||||||
@ -594,7 +584,7 @@ impl<'d, T: Pin> Flex<'d, T> {
|
|||||||
/// Toggle pin output
|
/// Toggle pin output
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn toggle(&mut self) {
|
pub fn toggle(&mut self) {
|
||||||
unsafe { self.pin.sio_out().value_xor().write_value(self.bit()) }
|
self.pin.sio_out().value_xor().write_value(self.bit())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -626,13 +616,11 @@ impl<'d, T: Pin> Flex<'d, T> {
|
|||||||
impl<'d, T: Pin> Drop for Flex<'d, T> {
|
impl<'d, T: Pin> Drop for Flex<'d, T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
|
||||||
self.pin.pad_ctrl().write(|_| {});
|
self.pin.pad_ctrl().write(|_| {});
|
||||||
self.pin.io().ctrl().write(|w| {
|
self.pin.io().ctrl().write(|w| {
|
||||||
w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0);
|
w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) mod sealed {
|
pub(crate) mod sealed {
|
||||||
@ -688,7 +676,7 @@ pub(crate) mod sealed {
|
|||||||
Bank::Bank0 => crate::pac::IO_BANK0,
|
Bank::Bank0 => crate::pac::IO_BANK0,
|
||||||
Bank::Qspi => crate::pac::IO_QSPI,
|
Bank::Qspi => crate::pac::IO_QSPI,
|
||||||
};
|
};
|
||||||
let proc = unsafe { SIO.cpuid().read() };
|
let proc = SIO.cpuid().read();
|
||||||
io_block.int_proc(proc as _)
|
io_block.int_proc(proc as _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,14 @@ use core::future;
|
|||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use embassy_cortex_m::interrupt::{self, Binding, Interrupt, InterruptExt};
|
|
||||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
use pac::i2c;
|
use pac::i2c;
|
||||||
|
|
||||||
use crate::gpio::sealed::Pin;
|
use crate::gpio::sealed::Pin;
|
||||||
use crate::gpio::AnyPin;
|
use crate::gpio::AnyPin;
|
||||||
use crate::{pac, peripherals, Peripheral};
|
use crate::interrupt::typelevel::{Binding, Interrupt};
|
||||||
|
use crate::{interrupt, pac, peripherals, Peripheral};
|
||||||
|
|
||||||
/// I2C error abort reason
|
/// I2C error abort reason
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -82,14 +82,12 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
|
|||||||
|
|
||||||
let i2c = Self::new_inner(peri, scl.map_into(), sda.map_into(), config);
|
let i2c = Self::new_inner(peri, scl.map_into(), sda.map_into(), config);
|
||||||
|
|
||||||
unsafe {
|
let r = T::regs();
|
||||||
let i2c = T::regs();
|
|
||||||
|
|
||||||
// mask everything initially
|
// mask everything initially
|
||||||
i2c.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0));
|
r.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0));
|
||||||
T::Interrupt::steal().unpend();
|
T::Interrupt::unpend();
|
||||||
T::Interrupt::steal().enable();
|
unsafe { T::Interrupt::enable() };
|
||||||
}
|
|
||||||
|
|
||||||
i2c
|
i2c
|
||||||
}
|
}
|
||||||
@ -137,14 +135,12 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
|
|||||||
let last = remaining_queue == 0;
|
let last = remaining_queue == 0;
|
||||||
batch += 1;
|
batch += 1;
|
||||||
|
|
||||||
unsafe {
|
|
||||||
p.ic_data_cmd().write(|w| {
|
p.ic_data_cmd().write(|w| {
|
||||||
w.set_restart(restart && remaining_queue == buffer.len() - 1);
|
w.set_restart(restart && remaining_queue == buffer.len() - 1);
|
||||||
w.set_stop(last && send_stop);
|
w.set_stop(last && send_stop);
|
||||||
w.set_cmd(true);
|
w.set_cmd(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// We've either run out of txfifo or just plain finished setting up
|
// We've either run out of txfifo or just plain finished setting up
|
||||||
// the clocks for the message - either way we need to wait for rx
|
// the clocks for the message - either way we need to wait for rx
|
||||||
@ -163,7 +159,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
|
|||||||
Poll::Pending
|
Poll::Pending
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|_me| unsafe {
|
|_me| {
|
||||||
// Set the read threshold to the number of bytes we're
|
// Set the read threshold to the number of bytes we're
|
||||||
// expecting so we don't get spurious interrupts.
|
// expecting so we don't get spurious interrupts.
|
||||||
p.ic_rx_tl().write(|w| w.set_rx_tl(batch - 1));
|
p.ic_rx_tl().write(|w| w.set_rx_tl(batch - 1));
|
||||||
@ -187,7 +183,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
|
|||||||
let rxbytes = (rxfifo as usize).min(remaining);
|
let rxbytes = (rxfifo as usize).min(remaining);
|
||||||
let received = buffer.len() - remaining;
|
let received = buffer.len() - remaining;
|
||||||
for b in &mut buffer[received..received + rxbytes] {
|
for b in &mut buffer[received..received + rxbytes] {
|
||||||
*b = unsafe { p.ic_data_cmd().read().dat() };
|
*b = p.ic_data_cmd().read().dat();
|
||||||
}
|
}
|
||||||
remaining -= rxbytes;
|
remaining -= rxbytes;
|
||||||
}
|
}
|
||||||
@ -213,13 +209,11 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
|
|||||||
if let Some(byte) = bytes.next() {
|
if let Some(byte) = bytes.next() {
|
||||||
let last = bytes.peek().is_none();
|
let last = bytes.peek().is_none();
|
||||||
|
|
||||||
unsafe {
|
|
||||||
p.ic_data_cmd().write(|w| {
|
p.ic_data_cmd().write(|w| {
|
||||||
w.set_stop(last && send_stop);
|
w.set_stop(last && send_stop);
|
||||||
w.set_cmd(false);
|
w.set_cmd(false);
|
||||||
w.set_dat(byte);
|
w.set_dat(byte);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
break 'xmit Ok(());
|
break 'xmit Ok(());
|
||||||
}
|
}
|
||||||
@ -237,7 +231,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
|
|||||||
Poll::Pending
|
Poll::Pending
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|_me| unsafe {
|
|_me| {
|
||||||
// Set tx "free" threshold a little high so that we get
|
// Set tx "free" threshold a little high so that we get
|
||||||
// woken before the fifo completely drains to minimize
|
// woken before the fifo completely drains to minimize
|
||||||
// transfer stalls.
|
// transfer stalls.
|
||||||
@ -269,7 +263,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
|
|||||||
|
|
||||||
let had_abort2 = self
|
let had_abort2 = self
|
||||||
.wait_on(
|
.wait_on(
|
||||||
|me| unsafe {
|
|me| {
|
||||||
// We could see an abort while processing fifo backlog,
|
// We could see an abort while processing fifo backlog,
|
||||||
// so handle it here.
|
// so handle it here.
|
||||||
let abort = me.read_and_clear_abort_reason();
|
let abort = me.read_and_clear_abort_reason();
|
||||||
@ -281,7 +275,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
|
|||||||
Poll::Pending
|
Poll::Pending
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|_me| unsafe {
|
|_me| {
|
||||||
p.ic_intr_mask().modify(|w| {
|
p.ic_intr_mask().modify(|w| {
|
||||||
w.set_m_stop_det(true);
|
w.set_m_stop_det(true);
|
||||||
w.set_m_tx_abrt(true);
|
w.set_m_tx_abrt(true);
|
||||||
@ -289,9 +283,7 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
unsafe {
|
|
||||||
p.ic_clr_stop_det().read();
|
p.ic_clr_stop_det().read();
|
||||||
}
|
|
||||||
|
|
||||||
had_abort.and(had_abort2)
|
had_abort.and(had_abort2)
|
||||||
} else {
|
} else {
|
||||||
@ -314,7 +306,7 @@ pub struct InterruptHandler<T: Instance> {
|
|||||||
_uart: PhantomData<T>,
|
_uart: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
// Mask interrupts and wake any task waiting for this interrupt
|
// Mask interrupts and wake any task waiting for this interrupt
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
let i2c = T::regs();
|
let i2c = T::regs();
|
||||||
@ -338,7 +330,6 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
|
|||||||
|
|
||||||
let p = T::regs();
|
let p = T::regs();
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let reset = T::reset();
|
let reset = T::reset();
|
||||||
crate::reset::reset(reset);
|
crate::reset::reset(reset);
|
||||||
crate::reset::unreset_wait(reset);
|
crate::reset::unreset_wait(reset);
|
||||||
@ -426,7 +417,6 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
|
|||||||
|
|
||||||
// Enable I2C block
|
// Enable I2C block
|
||||||
p.ic_enable().write(|w| w.set_enable(true));
|
p.ic_enable().write(|w| w.set_enable(true));
|
||||||
}
|
|
||||||
|
|
||||||
Self { phantom: PhantomData }
|
Self { phantom: PhantomData }
|
||||||
}
|
}
|
||||||
@ -441,11 +431,9 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let p = T::regs();
|
let p = T::regs();
|
||||||
unsafe {
|
|
||||||
p.ic_enable().write(|w| w.set_enable(false));
|
p.ic_enable().write(|w| w.set_enable(false));
|
||||||
p.ic_tar().write(|w| w.set_ic_tar(addr));
|
p.ic_tar().write(|w| w.set_ic_tar(addr));
|
||||||
p.ic_enable().write(|w| w.set_enable(true));
|
p.ic_enable().write(|w| w.set_enable(true));
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -457,18 +445,17 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn tx_fifo_capacity() -> u8 {
|
fn tx_fifo_capacity() -> u8 {
|
||||||
let p = T::regs();
|
let p = T::regs();
|
||||||
unsafe { FIFO_SIZE - p.ic_txflr().read().txflr() }
|
FIFO_SIZE - p.ic_txflr().read().txflr()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn rx_fifo_len() -> u8 {
|
fn rx_fifo_len() -> u8 {
|
||||||
let p = T::regs();
|
let p = T::regs();
|
||||||
unsafe { p.ic_rxflr().read().rxflr() }
|
p.ic_rxflr().read().rxflr()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> {
|
fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> {
|
||||||
let p = T::regs();
|
let p = T::regs();
|
||||||
unsafe {
|
|
||||||
let abort_reason = p.ic_tx_abrt_source().read();
|
let abort_reason = p.ic_tx_abrt_source().read();
|
||||||
if abort_reason.0 != 0 {
|
if abort_reason.0 != 0 {
|
||||||
// Note clearing the abort flag also clears the reason, and this
|
// Note clearing the abort flag also clears the reason, and this
|
||||||
@ -492,7 +479,6 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn read_blocking_internal(&mut self, read: &mut [u8], restart: bool, send_stop: bool) -> Result<(), Error> {
|
fn read_blocking_internal(&mut self, read: &mut [u8], restart: bool, send_stop: bool) -> Result<(), Error> {
|
||||||
if read.is_empty() {
|
if read.is_empty() {
|
||||||
@ -505,8 +491,6 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
|
|||||||
let first = i == 0;
|
let first = i == 0;
|
||||||
let last = i == lastindex;
|
let last = i == lastindex;
|
||||||
|
|
||||||
// NOTE(unsafe) We have &mut self
|
|
||||||
unsafe {
|
|
||||||
// wait until there is space in the FIFO to write the next byte
|
// wait until there is space in the FIFO to write the next byte
|
||||||
while Self::tx_fifo_full() {}
|
while Self::tx_fifo_full() {}
|
||||||
|
|
||||||
@ -523,7 +507,6 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
|
|||||||
|
|
||||||
*byte = p.ic_data_cmd().read().dat();
|
*byte = p.ic_data_cmd().read().dat();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -538,8 +521,6 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
|
|||||||
for (i, byte) in write.iter().enumerate() {
|
for (i, byte) in write.iter().enumerate() {
|
||||||
let last = i == write.len() - 1;
|
let last = i == write.len() - 1;
|
||||||
|
|
||||||
// NOTE(unsafe) We have &mut self
|
|
||||||
unsafe {
|
|
||||||
p.ic_data_cmd().write(|w| {
|
p.ic_data_cmd().write(|w| {
|
||||||
w.set_stop(send_stop && last);
|
w.set_stop(send_stop && last);
|
||||||
w.set_dat(*byte);
|
w.set_dat(*byte);
|
||||||
@ -568,7 +549,6 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
|
|||||||
// IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0.
|
// IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0.
|
||||||
abort_reason?;
|
abort_reason?;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -762,14 +742,15 @@ fn i2c_reserved_addr(addr: u16) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mod sealed {
|
mod sealed {
|
||||||
use embassy_cortex_m::interrupt::Interrupt;
|
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
|
|
||||||
|
use crate::interrupt;
|
||||||
|
|
||||||
pub trait Instance {
|
pub trait Instance {
|
||||||
const TX_DREQ: u8;
|
const TX_DREQ: u8;
|
||||||
const RX_DREQ: u8;
|
const RX_DREQ: u8;
|
||||||
|
|
||||||
type Interrupt: Interrupt;
|
type Interrupt: interrupt::typelevel::Interrupt;
|
||||||
|
|
||||||
fn regs() -> crate::pac::i2c::I2c;
|
fn regs() -> crate::pac::i2c::I2c;
|
||||||
fn reset() -> crate::pac::resets::regs::Peripherals;
|
fn reset() -> crate::pac::resets::regs::Peripherals;
|
||||||
@ -805,7 +786,7 @@ macro_rules! impl_instance {
|
|||||||
const TX_DREQ: u8 = $tx_dreq;
|
const TX_DREQ: u8 = $tx_dreq;
|
||||||
const RX_DREQ: u8 = $rx_dreq;
|
const RX_DREQ: u8 = $rx_dreq;
|
||||||
|
|
||||||
type Interrupt = crate::interrupt::$irq;
|
type Interrupt = crate::interrupt::typelevel::$irq;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn regs() -> pac::i2c::I2c {
|
fn regs() -> pac::i2c::I2c {
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
//! Interrupt definitions and macros to bind them.
|
|
||||||
pub use cortex_m::interrupt::{CriticalSection, Mutex};
|
|
||||||
use embassy_cortex_m::interrupt::_export::declare;
|
|
||||||
pub use embassy_cortex_m::interrupt::{Binding, Handler, Interrupt, InterruptExt, Priority};
|
|
||||||
|
|
||||||
use crate::pac::Interrupt as InterruptEnum;
|
|
||||||
declare!(TIMER_IRQ_0);
|
|
||||||
declare!(TIMER_IRQ_1);
|
|
||||||
declare!(TIMER_IRQ_2);
|
|
||||||
declare!(TIMER_IRQ_3);
|
|
||||||
declare!(PWM_IRQ_WRAP);
|
|
||||||
declare!(USBCTRL_IRQ);
|
|
||||||
declare!(XIP_IRQ);
|
|
||||||
declare!(PIO0_IRQ_0);
|
|
||||||
declare!(PIO0_IRQ_1);
|
|
||||||
declare!(PIO1_IRQ_0);
|
|
||||||
declare!(PIO1_IRQ_1);
|
|
||||||
declare!(DMA_IRQ_0);
|
|
||||||
declare!(DMA_IRQ_1);
|
|
||||||
declare!(IO_IRQ_BANK0);
|
|
||||||
declare!(IO_IRQ_QSPI);
|
|
||||||
declare!(SIO_IRQ_PROC0);
|
|
||||||
declare!(SIO_IRQ_PROC1);
|
|
||||||
declare!(CLOCKS_IRQ);
|
|
||||||
declare!(SPI0_IRQ);
|
|
||||||
declare!(SPI1_IRQ);
|
|
||||||
declare!(UART0_IRQ);
|
|
||||||
declare!(UART1_IRQ);
|
|
||||||
declare!(ADC_IRQ_FIFO);
|
|
||||||
declare!(I2C0_IRQ);
|
|
||||||
declare!(I2C1_IRQ);
|
|
||||||
declare!(RTC_IRQ);
|
|
||||||
declare!(SWI_IRQ_0);
|
|
||||||
declare!(SWI_IRQ_1);
|
|
||||||
declare!(SWI_IRQ_2);
|
|
||||||
declare!(SWI_IRQ_3);
|
|
||||||
declare!(SWI_IRQ_4);
|
|
||||||
declare!(SWI_IRQ_5);
|
|
||||||
|
|
||||||
/// Macro to bind interrupts to handlers.
|
|
||||||
///
|
|
||||||
/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
|
|
||||||
/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
|
|
||||||
/// prove at compile-time that the right interrupts have been bound.
|
|
||||||
// developer note: this macro can't be in `embassy-cortex-m` due to the use of `$crate`.
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! bind_interrupts {
|
|
||||||
($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
|
|
||||||
$vis struct $name;
|
|
||||||
|
|
||||||
$(
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
#[no_mangle]
|
|
||||||
unsafe extern "C" fn $irq() {
|
|
||||||
$(
|
|
||||||
<$handler as $crate::interrupt::Handler<$crate::interrupt::$irq>>::on_interrupt();
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
|
|
||||||
$(
|
|
||||||
unsafe impl $crate::interrupt::Binding<$crate::interrupt::$irq, $handler> for $name {}
|
|
||||||
)*
|
|
||||||
)*
|
|
||||||
};
|
|
||||||
}
|
|
@ -16,7 +16,6 @@ pub mod flash;
|
|||||||
mod float;
|
mod float;
|
||||||
pub mod gpio;
|
pub mod gpio;
|
||||||
pub mod i2c;
|
pub mod i2c;
|
||||||
pub mod interrupt;
|
|
||||||
pub mod multicore;
|
pub mod multicore;
|
||||||
pub mod pwm;
|
pub mod pwm;
|
||||||
mod reset;
|
mod reset;
|
||||||
@ -37,14 +36,77 @@ pub mod pio_instr_util;
|
|||||||
pub mod relocate;
|
pub mod relocate;
|
||||||
|
|
||||||
// Reexports
|
// Reexports
|
||||||
pub use embassy_cortex_m::executor;
|
|
||||||
pub use embassy_cortex_m::interrupt::_export::interrupt;
|
|
||||||
pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
|
pub use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
|
||||||
#[cfg(feature = "unstable-pac")]
|
#[cfg(feature = "unstable-pac")]
|
||||||
pub use rp_pac as pac;
|
pub use rp_pac as pac;
|
||||||
#[cfg(not(feature = "unstable-pac"))]
|
#[cfg(not(feature = "unstable-pac"))]
|
||||||
pub(crate) use rp_pac as pac;
|
pub(crate) use rp_pac as pac;
|
||||||
|
|
||||||
|
#[cfg(feature = "rt")]
|
||||||
|
pub use crate::pac::NVIC_PRIO_BITS;
|
||||||
|
|
||||||
|
embassy_hal_common::interrupt_mod!(
|
||||||
|
TIMER_IRQ_0,
|
||||||
|
TIMER_IRQ_1,
|
||||||
|
TIMER_IRQ_2,
|
||||||
|
TIMER_IRQ_3,
|
||||||
|
PWM_IRQ_WRAP,
|
||||||
|
USBCTRL_IRQ,
|
||||||
|
XIP_IRQ,
|
||||||
|
PIO0_IRQ_0,
|
||||||
|
PIO0_IRQ_1,
|
||||||
|
PIO1_IRQ_0,
|
||||||
|
PIO1_IRQ_1,
|
||||||
|
DMA_IRQ_0,
|
||||||
|
DMA_IRQ_1,
|
||||||
|
IO_IRQ_BANK0,
|
||||||
|
IO_IRQ_QSPI,
|
||||||
|
SIO_IRQ_PROC0,
|
||||||
|
SIO_IRQ_PROC1,
|
||||||
|
CLOCKS_IRQ,
|
||||||
|
SPI0_IRQ,
|
||||||
|
SPI1_IRQ,
|
||||||
|
UART0_IRQ,
|
||||||
|
UART1_IRQ,
|
||||||
|
ADC_IRQ_FIFO,
|
||||||
|
I2C0_IRQ,
|
||||||
|
I2C1_IRQ,
|
||||||
|
RTC_IRQ,
|
||||||
|
SWI_IRQ_0,
|
||||||
|
SWI_IRQ_1,
|
||||||
|
SWI_IRQ_2,
|
||||||
|
SWI_IRQ_3,
|
||||||
|
SWI_IRQ_4,
|
||||||
|
SWI_IRQ_5,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Macro to bind interrupts to handlers.
|
||||||
|
///
|
||||||
|
/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
|
||||||
|
/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
|
||||||
|
/// prove at compile-time that the right interrupts have been bound.
|
||||||
|
// developer note: this macro can't be in `embassy-hal-common` due to the use of `$crate`.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! bind_interrupts {
|
||||||
|
($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
|
||||||
|
$vis struct $name;
|
||||||
|
|
||||||
|
$(
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[no_mangle]
|
||||||
|
unsafe extern "C" fn $irq() {
|
||||||
|
$(
|
||||||
|
<$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt();
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
|
||||||
|
$(
|
||||||
|
unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {}
|
||||||
|
)*
|
||||||
|
)*
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
embassy_hal_common::peripherals! {
|
embassy_hal_common::peripherals! {
|
||||||
PIN_0,
|
PIN_0,
|
||||||
PIN_1,
|
PIN_1,
|
||||||
@ -199,33 +261,39 @@ pub fn init(config: config::Config) -> Peripherals {
|
|||||||
|
|
||||||
/// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes.
|
/// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes.
|
||||||
trait RegExt<T: Copy> {
|
trait RegExt<T: Copy> {
|
||||||
unsafe fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
|
fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
|
||||||
unsafe fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
|
fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
|
||||||
unsafe fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
|
fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Default + Copy, A: pac::common::Write> RegExt<T> for pac::common::Reg<T, A> {
|
impl<T: Default + Copy, A: pac::common::Write> RegExt<T> for pac::common::Reg<T, A> {
|
||||||
unsafe fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
|
fn write_xor<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
|
||||||
let mut val = Default::default();
|
let mut val = Default::default();
|
||||||
let res = f(&mut val);
|
let res = f(&mut val);
|
||||||
let ptr = (self.ptr() as *mut u8).add(0x1000) as *mut T;
|
unsafe {
|
||||||
|
let ptr = (self.as_ptr() as *mut u8).add(0x1000) as *mut T;
|
||||||
ptr.write_volatile(val);
|
ptr.write_volatile(val);
|
||||||
|
}
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
|
fn write_set<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
|
||||||
let mut val = Default::default();
|
let mut val = Default::default();
|
||||||
let res = f(&mut val);
|
let res = f(&mut val);
|
||||||
let ptr = (self.ptr() as *mut u8).add(0x2000) as *mut T;
|
unsafe {
|
||||||
|
let ptr = (self.as_ptr() as *mut u8).add(0x2000) as *mut T;
|
||||||
ptr.write_volatile(val);
|
ptr.write_volatile(val);
|
||||||
|
}
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
|
fn write_clear<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
|
||||||
let mut val = Default::default();
|
let mut val = Default::default();
|
||||||
let res = f(&mut val);
|
let res = f(&mut val);
|
||||||
let ptr = (self.ptr() as *mut u8).add(0x3000) as *mut T;
|
unsafe {
|
||||||
|
let ptr = (self.as_ptr() as *mut u8).add(0x3000) as *mut T;
|
||||||
ptr.write_volatile(val);
|
ptr.write_volatile(val);
|
||||||
|
}
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@
|
|||||||
use core::mem::ManuallyDrop;
|
use core::mem::ManuallyDrop;
|
||||||
use core::sync::atomic::{compiler_fence, AtomicBool, Ordering};
|
use core::sync::atomic::{compiler_fence, AtomicBool, Ordering};
|
||||||
|
|
||||||
use crate::interrupt::{Interrupt, InterruptExt};
|
use crate::interrupt::InterruptExt;
|
||||||
use crate::peripherals::CORE1;
|
use crate::peripherals::CORE1;
|
||||||
use crate::{gpio, interrupt, pac};
|
use crate::{gpio, interrupt, pac};
|
||||||
|
|
||||||
@ -106,6 +106,7 @@ impl<const SIZE: usize> Stack<SIZE> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rt")]
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
#[link_section = ".data.ram_func"]
|
#[link_section = ".data.ram_func"]
|
||||||
unsafe fn SIO_IRQ_PROC1() {
|
unsafe fn SIO_IRQ_PROC1() {
|
||||||
@ -156,21 +157,18 @@ where
|
|||||||
|
|
||||||
IS_CORE1_INIT.store(true, Ordering::Release);
|
IS_CORE1_INIT.store(true, Ordering::Release);
|
||||||
// Enable fifo interrupt on CORE1 for `pause` functionality.
|
// Enable fifo interrupt on CORE1 for `pause` functionality.
|
||||||
let irq = unsafe { interrupt::SIO_IRQ_PROC1::steal() };
|
unsafe { interrupt::SIO_IRQ_PROC1.enable() };
|
||||||
irq.enable();
|
|
||||||
|
|
||||||
entry()
|
entry()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the core
|
// Reset the core
|
||||||
unsafe {
|
|
||||||
let psm = pac::PSM;
|
let psm = pac::PSM;
|
||||||
psm.frce_off().modify(|w| w.set_proc1(true));
|
psm.frce_off().modify(|w| w.set_proc1(true));
|
||||||
while !psm.frce_off().read().proc1() {
|
while !psm.frce_off().read().proc1() {
|
||||||
cortex_m::asm::nop();
|
cortex_m::asm::nop();
|
||||||
}
|
}
|
||||||
psm.frce_off().modify(|w| w.set_proc1(false));
|
psm.frce_off().modify(|w| w.set_proc1(false));
|
||||||
}
|
|
||||||
|
|
||||||
// The ARM AAPCS ABI requires 8-byte stack alignment.
|
// The ARM AAPCS ABI requires 8-byte stack alignment.
|
||||||
// #[align] on `struct Stack` ensures the bottom is aligned, but the top could still be
|
// #[align] on `struct Stack` ensures the bottom is aligned, but the top could still be
|
||||||
@ -270,14 +268,12 @@ pub fn resume_core1() {
|
|||||||
// Push a value to the inter-core FIFO, block until space is available
|
// Push a value to the inter-core FIFO, block until space is available
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn fifo_write(value: u32) {
|
fn fifo_write(value: u32) {
|
||||||
unsafe {
|
|
||||||
let sio = pac::SIO;
|
let sio = pac::SIO;
|
||||||
// Wait for the FIFO to have enough space
|
// Wait for the FIFO to have enough space
|
||||||
while !sio.fifo().st().read().rdy() {
|
while !sio.fifo().st().read().rdy() {
|
||||||
cortex_m::asm::nop();
|
cortex_m::asm::nop();
|
||||||
}
|
}
|
||||||
sio.fifo().wr().write_value(value);
|
sio.fifo().wr().write_value(value);
|
||||||
}
|
|
||||||
// Fire off an event to the other core.
|
// Fire off an event to the other core.
|
||||||
// This is required as the other core may be `wfe` (waiting for event)
|
// This is required as the other core may be `wfe` (waiting for event)
|
||||||
cortex_m::asm::sev();
|
cortex_m::asm::sev();
|
||||||
@ -286,38 +282,33 @@ fn fifo_write(value: u32) {
|
|||||||
// Pop a value from inter-core FIFO, block until available
|
// Pop a value from inter-core FIFO, block until available
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn fifo_read() -> u32 {
|
fn fifo_read() -> u32 {
|
||||||
unsafe {
|
|
||||||
let sio = pac::SIO;
|
let sio = pac::SIO;
|
||||||
// Wait until FIFO has data
|
// Wait until FIFO has data
|
||||||
while !sio.fifo().st().read().vld() {
|
while !sio.fifo().st().read().vld() {
|
||||||
cortex_m::asm::nop();
|
cortex_m::asm::nop();
|
||||||
}
|
}
|
||||||
sio.fifo().rd().read()
|
sio.fifo().rd().read()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pop a value from inter-core FIFO, `wfe` until available
|
// Pop a value from inter-core FIFO, `wfe` until available
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[allow(unused)]
|
||||||
fn fifo_read_wfe() -> u32 {
|
fn fifo_read_wfe() -> u32 {
|
||||||
unsafe {
|
|
||||||
let sio = pac::SIO;
|
let sio = pac::SIO;
|
||||||
// Wait until FIFO has data
|
// Wait until FIFO has data
|
||||||
while !sio.fifo().st().read().vld() {
|
while !sio.fifo().st().read().vld() {
|
||||||
cortex_m::asm::wfe();
|
cortex_m::asm::wfe();
|
||||||
}
|
}
|
||||||
sio.fifo().rd().read()
|
sio.fifo().rd().read()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drain inter-core FIFO
|
// Drain inter-core FIFO
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn fifo_drain() {
|
fn fifo_drain() {
|
||||||
unsafe {
|
|
||||||
let sio = pac::SIO;
|
let sio = pac::SIO;
|
||||||
while sio.fifo().st().read().vld() {
|
while sio.fifo().st().read().vld() {
|
||||||
let _ = sio.fifo().rd().read();
|
let _ = sio.fifo().rd().read();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/nvzqz/bad-rs/blob/master/src/never.rs
|
// https://github.com/nvzqz/bad-rs/blob/master/src/never.rs
|
||||||
|
@ -5,7 +5,6 @@ use core::sync::atomic::{compiler_fence, Ordering};
|
|||||||
use core::task::{Context, Poll};
|
use core::task::{Context, Poll};
|
||||||
|
|
||||||
use atomic_polyfill::{AtomicU32, AtomicU8};
|
use atomic_polyfill::{AtomicU32, AtomicU8};
|
||||||
use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
|
|
||||||
use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
|
use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
use fixed::types::extra::U8;
|
use fixed::types::extra::U8;
|
||||||
@ -17,6 +16,7 @@ use pio::{SideSet, Wrap};
|
|||||||
use crate::dma::{Channel, Transfer, Word};
|
use crate::dma::{Channel, Transfer, Word};
|
||||||
use crate::gpio::sealed::Pin as SealedPin;
|
use crate::gpio::sealed::Pin as SealedPin;
|
||||||
use crate::gpio::{self, AnyPin, Drive, Level, Pull, SlewRate};
|
use crate::gpio::{self, AnyPin, Drive, Level, Pull, SlewRate};
|
||||||
|
use crate::interrupt::InterruptExt;
|
||||||
use crate::pac::dma::vals::TreqSel;
|
use crate::pac::dma::vals::TreqSel;
|
||||||
use crate::relocate::RelocatedProgram;
|
use crate::relocate::RelocatedProgram;
|
||||||
use crate::{interrupt, pac, peripherals, pio_instr_util, RegExt};
|
use crate::{interrupt, pac, peripherals, pio_instr_util, RegExt};
|
||||||
@ -85,8 +85,9 @@ const RXNEMPTY_MASK: u32 = 1 << 0;
|
|||||||
const TXNFULL_MASK: u32 = 1 << 4;
|
const TXNFULL_MASK: u32 = 1 << 4;
|
||||||
const SMIRQ_MASK: u32 = 1 << 8;
|
const SMIRQ_MASK: u32 = 1 << 8;
|
||||||
|
|
||||||
|
#[cfg(feature = "rt")]
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
unsafe fn PIO0_IRQ_0() {
|
fn PIO0_IRQ_0() {
|
||||||
use crate::pac;
|
use crate::pac;
|
||||||
let ints = pac::PIO0.irqs(0).ints().read().0;
|
let ints = pac::PIO0.irqs(0).ints().read().0;
|
||||||
for bit in 0..12 {
|
for bit in 0..12 {
|
||||||
@ -97,8 +98,9 @@ unsafe fn PIO0_IRQ_0() {
|
|||||||
pac::PIO0.irqs(0).inte().write_clear(|m| m.0 = ints);
|
pac::PIO0.irqs(0).inte().write_clear(|m| m.0 = ints);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rt")]
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
unsafe fn PIO1_IRQ_0() {
|
fn PIO1_IRQ_0() {
|
||||||
use crate::pac;
|
use crate::pac;
|
||||||
let ints = pac::PIO1.irqs(0).ints().read().0;
|
let ints = pac::PIO1.irqs(0).ints().read().0;
|
||||||
for bit in 0..12 {
|
for bit in 0..12 {
|
||||||
@ -110,17 +112,15 @@ unsafe fn PIO1_IRQ_0() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn init() {
|
pub(crate) unsafe fn init() {
|
||||||
let irq = interrupt::PIO0_IRQ_0::steal();
|
interrupt::PIO0_IRQ_0.disable();
|
||||||
irq.disable();
|
interrupt::PIO0_IRQ_0.set_priority(interrupt::Priority::P3);
|
||||||
irq.set_priority(interrupt::Priority::P3);
|
|
||||||
pac::PIO0.irqs(0).inte().write(|m| m.0 = 0);
|
pac::PIO0.irqs(0).inte().write(|m| m.0 = 0);
|
||||||
irq.enable();
|
interrupt::PIO0_IRQ_0.enable();
|
||||||
|
|
||||||
let irq = interrupt::PIO1_IRQ_0::steal();
|
interrupt::PIO1_IRQ_0.disable();
|
||||||
irq.disable();
|
interrupt::PIO1_IRQ_0.set_priority(interrupt::Priority::P3);
|
||||||
irq.set_priority(interrupt::Priority::P3);
|
|
||||||
pac::PIO1.irqs(0).inte().write(|m| m.0 = 0);
|
pac::PIO1.irqs(0).inte().write(|m| m.0 = 0);
|
||||||
irq.enable();
|
interrupt::PIO1_IRQ_0.enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Future that waits for TX-FIFO to become writable
|
/// Future that waits for TX-FIFO to become writable
|
||||||
@ -145,11 +145,9 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoOutFuture<'a, 'd, PI
|
|||||||
Poll::Ready(())
|
Poll::Ready(())
|
||||||
} else {
|
} else {
|
||||||
WAKERS[PIO::PIO_NO as usize].fifo_out()[SM].register(cx.waker());
|
WAKERS[PIO::PIO_NO as usize].fifo_out()[SM].register(cx.waker());
|
||||||
unsafe {
|
|
||||||
PIO::PIO.irqs(0).inte().write_set(|m| {
|
PIO::PIO.irqs(0).inte().write_set(|m| {
|
||||||
m.0 = TXNFULL_MASK << SM;
|
m.0 = TXNFULL_MASK << SM;
|
||||||
});
|
});
|
||||||
}
|
|
||||||
// debug!("Pending");
|
// debug!("Pending");
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
}
|
}
|
||||||
@ -158,12 +156,10 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoOutFuture<'a, 'd, PI
|
|||||||
|
|
||||||
impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoOutFuture<'a, 'd, PIO, SM> {
|
impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoOutFuture<'a, 'd, PIO, SM> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
|
||||||
PIO::PIO.irqs(0).inte().write_clear(|m| {
|
PIO::PIO.irqs(0).inte().write_clear(|m| {
|
||||||
m.0 = TXNFULL_MASK << SM;
|
m.0 = TXNFULL_MASK << SM;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Future that waits for RX-FIFO to become readable
|
/// Future that waits for RX-FIFO to become readable
|
||||||
@ -186,11 +182,9 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoInFuture<'a, 'd, PIO
|
|||||||
Poll::Ready(v)
|
Poll::Ready(v)
|
||||||
} else {
|
} else {
|
||||||
WAKERS[PIO::PIO_NO as usize].fifo_in()[SM].register(cx.waker());
|
WAKERS[PIO::PIO_NO as usize].fifo_in()[SM].register(cx.waker());
|
||||||
unsafe {
|
|
||||||
PIO::PIO.irqs(0).inte().write_set(|m| {
|
PIO::PIO.irqs(0).inte().write_set(|m| {
|
||||||
m.0 = RXNEMPTY_MASK << SM;
|
m.0 = RXNEMPTY_MASK << SM;
|
||||||
});
|
});
|
||||||
}
|
|
||||||
//debug!("Pending");
|
//debug!("Pending");
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
}
|
}
|
||||||
@ -199,12 +193,10 @@ impl<'a, 'd, PIO: Instance, const SM: usize> Future for FifoInFuture<'a, 'd, PIO
|
|||||||
|
|
||||||
impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoInFuture<'a, 'd, PIO, SM> {
|
impl<'a, 'd, PIO: Instance, const SM: usize> Drop for FifoInFuture<'a, 'd, PIO, SM> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
|
||||||
PIO::PIO.irqs(0).inte().write_clear(|m| {
|
PIO::PIO.irqs(0).inte().write_clear(|m| {
|
||||||
m.0 = RXNEMPTY_MASK << SM;
|
m.0 = RXNEMPTY_MASK << SM;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Future that waits for IRQ
|
/// Future that waits for IRQ
|
||||||
@ -220,31 +212,25 @@ impl<'a, 'd, PIO: Instance> Future for IrqFuture<'a, 'd, PIO> {
|
|||||||
//debug!("Poll {},{}", PIO::PIO_NO, SM);
|
//debug!("Poll {},{}", PIO::PIO_NO, SM);
|
||||||
|
|
||||||
// Check if IRQ flag is already set
|
// Check if IRQ flag is already set
|
||||||
if unsafe { PIO::PIO.irq().read().0 & (1 << self.irq_no) != 0 } {
|
if PIO::PIO.irq().read().0 & (1 << self.irq_no) != 0 {
|
||||||
unsafe {
|
|
||||||
PIO::PIO.irq().write(|m| m.0 = 1 << self.irq_no);
|
PIO::PIO.irq().write(|m| m.0 = 1 << self.irq_no);
|
||||||
}
|
|
||||||
return Poll::Ready(());
|
return Poll::Ready(());
|
||||||
}
|
}
|
||||||
|
|
||||||
WAKERS[PIO::PIO_NO as usize].irq()[self.irq_no as usize].register(cx.waker());
|
WAKERS[PIO::PIO_NO as usize].irq()[self.irq_no as usize].register(cx.waker());
|
||||||
unsafe {
|
|
||||||
PIO::PIO.irqs(0).inte().write_set(|m| {
|
PIO::PIO.irqs(0).inte().write_set(|m| {
|
||||||
m.0 = SMIRQ_MASK << self.irq_no;
|
m.0 = SMIRQ_MASK << self.irq_no;
|
||||||
});
|
});
|
||||||
}
|
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'd, PIO: Instance> Drop for IrqFuture<'a, 'd, PIO> {
|
impl<'a, 'd, PIO: Instance> Drop for IrqFuture<'a, 'd, PIO> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
|
||||||
PIO::PIO.irqs(0).inte().write_clear(|m| {
|
PIO::PIO.irqs(0).inte().write_clear(|m| {
|
||||||
m.0 = SMIRQ_MASK << self.irq_no;
|
m.0 = SMIRQ_MASK << self.irq_no;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Pin<'l, PIO: Instance> {
|
pub struct Pin<'l, PIO: Instance> {
|
||||||
@ -256,7 +242,6 @@ impl<'l, PIO: Instance> Pin<'l, PIO> {
|
|||||||
/// Set the pin's drive strength.
|
/// Set the pin's drive strength.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_drive_strength(&mut self, strength: Drive) {
|
pub fn set_drive_strength(&mut self, strength: Drive) {
|
||||||
unsafe {
|
|
||||||
self.pin.pad_ctrl().modify(|w| {
|
self.pin.pad_ctrl().modify(|w| {
|
||||||
w.set_drive(match strength {
|
w.set_drive(match strength {
|
||||||
Drive::_2mA => pac::pads::vals::Drive::_2MA,
|
Drive::_2mA => pac::pads::vals::Drive::_2MA,
|
||||||
@ -266,49 +251,40 @@ impl<'l, PIO: Instance> Pin<'l, PIO> {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Set the pin's slew rate.
|
// Set the pin's slew rate.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_slew_rate(&mut self, slew_rate: SlewRate) {
|
pub fn set_slew_rate(&mut self, slew_rate: SlewRate) {
|
||||||
unsafe {
|
|
||||||
self.pin.pad_ctrl().modify(|w| {
|
self.pin.pad_ctrl().modify(|w| {
|
||||||
w.set_slewfast(slew_rate == SlewRate::Fast);
|
w.set_slewfast(slew_rate == SlewRate::Fast);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the pin's pull.
|
/// Set the pin's pull.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_pull(&mut self, pull: Pull) {
|
pub fn set_pull(&mut self, pull: Pull) {
|
||||||
unsafe {
|
|
||||||
self.pin.pad_ctrl().modify(|w| {
|
self.pin.pad_ctrl().modify(|w| {
|
||||||
w.set_pue(pull == Pull::Up);
|
w.set_pue(pull == Pull::Up);
|
||||||
w.set_pde(pull == Pull::Down);
|
w.set_pde(pull == Pull::Down);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the pin's schmitt trigger.
|
/// Set the pin's schmitt trigger.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_schmitt(&mut self, enable: bool) {
|
pub fn set_schmitt(&mut self, enable: bool) {
|
||||||
unsafe {
|
|
||||||
self.pin.pad_ctrl().modify(|w| {
|
self.pin.pad_ctrl().modify(|w| {
|
||||||
w.set_schmitt(enable);
|
w.set_schmitt(enable);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) {
|
pub fn set_input_sync_bypass<'a>(&mut self, bypass: bool) {
|
||||||
let mask = 1 << self.pin();
|
let mask = 1 << self.pin();
|
||||||
unsafe {
|
|
||||||
if bypass {
|
if bypass {
|
||||||
PIO::PIO.input_sync_bypass().write_set(|w| *w = mask);
|
PIO::PIO.input_sync_bypass().write_set(|w| *w = mask);
|
||||||
} else {
|
} else {
|
||||||
PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask);
|
PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pin(&self) -> u8 {
|
pub fn pin(&self) -> u8 {
|
||||||
self.pin._pin()
|
self.pin._pin()
|
||||||
@ -321,19 +297,18 @@ pub struct StateMachineRx<'d, PIO: Instance, const SM: usize> {
|
|||||||
|
|
||||||
impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
|
impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
|
||||||
pub fn empty(&self) -> bool {
|
pub fn empty(&self) -> bool {
|
||||||
unsafe { PIO::PIO.fstat().read().rxempty() & (1u8 << SM) != 0 }
|
PIO::PIO.fstat().read().rxempty() & (1u8 << SM) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn full(&self) -> bool {
|
pub fn full(&self) -> bool {
|
||||||
unsafe { PIO::PIO.fstat().read().rxfull() & (1u8 << SM) != 0 }
|
PIO::PIO.fstat().read().rxfull() & (1u8 << SM) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn level(&self) -> u8 {
|
pub fn level(&self) -> u8 {
|
||||||
unsafe { (PIO::PIO.flevel().read().0 >> (SM * 8 + 4)) as u8 & 0x0f }
|
(PIO::PIO.flevel().read().0 >> (SM * 8 + 4)) as u8 & 0x0f
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stalled(&self) -> bool {
|
pub fn stalled(&self) -> bool {
|
||||||
unsafe {
|
|
||||||
let fdebug = PIO::PIO.fdebug();
|
let fdebug = PIO::PIO.fdebug();
|
||||||
let ret = fdebug.read().rxstall() & (1 << SM) != 0;
|
let ret = fdebug.read().rxstall() & (1 << SM) != 0;
|
||||||
if ret {
|
if ret {
|
||||||
@ -341,10 +316,8 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
|
|||||||
}
|
}
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn underflowed(&self) -> bool {
|
pub fn underflowed(&self) -> bool {
|
||||||
unsafe {
|
|
||||||
let fdebug = PIO::PIO.fdebug();
|
let fdebug = PIO::PIO.fdebug();
|
||||||
let ret = fdebug.read().rxunder() & (1 << SM) != 0;
|
let ret = fdebug.read().rxunder() & (1 << SM) != 0;
|
||||||
if ret {
|
if ret {
|
||||||
@ -352,10 +325,9 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
|
|||||||
}
|
}
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pull(&mut self) -> u32 {
|
pub fn pull(&mut self) -> u32 {
|
||||||
unsafe { PIO::PIO.rxf(SM).read() }
|
PIO::PIO.rxf(SM).read()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_pull(&mut self) -> Option<u32> {
|
pub fn try_pull(&mut self) -> Option<u32> {
|
||||||
@ -374,11 +346,10 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
|
|||||||
ch: PeripheralRef<'a, C>,
|
ch: PeripheralRef<'a, C>,
|
||||||
data: &'a mut [W],
|
data: &'a mut [W],
|
||||||
) -> Transfer<'a, C> {
|
) -> Transfer<'a, C> {
|
||||||
unsafe {
|
|
||||||
let pio_no = PIO::PIO_NO;
|
let pio_no = PIO::PIO_NO;
|
||||||
let p = ch.regs();
|
let p = ch.regs();
|
||||||
p.write_addr().write_value(data.as_ptr() as u32);
|
p.write_addr().write_value(data.as_ptr() as u32);
|
||||||
p.read_addr().write_value(PIO::PIO.rxf(SM).ptr() as u32);
|
p.read_addr().write_value(PIO::PIO.rxf(SM).as_ptr() as u32);
|
||||||
p.trans_count().write_value(data.len() as u32);
|
p.trans_count().write_value(data.len() as u32);
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
p.ctrl_trig().write(|w| {
|
p.ctrl_trig().write(|w| {
|
||||||
@ -391,7 +362,6 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineRx<'d, PIO, SM> {
|
|||||||
w.set_en(true);
|
w.set_en(true);
|
||||||
});
|
});
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
}
|
|
||||||
Transfer::new(ch)
|
Transfer::new(ch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -402,18 +372,17 @@ pub struct StateMachineTx<'d, PIO: Instance, const SM: usize> {
|
|||||||
|
|
||||||
impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
|
impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
|
||||||
pub fn empty(&self) -> bool {
|
pub fn empty(&self) -> bool {
|
||||||
unsafe { PIO::PIO.fstat().read().txempty() & (1u8 << SM) != 0 }
|
PIO::PIO.fstat().read().txempty() & (1u8 << SM) != 0
|
||||||
}
|
}
|
||||||
pub fn full(&self) -> bool {
|
pub fn full(&self) -> bool {
|
||||||
unsafe { PIO::PIO.fstat().read().txfull() & (1u8 << SM) != 0 }
|
PIO::PIO.fstat().read().txfull() & (1u8 << SM) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn level(&self) -> u8 {
|
pub fn level(&self) -> u8 {
|
||||||
unsafe { (PIO::PIO.flevel().read().0 >> (SM * 8)) as u8 & 0x0f }
|
(PIO::PIO.flevel().read().0 >> (SM * 8)) as u8 & 0x0f
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stalled(&self) -> bool {
|
pub fn stalled(&self) -> bool {
|
||||||
unsafe {
|
|
||||||
let fdebug = PIO::PIO.fdebug();
|
let fdebug = PIO::PIO.fdebug();
|
||||||
let ret = fdebug.read().txstall() & (1 << SM) != 0;
|
let ret = fdebug.read().txstall() & (1 << SM) != 0;
|
||||||
if ret {
|
if ret {
|
||||||
@ -421,10 +390,8 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
|
|||||||
}
|
}
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn overflowed(&self) -> bool {
|
pub fn overflowed(&self) -> bool {
|
||||||
unsafe {
|
|
||||||
let fdebug = PIO::PIO.fdebug();
|
let fdebug = PIO::PIO.fdebug();
|
||||||
let ret = fdebug.read().txover() & (1 << SM) != 0;
|
let ret = fdebug.read().txover() & (1 << SM) != 0;
|
||||||
if ret {
|
if ret {
|
||||||
@ -432,13 +399,10 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
|
|||||||
}
|
}
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push(&mut self, v: u32) {
|
pub fn push(&mut self, v: u32) {
|
||||||
unsafe {
|
|
||||||
PIO::PIO.txf(SM).write_value(v);
|
PIO::PIO.txf(SM).write_value(v);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_push(&mut self, v: u32) -> bool {
|
pub fn try_push(&mut self, v: u32) -> bool {
|
||||||
if self.full() {
|
if self.full() {
|
||||||
@ -453,11 +417,10 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn dma_push<'a, C: Channel, W: Word>(&'a mut self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> {
|
pub fn dma_push<'a, C: Channel, W: Word>(&'a mut self, ch: PeripheralRef<'a, C>, data: &'a [W]) -> Transfer<'a, C> {
|
||||||
unsafe {
|
|
||||||
let pio_no = PIO::PIO_NO;
|
let pio_no = PIO::PIO_NO;
|
||||||
let p = ch.regs();
|
let p = ch.regs();
|
||||||
p.read_addr().write_value(data.as_ptr() as u32);
|
p.read_addr().write_value(data.as_ptr() as u32);
|
||||||
p.write_addr().write_value(PIO::PIO.txf(SM).ptr() as u32);
|
p.write_addr().write_value(PIO::PIO.txf(SM).as_ptr() as u32);
|
||||||
p.trans_count().write_value(data.len() as u32);
|
p.trans_count().write_value(data.len() as u32);
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
p.ctrl_trig().write(|w| {
|
p.ctrl_trig().write(|w| {
|
||||||
@ -470,7 +433,6 @@ impl<'d, PIO: Instance, const SM: usize> StateMachineTx<'d, PIO, SM> {
|
|||||||
w.set_en(true);
|
w.set_en(true);
|
||||||
});
|
});
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst);
|
||||||
}
|
|
||||||
Transfer::new(ch)
|
Transfer::new(ch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -482,9 +444,7 @@ pub struct StateMachine<'d, PIO: Instance, const SM: usize> {
|
|||||||
|
|
||||||
impl<'d, PIO: Instance, const SM: usize> Drop for StateMachine<'d, PIO, SM> {
|
impl<'d, PIO: Instance, const SM: usize> Drop for StateMachine<'d, PIO, SM> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
|
||||||
PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(1 << SM));
|
PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(1 << SM));
|
||||||
}
|
|
||||||
on_pio_drop::<PIO>();
|
on_pio_drop::<PIO>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -647,7 +607,6 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
|
|||||||
assert!(config.shift_in.threshold <= 32, "shift_in.threshold must be <= 32");
|
assert!(config.shift_in.threshold <= 32, "shift_in.threshold must be <= 32");
|
||||||
assert!(config.shift_out.threshold <= 32, "shift_out.threshold must be <= 32");
|
assert!(config.shift_out.threshold <= 32, "shift_out.threshold must be <= 32");
|
||||||
let sm = Self::this_sm();
|
let sm = Self::this_sm();
|
||||||
unsafe {
|
|
||||||
sm.clkdiv().write(|w| w.0 = config.clock_divider.to_bits() << 8);
|
sm.clkdiv().write(|w| w.0 = config.clock_divider.to_bits() << 8);
|
||||||
sm.execctrl().write(|w| {
|
sm.execctrl().write(|w| {
|
||||||
w.set_side_en(config.exec.side_en);
|
w.set_side_en(config.exec.side_en);
|
||||||
@ -684,8 +643,7 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
|
|||||||
w.set_out_base(config.pins.out_base);
|
w.set_out_base(config.pins.out_base);
|
||||||
});
|
});
|
||||||
if let Some(origin) = config.origin {
|
if let Some(origin) = config.origin {
|
||||||
pio_instr_util::exec_jmp(self, origin);
|
unsafe { pio_instr_util::exec_jmp(self, origin) }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -696,45 +654,35 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
|
|||||||
|
|
||||||
pub fn restart(&mut self) {
|
pub fn restart(&mut self) {
|
||||||
let mask = 1u8 << SM;
|
let mask = 1u8 << SM;
|
||||||
unsafe {
|
|
||||||
PIO::PIO.ctrl().write_set(|w| w.set_sm_restart(mask));
|
PIO::PIO.ctrl().write_set(|w| w.set_sm_restart(mask));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
pub fn set_enable(&mut self, enable: bool) {
|
pub fn set_enable(&mut self, enable: bool) {
|
||||||
let mask = 1u8 << SM;
|
let mask = 1u8 << SM;
|
||||||
unsafe {
|
|
||||||
if enable {
|
if enable {
|
||||||
PIO::PIO.ctrl().write_set(|w| w.set_sm_enable(mask));
|
PIO::PIO.ctrl().write_set(|w| w.set_sm_enable(mask));
|
||||||
} else {
|
} else {
|
||||||
PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(mask));
|
PIO::PIO.ctrl().write_clear(|w| w.set_sm_enable(mask));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_enabled(&self) -> bool {
|
pub fn is_enabled(&self) -> bool {
|
||||||
unsafe { PIO::PIO.ctrl().read().sm_enable() & (1u8 << SM) != 0 }
|
PIO::PIO.ctrl().read().sm_enable() & (1u8 << SM) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clkdiv_restart(&mut self) {
|
pub fn clkdiv_restart(&mut self) {
|
||||||
let mask = 1u8 << SM;
|
let mask = 1u8 << SM;
|
||||||
unsafe {
|
|
||||||
PIO::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask));
|
PIO::PIO.ctrl().write_set(|w| w.set_clkdiv_restart(mask));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn with_paused(&mut self, f: impl FnOnce(&mut Self)) {
|
fn with_paused(&mut self, f: impl FnOnce(&mut Self)) {
|
||||||
let enabled = self.is_enabled();
|
let enabled = self.is_enabled();
|
||||||
self.set_enable(false);
|
self.set_enable(false);
|
||||||
let pincfg = unsafe { Self::this_sm().pinctrl().read() };
|
let pincfg = Self::this_sm().pinctrl().read();
|
||||||
let execcfg = unsafe { Self::this_sm().execctrl().read() };
|
let execcfg = Self::this_sm().execctrl().read();
|
||||||
unsafe {
|
|
||||||
Self::this_sm().execctrl().write_clear(|w| w.set_out_sticky(true));
|
Self::this_sm().execctrl().write_clear(|w| w.set_out_sticky(true));
|
||||||
}
|
|
||||||
f(self);
|
f(self);
|
||||||
unsafe {
|
|
||||||
Self::this_sm().pinctrl().write_value(pincfg);
|
Self::this_sm().pinctrl().write_value(pincfg);
|
||||||
Self::this_sm().execctrl().write_value(execcfg);
|
Self::this_sm().execctrl().write_value(execcfg);
|
||||||
}
|
|
||||||
self.set_enable(enabled);
|
self.set_enable(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -743,14 +691,12 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
|
|||||||
pub fn set_pin_dirs(&mut self, dir: Direction, pins: &[&Pin<'d, PIO>]) {
|
pub fn set_pin_dirs(&mut self, dir: Direction, pins: &[&Pin<'d, PIO>]) {
|
||||||
self.with_paused(|sm| {
|
self.with_paused(|sm| {
|
||||||
for pin in pins {
|
for pin in pins {
|
||||||
unsafe {
|
|
||||||
Self::this_sm().pinctrl().write(|w| {
|
Self::this_sm().pinctrl().write(|w| {
|
||||||
w.set_set_base(pin.pin());
|
w.set_set_base(pin.pin());
|
||||||
w.set_set_count(1);
|
w.set_set_count(1);
|
||||||
});
|
});
|
||||||
// SET PINDIRS, (dir)
|
// SET PINDIRS, (dir)
|
||||||
sm.exec_instr(0b111_00000_100_00000 | dir as u16);
|
unsafe { sm.exec_instr(0b111_00000_100_00000 | dir as u16) };
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -760,21 +706,18 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
|
|||||||
pub fn set_pins(&mut self, level: Level, pins: &[&Pin<'d, PIO>]) {
|
pub fn set_pins(&mut self, level: Level, pins: &[&Pin<'d, PIO>]) {
|
||||||
self.with_paused(|sm| {
|
self.with_paused(|sm| {
|
||||||
for pin in pins {
|
for pin in pins {
|
||||||
unsafe {
|
|
||||||
Self::this_sm().pinctrl().write(|w| {
|
Self::this_sm().pinctrl().write(|w| {
|
||||||
w.set_set_base(pin.pin());
|
w.set_set_base(pin.pin());
|
||||||
w.set_set_count(1);
|
w.set_set_count(1);
|
||||||
});
|
});
|
||||||
// SET PINS, (dir)
|
// SET PINS, (dir)
|
||||||
sm.exec_instr(0b111_00000_000_00000 | level as u16);
|
unsafe { sm.exec_instr(0b111_00000_000_00000 | level as u16) };
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_fifos(&mut self) {
|
pub fn clear_fifos(&mut self) {
|
||||||
// Toggle FJOIN_RX to flush FIFOs
|
// Toggle FJOIN_RX to flush FIFOs
|
||||||
unsafe {
|
|
||||||
let shiftctrl = Self::this_sm().shiftctrl();
|
let shiftctrl = Self::this_sm().shiftctrl();
|
||||||
shiftctrl.modify(|w| {
|
shiftctrl.modify(|w| {
|
||||||
w.set_fjoin_rx(!w.fjoin_rx());
|
w.set_fjoin_rx(!w.fjoin_rx());
|
||||||
@ -783,7 +726,6 @@ impl<'d, PIO: Instance + 'd, const SM: usize> StateMachine<'d, PIO, SM> {
|
|||||||
w.set_fjoin_rx(!w.fjoin_rx());
|
w.set_fjoin_rx(!w.fjoin_rx());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn exec_instr(&mut self, instr: u16) {
|
pub unsafe fn exec_instr(&mut self, instr: u16) {
|
||||||
Self::this_sm().instr().write(|w| w.set_instr(instr));
|
Self::this_sm().instr().write(|w| w.set_instr(instr));
|
||||||
@ -856,11 +798,9 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
|
|||||||
if (self.instructions_used | used_mask) & mask != 0 {
|
if (self.instructions_used | used_mask) & mask != 0 {
|
||||||
return Err(addr);
|
return Err(addr);
|
||||||
}
|
}
|
||||||
unsafe {
|
|
||||||
PIO::PIO.instr_mem(addr).write(|w| {
|
PIO::PIO.instr_mem(addr).write(|w| {
|
||||||
w.set_instr_mem(instr);
|
w.set_instr_mem(instr);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
used_mask |= mask;
|
used_mask |= mask;
|
||||||
}
|
}
|
||||||
self.instructions_used |= used_mask;
|
self.instructions_used |= used_mask;
|
||||||
@ -877,17 +817,15 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) {
|
pub fn set_input_sync_bypass<'a>(&'a mut self, bypass: u32, mask: u32) {
|
||||||
unsafe {
|
|
||||||
// this can interfere with per-pin bypass functions. splitting the
|
// this can interfere with per-pin bypass functions. splitting the
|
||||||
// modification is going to be fine since nothing that relies on
|
// modification is going to be fine since nothing that relies on
|
||||||
// it can reasonably run before we finish.
|
// it can reasonably run before we finish.
|
||||||
PIO::PIO.input_sync_bypass().write_set(|w| *w = mask & bypass);
|
PIO::PIO.input_sync_bypass().write_set(|w| *w = mask & bypass);
|
||||||
PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass);
|
PIO::PIO.input_sync_bypass().write_clear(|w| *w = mask & !bypass);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_input_sync_bypass(&self) -> u32 {
|
pub fn get_input_sync_bypass(&self) -> u32 {
|
||||||
unsafe { PIO::PIO.input_sync_bypass().read() }
|
PIO::PIO.input_sync_bypass().read()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register a pin for PIO usage. Pins will be released from the PIO block
|
/// Register a pin for PIO usage. Pins will be released from the PIO block
|
||||||
@ -896,9 +834,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
|
|||||||
/// of [`Pio`] do not keep pin registrations alive.**
|
/// of [`Pio`] do not keep pin registrations alive.**
|
||||||
pub fn make_pio_pin(&mut self, pin: impl Peripheral<P = impl PioPin + 'd> + 'd) -> Pin<'d, PIO> {
|
pub fn make_pio_pin(&mut self, pin: impl Peripheral<P = impl PioPin + 'd> + 'd) -> Pin<'d, PIO> {
|
||||||
into_ref!(pin);
|
into_ref!(pin);
|
||||||
unsafe {
|
|
||||||
pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0));
|
pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0));
|
||||||
}
|
|
||||||
// we can be relaxed about this because we're &mut here and nothing is cached
|
// we can be relaxed about this because we're &mut here and nothing is cached
|
||||||
PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed);
|
PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed);
|
||||||
Pin {
|
Pin {
|
||||||
@ -916,14 +852,12 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
|
|||||||
_pio: PhantomData,
|
_pio: PhantomData,
|
||||||
};
|
};
|
||||||
f(&mut batch);
|
f(&mut batch);
|
||||||
unsafe {
|
|
||||||
PIO::PIO.ctrl().modify(|w| {
|
PIO::PIO.ctrl().modify(|w| {
|
||||||
w.set_clkdiv_restart(batch.clkdiv_restart);
|
w.set_clkdiv_restart(batch.clkdiv_restart);
|
||||||
w.set_sm_restart(batch.sm_restart);
|
w.set_sm_restart(batch.sm_restart);
|
||||||
w.set_sm_enable((w.sm_enable() & !batch.sm_enable_mask) | batch.sm_enable);
|
w.set_sm_enable((w.sm_enable() & !batch.sm_enable_mask) | batch.sm_enable);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PioBatch<'a, PIO: Instance> {
|
pub struct PioBatch<'a, PIO: Instance> {
|
||||||
@ -974,11 +908,11 @@ impl<'d, PIO: Instance> IrqFlags<'d, PIO> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_any(&self, irqs: u8) -> bool {
|
pub fn check_any(&self, irqs: u8) -> bool {
|
||||||
unsafe { PIO::PIO.irq().read().irq() & irqs != 0 }
|
PIO::PIO.irq().read().irq() & irqs != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_all(&self, irqs: u8) -> bool {
|
pub fn check_all(&self, irqs: u8) -> bool {
|
||||||
unsafe { PIO::PIO.irq().read().irq() & irqs == irqs }
|
PIO::PIO.irq().read().irq() & irqs == irqs
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&self, irq_no: usize) {
|
pub fn clear(&self, irq_no: usize) {
|
||||||
@ -987,7 +921,7 @@ impl<'d, PIO: Instance> IrqFlags<'d, PIO> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_all(&self, irqs: u8) {
|
pub fn clear_all(&self, irqs: u8) {
|
||||||
unsafe { PIO::PIO.irq().write(|w| w.set_irq(irqs)) }
|
PIO::PIO.irq().write(|w| w.set_irq(irqs))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set(&self, irq_no: usize) {
|
pub fn set(&self, irq_no: usize) {
|
||||||
@ -996,7 +930,7 @@ impl<'d, PIO: Instance> IrqFlags<'d, PIO> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_all(&self, irqs: u8) {
|
pub fn set_all(&self, irqs: u8) {
|
||||||
unsafe { PIO::PIO.irq_force().write(|w| w.set_irq_force(irqs)) }
|
PIO::PIO.irq_force().write(|w| w.set_irq_force(irqs))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1068,12 +1002,10 @@ fn on_pio_drop<PIO: Instance>() {
|
|||||||
// we only have 30 pins. don't test the other two since gpio() asserts.
|
// we only have 30 pins. don't test the other two since gpio() asserts.
|
||||||
for i in 0..30 {
|
for i in 0..30 {
|
||||||
if used_pins & (1 << i) != 0 {
|
if used_pins & (1 << i) != 0 {
|
||||||
unsafe {
|
|
||||||
pac::IO_BANK0.gpio(i).ctrl().write(|w| w.set_funcsel(null));
|
pac::IO_BANK0.gpio(i).ctrl().write(|w| w.set_funcsel(null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mod sealed {
|
mod sealed {
|
||||||
|
@ -71,7 +71,6 @@ impl<'d, T: Channel> Pwm<'d, T> {
|
|||||||
into_ref!(inner);
|
into_ref!(inner);
|
||||||
|
|
||||||
let p = inner.regs();
|
let p = inner.regs();
|
||||||
unsafe {
|
|
||||||
p.csr().modify(|w| {
|
p.csr().modify(|w| {
|
||||||
w.set_divmode(divmode);
|
w.set_divmode(divmode);
|
||||||
w.set_en(false);
|
w.set_en(false);
|
||||||
@ -85,7 +84,6 @@ impl<'d, T: Channel> Pwm<'d, T> {
|
|||||||
if let Some(pin) = &b {
|
if let Some(pin) = &b {
|
||||||
pin.io().ctrl().write(|w| w.set_funcsel(4));
|
pin.io().ctrl().write(|w| w.set_funcsel(4));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Self {
|
Self {
|
||||||
inner,
|
inner,
|
||||||
pin_a: a.into(),
|
pin_a: a.into(),
|
||||||
@ -161,7 +159,6 @@ impl<'d, T: Channel> Pwm<'d, T> {
|
|||||||
panic!("Requested divider is too large");
|
panic!("Requested divider is too large");
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
|
||||||
p.div().write_value(ChDiv(config.divider.to_bits() as u32));
|
p.div().write_value(ChDiv(config.divider.to_bits() as u32));
|
||||||
p.cc().write(|w| {
|
p.cc().write(|w| {
|
||||||
w.set_a(config.compare_a);
|
w.set_a(config.compare_a);
|
||||||
@ -175,17 +172,16 @@ impl<'d, T: Channel> Pwm<'d, T> {
|
|||||||
w.set_en(config.enable);
|
w.set_en(config.enable);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn phase_advance(&mut self) {
|
pub fn phase_advance(&mut self) {
|
||||||
let p = self.inner.regs();
|
let p = self.inner.regs();
|
||||||
p.csr().write_set(|w| w.set_ph_adv(true));
|
p.csr().write_set(|w| w.set_ph_adv(true));
|
||||||
while p.csr().read().ph_adv() {}
|
while p.csr().read().ph_adv() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn phase_retard(&mut self) {
|
pub fn phase_retard(&mut self) {
|
||||||
let p = self.inner.regs();
|
let p = self.inner.regs();
|
||||||
p.csr().write_set(|w| w.set_ph_ret(true));
|
p.csr().write_set(|w| w.set_ph_ret(true));
|
||||||
while p.csr().read().ph_ret() {}
|
while p.csr().read().ph_ret() {}
|
||||||
@ -193,12 +189,12 @@ impl<'d, T: Channel> Pwm<'d, T> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn counter(&self) -> u16 {
|
pub fn counter(&self) -> u16 {
|
||||||
unsafe { self.inner.regs().ctr().read().ctr() }
|
self.inner.regs().ctr().read().ctr()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_counter(&self, ctr: u16) {
|
pub fn set_counter(&self, ctr: u16) {
|
||||||
unsafe { self.inner.regs().ctr().write(|w| w.set_ctr(ctr)) }
|
self.inner.regs().ctr().write(|w| w.set_ctr(ctr))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -209,15 +205,13 @@ impl<'d, T: Channel> Pwm<'d, T> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn wrapped(&mut self) -> bool {
|
pub fn wrapped(&mut self) -> bool {
|
||||||
unsafe { pac::PWM.intr().read().0 & self.bit() != 0 }
|
pac::PWM.intr().read().0 & self.bit() != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn clear_wrapped(&mut self) {
|
pub fn clear_wrapped(&mut self) {
|
||||||
unsafe {
|
|
||||||
pac::PWM.intr().write_value(Intr(self.bit() as _));
|
pac::PWM.intr().write_value(Intr(self.bit() as _));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn bit(&self) -> u32 {
|
fn bit(&self) -> u32 {
|
||||||
@ -237,19 +231,16 @@ impl PwmBatch {
|
|||||||
pub fn set_enabled(enabled: bool, batch: impl FnOnce(&mut PwmBatch)) {
|
pub fn set_enabled(enabled: bool, batch: impl FnOnce(&mut PwmBatch)) {
|
||||||
let mut en = PwmBatch(0);
|
let mut en = PwmBatch(0);
|
||||||
batch(&mut en);
|
batch(&mut en);
|
||||||
unsafe {
|
|
||||||
if enabled {
|
if enabled {
|
||||||
pac::PWM.en().write_set(|w| w.0 = en.0);
|
pac::PWM.en().write_set(|w| w.0 = en.0);
|
||||||
} else {
|
} else {
|
||||||
pac::PWM.en().write_clear(|w| w.0 = en.0);
|
pac::PWM.en().write_clear(|w| w.0 = en.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Channel> Drop for Pwm<'d, T> {
|
impl<'d, T: Channel> Drop for Pwm<'d, T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
|
||||||
self.inner.regs().csr().write_clear(|w| w.set_en(false));
|
self.inner.regs().csr().write_clear(|w| w.set_en(false));
|
||||||
if let Some(pin) = &self.pin_a {
|
if let Some(pin) = &self.pin_a {
|
||||||
pin.io().ctrl().write(|w| w.set_funcsel(31));
|
pin.io().ctrl().write(|w| w.set_funcsel(31));
|
||||||
@ -258,7 +249,6 @@ impl<'d, T: Channel> Drop for Pwm<'d, T> {
|
|||||||
pin.io().ctrl().write(|w| w.set_funcsel(31));
|
pin.io().ctrl().write(|w| w.set_funcsel(31));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mod sealed {
|
mod sealed {
|
||||||
|
@ -4,11 +4,11 @@ use crate::pac;
|
|||||||
|
|
||||||
pub const ALL_PERIPHERALS: Peripherals = Peripherals(0x01ffffff);
|
pub const ALL_PERIPHERALS: Peripherals = Peripherals(0x01ffffff);
|
||||||
|
|
||||||
pub unsafe fn reset(peris: Peripherals) {
|
pub(crate) fn reset(peris: Peripherals) {
|
||||||
pac::RESETS.reset().write_value(peris);
|
pac::RESETS.reset().write_value(peris);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn unreset_wait(peris: Peripherals) {
|
pub(crate) fn unreset_wait(peris: Peripherals) {
|
||||||
// TODO use the "atomic clear" register version
|
// TODO use the "atomic clear" register version
|
||||||
pac::RESETS.reset().modify(|v| *v = Peripherals(v.0 & !peris.0));
|
pac::RESETS.reset().modify(|v| *v = Peripherals(v.0 & !peris.0));
|
||||||
while ((!pac::RESETS.reset_done().read().0) & peris.0) != 0 {}
|
while ((!pac::RESETS.reset_done().read().0) & peris.0) != 0 {}
|
||||||
|
@ -26,7 +26,7 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
|
|||||||
into_ref!(inner);
|
into_ref!(inner);
|
||||||
|
|
||||||
// Set the RTC divider
|
// Set the RTC divider
|
||||||
unsafe { inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1)) };
|
inner.regs().clkdiv_m1().write(|w| w.set_clkdiv_m1(clk_rtc_freq() - 1));
|
||||||
|
|
||||||
let mut result = Self { inner };
|
let mut result = Self { inner };
|
||||||
result.set_leap_year_check(true); // should be on by default, make sure this is the case.
|
result.set_leap_year_check(true); // should be on by default, make sure this is the case.
|
||||||
@ -38,17 +38,14 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
|
|||||||
///
|
///
|
||||||
/// Leap year checking is enabled by default.
|
/// Leap year checking is enabled by default.
|
||||||
pub fn set_leap_year_check(&mut self, leap_year_check_enabled: bool) {
|
pub fn set_leap_year_check(&mut self, leap_year_check_enabled: bool) {
|
||||||
unsafe {
|
self.inner.regs().ctrl().modify(|w| {
|
||||||
self.inner
|
w.set_force_notleapyear(!leap_year_check_enabled);
|
||||||
.regs()
|
});
|
||||||
.ctrl()
|
|
||||||
.modify(|w| w.set_force_notleapyear(!leap_year_check_enabled))
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks to see if this RealTimeClock is running
|
/// Checks to see if this RealTimeClock is running
|
||||||
pub fn is_running(&self) -> bool {
|
pub fn is_running(&self) -> bool {
|
||||||
unsafe { self.inner.regs().ctrl().read().rtc_active() }
|
self.inner.regs().ctrl().read().rtc_active()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the datetime to a new value.
|
/// Set the datetime to a new value.
|
||||||
@ -60,7 +57,6 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
|
|||||||
self::datetime::validate_datetime(&t).map_err(RtcError::InvalidDateTime)?;
|
self::datetime::validate_datetime(&t).map_err(RtcError::InvalidDateTime)?;
|
||||||
|
|
||||||
// disable RTC while we configure it
|
// disable RTC while we configure it
|
||||||
unsafe {
|
|
||||||
self.inner.regs().ctrl().modify(|w| w.set_rtc_enable(false));
|
self.inner.regs().ctrl().modify(|w| w.set_rtc_enable(false));
|
||||||
while self.inner.regs().ctrl().read().rtc_active() {
|
while self.inner.regs().ctrl().read().rtc_active() {
|
||||||
core::hint::spin_loop();
|
core::hint::spin_loop();
|
||||||
@ -79,7 +75,6 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
|
|||||||
while !self.inner.regs().ctrl().read().rtc_active() {
|
while !self.inner.regs().ctrl().read().rtc_active() {
|
||||||
core::hint::spin_loop();
|
core::hint::spin_loop();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,8 +88,8 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
|
|||||||
return Err(RtcError::NotRunning);
|
return Err(RtcError::NotRunning);
|
||||||
}
|
}
|
||||||
|
|
||||||
let rtc_0 = unsafe { self.inner.regs().rtc_0().read() };
|
let rtc_0 = self.inner.regs().rtc_0().read();
|
||||||
let rtc_1 = unsafe { self.inner.regs().rtc_1().read() };
|
let rtc_1 = self.inner.regs().rtc_1().read();
|
||||||
|
|
||||||
self::datetime::datetime_from_registers(rtc_0, rtc_1).map_err(RtcError::InvalidDateTime)
|
self::datetime::datetime_from_registers(rtc_0, rtc_1).map_err(RtcError::InvalidDateTime)
|
||||||
}
|
}
|
||||||
@ -103,14 +98,12 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
|
|||||||
///
|
///
|
||||||
/// [`schedule_alarm`]: #method.schedule_alarm
|
/// [`schedule_alarm`]: #method.schedule_alarm
|
||||||
pub fn disable_alarm(&mut self) {
|
pub fn disable_alarm(&mut self) {
|
||||||
unsafe {
|
|
||||||
self.inner.regs().irq_setup_0().modify(|s| s.set_match_ena(false));
|
self.inner.regs().irq_setup_0().modify(|s| s.set_match_ena(false));
|
||||||
|
|
||||||
while self.inner.regs().irq_setup_0().read().match_active() {
|
while self.inner.regs().irq_setup_0().read().match_active() {
|
||||||
core::hint::spin_loop();
|
core::hint::spin_loop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Schedule an alarm. The `filter` determines at which point in time this alarm is set.
|
/// Schedule an alarm. The `filter` determines at which point in time this alarm is set.
|
||||||
///
|
///
|
||||||
@ -132,7 +125,6 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
|
|||||||
pub fn schedule_alarm(&mut self, filter: DateTimeFilter) {
|
pub fn schedule_alarm(&mut self, filter: DateTimeFilter) {
|
||||||
self.disable_alarm();
|
self.disable_alarm();
|
||||||
|
|
||||||
unsafe {
|
|
||||||
self.inner.regs().irq_setup_0().write(|w| {
|
self.inner.regs().irq_setup_0().write(|w| {
|
||||||
filter.write_setup_0(w);
|
filter.write_setup_0(w);
|
||||||
});
|
});
|
||||||
@ -148,7 +140,6 @@ impl<'d, T: Instance> RealTimeClock<'d, T> {
|
|||||||
core::hint::spin_loop();
|
core::hint::spin_loop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Clear the interrupt. This should be called every time the `RTC_IRQ` interrupt is triggered,
|
/// Clear the interrupt. This should be called every time the `RTC_IRQ` interrupt is triggered,
|
||||||
/// or the next [`schedule_alarm`] will never fire.
|
/// or the next [`schedule_alarm`] will never fire.
|
||||||
|
@ -79,7 +79,6 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(inner);
|
into_ref!(inner);
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let p = inner.regs();
|
let p = inner.regs();
|
||||||
let (presc, postdiv) = calc_prescs(config.frequency);
|
let (presc, postdiv) = calc_prescs(config.frequency);
|
||||||
|
|
||||||
@ -90,10 +89,16 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
|
|||||||
w.set_sph(config.phase == Phase::CaptureOnSecondTransition);
|
w.set_sph(config.phase == Phase::CaptureOnSecondTransition);
|
||||||
w.set_scr(postdiv);
|
w.set_scr(postdiv);
|
||||||
});
|
});
|
||||||
p.cr1().write(|w| {
|
|
||||||
w.set_sse(true); // enable
|
// Always enable DREQ signals -- harmless if DMA is not listening
|
||||||
|
p.dmacr().write(|reg| {
|
||||||
|
reg.set_rxdmae(true);
|
||||||
|
reg.set_txdmae(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// finally, enable.
|
||||||
|
p.cr1().write(|w| w.set_sse(true));
|
||||||
|
|
||||||
if let Some(pin) = &clk {
|
if let Some(pin) = &clk {
|
||||||
pin.io().ctrl().write(|w| w.set_funcsel(1));
|
pin.io().ctrl().write(|w| w.set_funcsel(1));
|
||||||
}
|
}
|
||||||
@ -106,7 +111,6 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
|
|||||||
if let Some(pin) = &cs {
|
if let Some(pin) = &cs {
|
||||||
pin.io().ctrl().write(|w| w.set_funcsel(1));
|
pin.io().ctrl().write(|w| w.set_funcsel(1));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Self {
|
Self {
|
||||||
inner,
|
inner,
|
||||||
tx_dma,
|
tx_dma,
|
||||||
@ -116,7 +120,6 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> {
|
pub fn blocking_write(&mut self, data: &[u8]) -> Result<(), Error> {
|
||||||
unsafe {
|
|
||||||
let p = self.inner.regs();
|
let p = self.inner.regs();
|
||||||
for &b in data {
|
for &b in data {
|
||||||
while !p.sr().read().tnf() {}
|
while !p.sr().read().tnf() {}
|
||||||
@ -124,13 +127,11 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
|
|||||||
while !p.sr().read().rne() {}
|
while !p.sr().read().rne() {}
|
||||||
let _ = p.dr().read();
|
let _ = p.dr().read();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
self.flush()?;
|
self.flush()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> {
|
pub fn blocking_transfer_in_place(&mut self, data: &mut [u8]) -> Result<(), Error> {
|
||||||
unsafe {
|
|
||||||
let p = self.inner.regs();
|
let p = self.inner.regs();
|
||||||
for b in data {
|
for b in data {
|
||||||
while !p.sr().read().tnf() {}
|
while !p.sr().read().tnf() {}
|
||||||
@ -138,13 +139,11 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
|
|||||||
while !p.sr().read().rne() {}
|
while !p.sr().read().rne() {}
|
||||||
*b = p.dr().read().data() as u8;
|
*b = p.dr().read().data() as u8;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
self.flush()?;
|
self.flush()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> {
|
pub fn blocking_read(&mut self, data: &mut [u8]) -> Result<(), Error> {
|
||||||
unsafe {
|
|
||||||
let p = self.inner.regs();
|
let p = self.inner.regs();
|
||||||
for b in data {
|
for b in data {
|
||||||
while !p.sr().read().tnf() {}
|
while !p.sr().read().tnf() {}
|
||||||
@ -152,13 +151,11 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
|
|||||||
while !p.sr().read().rne() {}
|
while !p.sr().read().rne() {}
|
||||||
*b = p.dr().read().data() as u8;
|
*b = p.dr().read().data() as u8;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
self.flush()?;
|
self.flush()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
|
pub fn blocking_transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Error> {
|
||||||
unsafe {
|
|
||||||
let p = self.inner.regs();
|
let p = self.inner.regs();
|
||||||
let len = read.len().max(write.len());
|
let len = read.len().max(write.len());
|
||||||
for i in 0..len {
|
for i in 0..len {
|
||||||
@ -171,23 +168,19 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
|
|||||||
*r = rb;
|
*r = rb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
self.flush()?;
|
self.flush()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn flush(&mut self) -> Result<(), Error> {
|
pub fn flush(&mut self) -> Result<(), Error> {
|
||||||
unsafe {
|
|
||||||
let p = self.inner.regs();
|
let p = self.inner.regs();
|
||||||
while p.sr().read().bsy() {}
|
while p.sr().read().bsy() {}
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_frequency(&mut self, freq: u32) {
|
pub fn set_frequency(&mut self, freq: u32) {
|
||||||
let (presc, postdiv) = calc_prescs(freq);
|
let (presc, postdiv) = calc_prescs(freq);
|
||||||
let p = self.inner.regs();
|
let p = self.inner.regs();
|
||||||
unsafe {
|
|
||||||
// disable
|
// disable
|
||||||
p.cr1().write(|w| w.set_sse(false));
|
p.cr1().write(|w| w.set_sse(false));
|
||||||
|
|
||||||
@ -200,7 +193,6 @@ impl<'d, T: Instance, M: Mode> Spi<'d, T, M> {
|
|||||||
// enable
|
// enable
|
||||||
p.cr1().write(|w| w.set_sse(true));
|
p.cr1().write(|w| w.set_sse(true));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> Spi<'d, T, Blocking> {
|
impl<'d, T: Instance> Spi<'d, T, Blocking> {
|
||||||
@ -329,17 +321,13 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
|
|||||||
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||||
let tx_ch = self.tx_dma.as_mut().unwrap();
|
let tx_ch = self.tx_dma.as_mut().unwrap();
|
||||||
let tx_transfer = unsafe {
|
let tx_transfer = unsafe {
|
||||||
self.inner.regs().dmacr().modify(|reg| {
|
|
||||||
reg.set_txdmae(true);
|
|
||||||
});
|
|
||||||
// If we don't assign future to a variable, the data register pointer
|
// If we don't assign future to a variable, the data register pointer
|
||||||
// is held across an await and makes the future non-Send.
|
// is held across an await and makes the future non-Send.
|
||||||
crate::dma::write(tx_ch, buffer, self.inner.regs().dr().ptr() as *mut _, T::TX_DREQ)
|
crate::dma::write(tx_ch, buffer, self.inner.regs().dr().as_ptr() as *mut _, T::TX_DREQ)
|
||||||
};
|
};
|
||||||
tx_transfer.await;
|
tx_transfer.await;
|
||||||
|
|
||||||
let p = self.inner.regs();
|
let p = self.inner.regs();
|
||||||
unsafe {
|
|
||||||
while p.sr().read().bsy() {}
|
while p.sr().read().bsy() {}
|
||||||
|
|
||||||
// clear RX FIFO contents to prevent stale reads
|
// clear RX FIFO contents to prevent stale reads
|
||||||
@ -348,29 +336,30 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
|
|||||||
}
|
}
|
||||||
// clear RX overrun interrupt
|
// clear RX overrun interrupt
|
||||||
p.icr().write(|w| w.set_roric(true));
|
p.icr().write(|w| w.set_roric(true));
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
|
||||||
unsafe {
|
// Start RX first. Transfer starts when TX starts, if RX
|
||||||
self.inner.regs().dmacr().write(|reg| {
|
// is not started yet we might lose bytes.
|
||||||
reg.set_rxdmae(true);
|
|
||||||
reg.set_txdmae(true);
|
|
||||||
})
|
|
||||||
};
|
|
||||||
let tx_ch = self.tx_dma.as_mut().unwrap();
|
|
||||||
let tx_transfer = unsafe {
|
|
||||||
// If we don't assign future to a variable, the data register pointer
|
|
||||||
// is held across an await and makes the future non-Send.
|
|
||||||
crate::dma::write_repeated(tx_ch, self.inner.regs().dr().ptr() as *mut u8, buffer.len(), T::TX_DREQ)
|
|
||||||
};
|
|
||||||
let rx_ch = self.rx_dma.as_mut().unwrap();
|
let rx_ch = self.rx_dma.as_mut().unwrap();
|
||||||
let rx_transfer = unsafe {
|
let rx_transfer = unsafe {
|
||||||
// If we don't assign future to a variable, the data register pointer
|
// If we don't assign future to a variable, the data register pointer
|
||||||
// is held across an await and makes the future non-Send.
|
// is held across an await and makes the future non-Send.
|
||||||
crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, buffer, T::RX_DREQ)
|
crate::dma::read(rx_ch, self.inner.regs().dr().as_ptr() as *const _, buffer, T::RX_DREQ)
|
||||||
|
};
|
||||||
|
|
||||||
|
let tx_ch = self.tx_dma.as_mut().unwrap();
|
||||||
|
let tx_transfer = unsafe {
|
||||||
|
// If we don't assign future to a variable, the data register pointer
|
||||||
|
// is held across an await and makes the future non-Send.
|
||||||
|
crate::dma::write_repeated(
|
||||||
|
tx_ch,
|
||||||
|
self.inner.regs().dr().as_ptr() as *mut u8,
|
||||||
|
buffer.len(),
|
||||||
|
T::TX_DREQ,
|
||||||
|
)
|
||||||
};
|
};
|
||||||
join(tx_transfer, rx_transfer).await;
|
join(tx_transfer, rx_transfer).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -388,11 +377,13 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
|
|||||||
let (_, tx_len) = crate::dma::slice_ptr_parts(tx_ptr);
|
let (_, tx_len) = crate::dma::slice_ptr_parts(tx_ptr);
|
||||||
let (_, rx_len) = crate::dma::slice_ptr_parts_mut(rx_ptr);
|
let (_, rx_len) = crate::dma::slice_ptr_parts_mut(rx_ptr);
|
||||||
|
|
||||||
unsafe {
|
// Start RX first. Transfer starts when TX starts, if RX
|
||||||
self.inner.regs().dmacr().write(|reg| {
|
// is not started yet we might lose bytes.
|
||||||
reg.set_rxdmae(true);
|
let rx_ch = self.rx_dma.as_mut().unwrap();
|
||||||
reg.set_txdmae(true);
|
let rx_transfer = unsafe {
|
||||||
})
|
// If we don't assign future to a variable, the data register pointer
|
||||||
|
// is held across an await and makes the future non-Send.
|
||||||
|
crate::dma::read(rx_ch, self.inner.regs().dr().as_ptr() as *const _, rx_ptr, T::RX_DREQ)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut tx_ch = self.tx_dma.as_mut().unwrap();
|
let mut tx_ch = self.tx_dma.as_mut().unwrap();
|
||||||
@ -401,29 +392,21 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
|
|||||||
let tx_transfer = async {
|
let tx_transfer = async {
|
||||||
let p = self.inner.regs();
|
let p = self.inner.regs();
|
||||||
unsafe {
|
unsafe {
|
||||||
crate::dma::write(&mut tx_ch, tx_ptr, p.dr().ptr() as *mut _, T::TX_DREQ).await;
|
crate::dma::write(&mut tx_ch, tx_ptr, p.dr().as_ptr() as *mut _, T::TX_DREQ).await;
|
||||||
|
|
||||||
if rx_len > tx_len {
|
if rx_len > tx_len {
|
||||||
let write_bytes_len = rx_len - tx_len;
|
let write_bytes_len = rx_len - tx_len;
|
||||||
// write dummy data
|
// write dummy data
|
||||||
// this will disable incrementation of the buffers
|
// this will disable incrementation of the buffers
|
||||||
crate::dma::write_repeated(tx_ch, p.dr().ptr() as *mut u8, write_bytes_len, T::TX_DREQ).await
|
crate::dma::write_repeated(tx_ch, p.dr().as_ptr() as *mut u8, write_bytes_len, T::TX_DREQ).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let rx_ch = self.rx_dma.as_mut().unwrap();
|
|
||||||
let rx_transfer = unsafe {
|
|
||||||
// If we don't assign future to a variable, the data register pointer
|
|
||||||
// is held across an await and makes the future non-Send.
|
|
||||||
crate::dma::read(rx_ch, self.inner.regs().dr().ptr() as *const _, rx_ptr, T::RX_DREQ)
|
|
||||||
};
|
|
||||||
join(tx_transfer, rx_transfer).await;
|
join(tx_transfer, rx_transfer).await;
|
||||||
|
|
||||||
// if tx > rx we should clear any overflow of the FIFO SPI buffer
|
// if tx > rx we should clear any overflow of the FIFO SPI buffer
|
||||||
if tx_len > rx_len {
|
if tx_len > rx_len {
|
||||||
let p = self.inner.regs();
|
let p = self.inner.regs();
|
||||||
unsafe {
|
|
||||||
while p.sr().read().bsy() {}
|
while p.sr().read().bsy() {}
|
||||||
|
|
||||||
// clear RX FIFO contents to prevent stale reads
|
// clear RX FIFO contents to prevent stale reads
|
||||||
@ -433,7 +416,6 @@ impl<'d, T: Instance> Spi<'d, T, Async> {
|
|||||||
// clear RX overrun interrupt
|
// clear RX overrun interrupt
|
||||||
p.icr().write(|w| w.set_roric(true));
|
p.icr().write(|w| w.set_roric(true));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -630,7 +612,6 @@ impl<'d, T: Instance, M: Mode> SetConfig for Spi<'d, T, M> {
|
|||||||
fn set_config(&mut self, config: &Self::Config) {
|
fn set_config(&mut self, config: &Self::Config) {
|
||||||
let p = self.inner.regs();
|
let p = self.inner.regs();
|
||||||
let (presc, postdiv) = calc_prescs(config.frequency);
|
let (presc, postdiv) = calc_prescs(config.frequency);
|
||||||
unsafe {
|
|
||||||
p.cpsr().write(|w| w.set_cpsdvsr(presc));
|
p.cpsr().write(|w| w.set_cpsdvsr(presc));
|
||||||
p.cr0().write(|w| {
|
p.cr0().write(|w| {
|
||||||
w.set_dss(0b0111); // 8bit
|
w.set_dss(0b0111); // 8bit
|
||||||
@ -639,5 +620,4 @@ impl<'d, T: Instance, M: Mode> SetConfig for Spi<'d, T, M> {
|
|||||||
w.set_scr(postdiv);
|
w.set_scr(postdiv);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
|||||||
use embassy_sync::blocking_mutex::Mutex;
|
use embassy_sync::blocking_mutex::Mutex;
|
||||||
use embassy_time::driver::{AlarmHandle, Driver};
|
use embassy_time::driver::{AlarmHandle, Driver};
|
||||||
|
|
||||||
use crate::interrupt::{Interrupt, InterruptExt};
|
use crate::interrupt::InterruptExt;
|
||||||
use crate::{interrupt, pac};
|
use crate::{interrupt, pac};
|
||||||
|
|
||||||
struct AlarmState {
|
struct AlarmState {
|
||||||
@ -34,7 +34,6 @@ embassy_time::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{
|
|||||||
impl Driver for TimerDriver {
|
impl Driver for TimerDriver {
|
||||||
fn now(&self) -> u64 {
|
fn now(&self) -> u64 {
|
||||||
loop {
|
loop {
|
||||||
unsafe {
|
|
||||||
let hi = pac::TIMER.timerawh().read();
|
let hi = pac::TIMER.timerawh().read();
|
||||||
let lo = pac::TIMER.timerawl().read();
|
let lo = pac::TIMER.timerawl().read();
|
||||||
let hi2 = pac::TIMER.timerawh().read();
|
let hi2 = pac::TIMER.timerawh().read();
|
||||||
@ -43,7 +42,6 @@ impl Driver for TimerDriver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
|
unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
|
||||||
let id = self.next_alarm.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
|
let id = self.next_alarm.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
|
||||||
@ -78,13 +76,13 @@ impl Driver for TimerDriver {
|
|||||||
// Note that we're not checking the high bits at all. This means the irq may fire early
|
// Note that we're not checking the high bits at all. This means the irq may fire early
|
||||||
// if the alarm is more than 72 minutes (2^32 us) in the future. This is OK, since on irq fire
|
// if the alarm is more than 72 minutes (2^32 us) in the future. This is OK, since on irq fire
|
||||||
// it is checked if the alarm time has passed.
|
// it is checked if the alarm time has passed.
|
||||||
unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) };
|
pac::TIMER.alarm(n).write_value(timestamp as u32);
|
||||||
|
|
||||||
let now = self.now();
|
let now = self.now();
|
||||||
if timestamp <= now {
|
if timestamp <= now {
|
||||||
// If alarm timestamp has passed the alarm will not fire.
|
// If alarm timestamp has passed the alarm will not fire.
|
||||||
// Disarm the alarm and return `false` to indicate that.
|
// Disarm the alarm and return `false` to indicate that.
|
||||||
unsafe { pac::TIMER.armed().write(|w| w.set_armed(1 << n)) }
|
pac::TIMER.armed().write(|w| w.set_armed(1 << n));
|
||||||
|
|
||||||
alarm.timestamp.set(u64::MAX);
|
alarm.timestamp.set(u64::MAX);
|
||||||
|
|
||||||
@ -106,17 +104,17 @@ impl TimerDriver {
|
|||||||
} else {
|
} else {
|
||||||
// Not elapsed, arm it again.
|
// Not elapsed, arm it again.
|
||||||
// This can happen if it was set more than 2^32 us in the future.
|
// This can happen if it was set more than 2^32 us in the future.
|
||||||
unsafe { pac::TIMER.alarm(n).write_value(timestamp as u32) };
|
pac::TIMER.alarm(n).write_value(timestamp as u32);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// clear the irq
|
// clear the irq
|
||||||
unsafe { pac::TIMER.intr().write(|w| w.set_alarm(n, true)) }
|
pac::TIMER.intr().write(|w| w.set_alarm(n, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trigger_alarm(&self, n: usize, cs: CriticalSection) {
|
fn trigger_alarm(&self, n: usize, cs: CriticalSection) {
|
||||||
// disarm
|
// disarm
|
||||||
unsafe { pac::TIMER.armed().write(|w| w.set_armed(1 << n)) }
|
pac::TIMER.armed().write(|w| w.set_armed(1 << n));
|
||||||
|
|
||||||
let alarm = &self.alarms.borrow(cs)[n];
|
let alarm = &self.alarms.borrow(cs)[n];
|
||||||
alarm.timestamp.set(u64::MAX);
|
alarm.timestamp.set(u64::MAX);
|
||||||
@ -145,28 +143,32 @@ pub unsafe fn init() {
|
|||||||
w.set_alarm(2, true);
|
w.set_alarm(2, true);
|
||||||
w.set_alarm(3, true);
|
w.set_alarm(3, true);
|
||||||
});
|
});
|
||||||
interrupt::TIMER_IRQ_0::steal().enable();
|
interrupt::TIMER_IRQ_0.enable();
|
||||||
interrupt::TIMER_IRQ_1::steal().enable();
|
interrupt::TIMER_IRQ_1.enable();
|
||||||
interrupt::TIMER_IRQ_2::steal().enable();
|
interrupt::TIMER_IRQ_2.enable();
|
||||||
interrupt::TIMER_IRQ_3::steal().enable();
|
interrupt::TIMER_IRQ_3.enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rt")]
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
unsafe fn TIMER_IRQ_0() {
|
fn TIMER_IRQ_0() {
|
||||||
DRIVER.check_alarm(0)
|
DRIVER.check_alarm(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rt")]
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
unsafe fn TIMER_IRQ_1() {
|
fn TIMER_IRQ_1() {
|
||||||
DRIVER.check_alarm(1)
|
DRIVER.check_alarm(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rt")]
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
unsafe fn TIMER_IRQ_2() {
|
fn TIMER_IRQ_2() {
|
||||||
DRIVER.check_alarm(2)
|
DRIVER.check_alarm(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "rt")]
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
unsafe fn TIMER_IRQ_3() {
|
fn TIMER_IRQ_3() {
|
||||||
DRIVER.check_alarm(3)
|
DRIVER.check_alarm(3)
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,14 @@ use core::slice;
|
|||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use atomic_polyfill::{AtomicU8, Ordering};
|
use atomic_polyfill::{AtomicU8, Ordering};
|
||||||
use embassy_cortex_m::interrupt::{self, Binding, Interrupt, InterruptExt};
|
|
||||||
use embassy_hal_common::atomic_ring_buffer::RingBuffer;
|
use embassy_hal_common::atomic_ring_buffer::RingBuffer;
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::clocks::clk_peri_freq;
|
use crate::clocks::clk_peri_freq;
|
||||||
use crate::RegExt;
|
use crate::interrupt::typelevel::{Binding, Interrupt};
|
||||||
|
use crate::{interrupt, RegExt};
|
||||||
|
|
||||||
pub struct State {
|
pub struct State {
|
||||||
tx_waker: AtomicWaker,
|
tx_waker: AtomicWaker,
|
||||||
@ -73,16 +73,14 @@ pub(crate) fn init_buffers<'d, T: Instance + 'd>(
|
|||||||
// we clear it after it happens. The downside is that the we manually have
|
// we clear it after it happens. The downside is that the we manually have
|
||||||
// to pend the ISR when we want data transmission to start.
|
// to pend the ISR when we want data transmission to start.
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
unsafe {
|
|
||||||
regs.uartimsc().write(|w| {
|
regs.uartimsc().write(|w| {
|
||||||
w.set_rxim(true);
|
w.set_rxim(true);
|
||||||
w.set_rtim(true);
|
w.set_rtim(true);
|
||||||
w.set_txim(true);
|
w.set_txim(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
T::Interrupt::steal().unpend();
|
T::Interrupt::unpend();
|
||||||
T::Interrupt::steal().enable();
|
unsafe { T::Interrupt::enable() };
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> BufferedUart<'d, T> {
|
impl<'d, T: Instance> BufferedUart<'d, T> {
|
||||||
@ -247,12 +245,10 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
|
|||||||
// (Re-)Enable the interrupt to receive more data in case it was
|
// (Re-)Enable the interrupt to receive more data in case it was
|
||||||
// disabled because the buffer was full or errors were detected.
|
// disabled because the buffer was full or errors were detected.
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
unsafe {
|
|
||||||
regs.uartimsc().write_set(|w| {
|
regs.uartimsc().write_set(|w| {
|
||||||
w.set_rxim(true);
|
w.set_rxim(true);
|
||||||
w.set_rtim(true);
|
w.set_rtim(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Poll::Ready(result)
|
Poll::Ready(result)
|
||||||
}
|
}
|
||||||
@ -299,13 +295,11 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
|
|||||||
// (Re-)Enable the interrupt to receive more data in case it was
|
// (Re-)Enable the interrupt to receive more data in case it was
|
||||||
// disabled because the buffer was full or errors were detected.
|
// disabled because the buffer was full or errors were detected.
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
unsafe {
|
|
||||||
regs.uartimsc().write_set(|w| {
|
regs.uartimsc().write_set(|w| {
|
||||||
w.set_rxim(true);
|
w.set_rxim(true);
|
||||||
w.set_rtim(true);
|
w.set_rtim(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
||||||
@ -362,7 +356,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
|||||||
// FIFO and the number of bytes drops below a threshold. When the
|
// FIFO and the number of bytes drops below a threshold. When the
|
||||||
// FIFO was empty we have to manually pend the interrupt to shovel
|
// FIFO was empty we have to manually pend the interrupt to shovel
|
||||||
// TX data from the buffer into the FIFO.
|
// TX data from the buffer into the FIFO.
|
||||||
unsafe { T::Interrupt::steal() }.pend();
|
T::Interrupt::pend();
|
||||||
Poll::Ready(Ok(n))
|
Poll::Ready(Ok(n))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -398,7 +392,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
|||||||
// FIFO and the number of bytes drops below a threshold. When the
|
// FIFO and the number of bytes drops below a threshold. When the
|
||||||
// FIFO was empty we have to manually pend the interrupt to shovel
|
// FIFO was empty we have to manually pend the interrupt to shovel
|
||||||
// TX data from the buffer into the FIFO.
|
// TX data from the buffer into the FIFO.
|
||||||
unsafe { T::Interrupt::steal() }.pend();
|
T::Interrupt::pend();
|
||||||
return Ok(n);
|
return Ok(n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -414,7 +408,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn busy(&self) -> bool {
|
pub fn busy(&self) -> bool {
|
||||||
unsafe { T::regs().uartfr().read().busy() }
|
T::regs().uartfr().read().busy()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Assert a break condition after waiting for the transmit buffers to empty,
|
/// Assert a break condition after waiting for the transmit buffers to empty,
|
||||||
@ -426,42 +420,35 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
|||||||
/// for the transmit fifo to empty, which may take a while on slow links.
|
/// for the transmit fifo to empty, which may take a while on slow links.
|
||||||
pub async fn send_break(&mut self, bits: u32) {
|
pub async fn send_break(&mut self, bits: u32) {
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
let bits = bits.max(unsafe {
|
let bits = bits.max({
|
||||||
let lcr = regs.uartlcr_h().read();
|
let lcr = regs.uartlcr_h().read();
|
||||||
let width = lcr.wlen() as u32 + 5;
|
let width = lcr.wlen() as u32 + 5;
|
||||||
let parity = lcr.pen() as u32;
|
let parity = lcr.pen() as u32;
|
||||||
let stops = 1 + lcr.stp2() as u32;
|
let stops = 1 + lcr.stp2() as u32;
|
||||||
2 * (1 + width + parity + stops)
|
2 * (1 + width + parity + stops)
|
||||||
});
|
});
|
||||||
let divx64 = unsafe {
|
let divx64 = (((regs.uartibrd().read().baud_divint() as u32) << 6)
|
||||||
((regs.uartibrd().read().baud_divint() as u32) << 6) + regs.uartfbrd().read().baud_divfrac() as u32
|
+ regs.uartfbrd().read().baud_divfrac() as u32) as u64;
|
||||||
} as u64;
|
|
||||||
let div_clk = clk_peri_freq() as u64 * 64;
|
let div_clk = clk_peri_freq() as u64 * 64;
|
||||||
let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk;
|
let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk;
|
||||||
|
|
||||||
Self::flush().await.unwrap();
|
Self::flush().await.unwrap();
|
||||||
while self.busy() {}
|
while self.busy() {}
|
||||||
unsafe {
|
|
||||||
regs.uartlcr_h().write_set(|w| w.set_brk(true));
|
regs.uartlcr_h().write_set(|w| w.set_brk(true));
|
||||||
}
|
|
||||||
Timer::after(Duration::from_micros(wait_usecs)).await;
|
Timer::after(Duration::from_micros(wait_usecs)).await;
|
||||||
unsafe {
|
|
||||||
regs.uartlcr_h().write_clear(|w| w.set_brk(true));
|
regs.uartlcr_h().write_clear(|w| w.set_brk(true));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> {
|
impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let state = T::buffered_state();
|
let state = T::buffered_state();
|
||||||
unsafe {
|
unsafe { state.rx_buf.deinit() }
|
||||||
state.rx_buf.deinit();
|
|
||||||
|
|
||||||
// TX is inactive if the the buffer is not available.
|
// TX is inactive if the the buffer is not available.
|
||||||
// We can now unregister the interrupt handler
|
// We can now unregister the interrupt handler
|
||||||
if state.tx_buf.len() == 0 {
|
if state.tx_buf.len() == 0 {
|
||||||
T::Interrupt::steal().disable();
|
T::Interrupt::disable();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -469,14 +456,12 @@ impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> {
|
|||||||
impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> {
|
impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let state = T::buffered_state();
|
let state = T::buffered_state();
|
||||||
unsafe {
|
unsafe { state.tx_buf.deinit() }
|
||||||
state.tx_buf.deinit();
|
|
||||||
|
|
||||||
// RX is inactive if the the buffer is not available.
|
// RX is inactive if the the buffer is not available.
|
||||||
// We can now unregister the interrupt handler
|
// We can now unregister the interrupt handler
|
||||||
if state.rx_buf.len() == 0 {
|
if state.rx_buf.len() == 0 {
|
||||||
T::Interrupt::steal().disable();
|
T::Interrupt::disable();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -485,7 +470,7 @@ pub struct BufferedInterruptHandler<T: Instance> {
|
|||||||
_uart: PhantomData<T>,
|
_uart: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for BufferedInterruptHandler<T> {
|
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterruptHandler<T> {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
if r.uartdmacr().read().rxdmae() {
|
if r.uartdmacr().read().rxdmae() {
|
||||||
@ -494,7 +479,6 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for BufferedInterruptHandler<
|
|||||||
|
|
||||||
let s = T::buffered_state();
|
let s = T::buffered_state();
|
||||||
|
|
||||||
unsafe {
|
|
||||||
// Clear TX and error interrupt flags
|
// Clear TX and error interrupt flags
|
||||||
// RX interrupt flags are cleared by reading from the FIFO.
|
// RX interrupt flags are cleared by reading from the FIFO.
|
||||||
let ris = r.uartris().read();
|
let ris = r.uartris().read();
|
||||||
@ -523,7 +507,7 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for BufferedInterruptHandler<
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RX
|
// RX
|
||||||
let mut rx_writer = s.rx_buf.writer();
|
let mut rx_writer = unsafe { s.rx_buf.writer() };
|
||||||
let rx_buf = rx_writer.push_slice();
|
let rx_buf = rx_writer.push_slice();
|
||||||
let mut n_read = 0;
|
let mut n_read = 0;
|
||||||
let mut error = false;
|
let mut error = false;
|
||||||
@ -564,7 +548,7 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for BufferedInterruptHandler<
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TX
|
// TX
|
||||||
let mut tx_reader = s.tx_buf.reader();
|
let mut tx_reader = unsafe { s.tx_buf.reader() };
|
||||||
let tx_buf = tx_reader.pop_slice();
|
let tx_buf = tx_reader.pop_slice();
|
||||||
let mut n_written = 0;
|
let mut n_written = 0;
|
||||||
for tx_byte in tx_buf.iter_mut() {
|
for tx_byte in tx_buf.iter_mut() {
|
||||||
@ -582,7 +566,6 @@ impl<T: Instance> interrupt::Handler<T::Interrupt> for BufferedInterruptHandler<
|
|||||||
// crossed. No need to disable it when the buffer becomes empty
|
// crossed. No need to disable it when the buffer becomes empty
|
||||||
// as it does re-trigger anymore once we have cleared it.
|
// as it does re-trigger anymore once we have cleared it.
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl embedded_io::Error for Error {
|
impl embedded_io::Error for Error {
|
||||||
@ -695,7 +678,6 @@ mod eh02 {
|
|||||||
|
|
||||||
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
unsafe {
|
|
||||||
if r.uartfr().read().rxfe() {
|
if r.uartfr().read().rxfe() {
|
||||||
return Err(nb::Error::WouldBlock);
|
return Err(nb::Error::WouldBlock);
|
||||||
}
|
}
|
||||||
@ -715,7 +697,6 @@ mod eh02 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for BufferedUartTx<'d, T> {
|
impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for BufferedUartTx<'d, T> {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
@ -3,7 +3,6 @@ use core::marker::PhantomData;
|
|||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use atomic_polyfill::{AtomicU16, Ordering};
|
use atomic_polyfill::{AtomicU16, Ordering};
|
||||||
use embassy_cortex_m::interrupt::{self, Binding, Interrupt, InterruptExt};
|
|
||||||
use embassy_futures::select::{select, Either};
|
use embassy_futures::select::{select, Either};
|
||||||
use embassy_hal_common::{into_ref, PeripheralRef};
|
use embassy_hal_common::{into_ref, PeripheralRef};
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
@ -14,8 +13,9 @@ use crate::clocks::clk_peri_freq;
|
|||||||
use crate::dma::{AnyChannel, Channel};
|
use crate::dma::{AnyChannel, Channel};
|
||||||
use crate::gpio::sealed::Pin;
|
use crate::gpio::sealed::Pin;
|
||||||
use crate::gpio::AnyPin;
|
use crate::gpio::AnyPin;
|
||||||
|
use crate::interrupt::typelevel::{Binding, Interrupt};
|
||||||
use crate::pac::io::vals::{Inover, Outover};
|
use crate::pac::io::vals::{Inover, Outover};
|
||||||
use crate::{pac, peripherals, Peripheral, RegExt};
|
use crate::{interrupt, pac, peripherals, Peripheral, RegExt};
|
||||||
|
|
||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
mod buffered;
|
mod buffered;
|
||||||
@ -146,23 +146,21 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
|
|||||||
|
|
||||||
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
unsafe {
|
|
||||||
for &b in buffer {
|
for &b in buffer {
|
||||||
while r.uartfr().read().txff() {}
|
while r.uartfr().read().txff() {}
|
||||||
r.uartdr().write(|w| w.set_data(b));
|
r.uartdr().write(|w| w.set_data(b));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn blocking_flush(&mut self) -> Result<(), Error> {
|
pub fn blocking_flush(&mut self) -> Result<(), Error> {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
unsafe { while !r.uartfr().read().txfe() {} }
|
while !r.uartfr().read().txfe() {}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn busy(&self) -> bool {
|
pub fn busy(&self) -> bool {
|
||||||
unsafe { T::regs().uartfr().read().busy() }
|
T::regs().uartfr().read().busy()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Assert a break condition after waiting for the transmit buffers to empty,
|
/// Assert a break condition after waiting for the transmit buffers to empty,
|
||||||
@ -174,29 +172,24 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
|
|||||||
/// for the transmit fifo to empty, which may take a while on slow links.
|
/// for the transmit fifo to empty, which may take a while on slow links.
|
||||||
pub async fn send_break(&mut self, bits: u32) {
|
pub async fn send_break(&mut self, bits: u32) {
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
let bits = bits.max(unsafe {
|
let bits = bits.max({
|
||||||
let lcr = regs.uartlcr_h().read();
|
let lcr = regs.uartlcr_h().read();
|
||||||
let width = lcr.wlen() as u32 + 5;
|
let width = lcr.wlen() as u32 + 5;
|
||||||
let parity = lcr.pen() as u32;
|
let parity = lcr.pen() as u32;
|
||||||
let stops = 1 + lcr.stp2() as u32;
|
let stops = 1 + lcr.stp2() as u32;
|
||||||
2 * (1 + width + parity + stops)
|
2 * (1 + width + parity + stops)
|
||||||
});
|
});
|
||||||
let divx64 = unsafe {
|
let divx64 = (((regs.uartibrd().read().baud_divint() as u32) << 6)
|
||||||
((regs.uartibrd().read().baud_divint() as u32) << 6) + regs.uartfbrd().read().baud_divfrac() as u32
|
+ regs.uartfbrd().read().baud_divfrac() as u32) as u64;
|
||||||
} as u64;
|
|
||||||
let div_clk = clk_peri_freq() as u64 * 64;
|
let div_clk = clk_peri_freq() as u64 * 64;
|
||||||
let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk;
|
let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk;
|
||||||
|
|
||||||
self.blocking_flush().unwrap();
|
self.blocking_flush().unwrap();
|
||||||
while self.busy() {}
|
while self.busy() {}
|
||||||
unsafe {
|
|
||||||
regs.uartlcr_h().write_set(|w| w.set_brk(true));
|
regs.uartlcr_h().write_set(|w| w.set_brk(true));
|
||||||
}
|
|
||||||
Timer::after(Duration::from_micros(wait_usecs)).await;
|
Timer::after(Duration::from_micros(wait_usecs)).await;
|
||||||
unsafe {
|
|
||||||
regs.uartlcr_h().write_clear(|w| w.set_brk(true));
|
regs.uartlcr_h().write_clear(|w| w.set_brk(true));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> UartTx<'d, T, Blocking> {
|
impl<'d, T: Instance> UartTx<'d, T, Blocking> {
|
||||||
@ -221,7 +214,7 @@ impl<'d, T: Instance> UartTx<'d, T, Async> {
|
|||||||
});
|
});
|
||||||
// If we don't assign future to a variable, the data register pointer
|
// If we don't assign future to a variable, the data register pointer
|
||||||
// is held across an await and makes the future non-Send.
|
// is held across an await and makes the future non-Send.
|
||||||
crate::dma::write(ch, buffer, T::regs().uartdr().ptr() as *mut _, T::TX_DREQ)
|
crate::dma::write(ch, buffer, T::regs().uartdr().as_ptr() as *mut _, T::TX_DREQ)
|
||||||
};
|
};
|
||||||
transfer.await;
|
transfer.await;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -245,12 +238,10 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
|
|||||||
fn new_inner(has_irq: bool, rx_dma: Option<PeripheralRef<'d, AnyChannel>>) -> Self {
|
fn new_inner(has_irq: bool, rx_dma: Option<PeripheralRef<'d, AnyChannel>>) -> Self {
|
||||||
debug_assert_eq!(has_irq, rx_dma.is_some());
|
debug_assert_eq!(has_irq, rx_dma.is_some());
|
||||||
if has_irq {
|
if has_irq {
|
||||||
unsafe {
|
|
||||||
// disable all error interrupts initially
|
// disable all error interrupts initially
|
||||||
T::regs().uartimsc().write(|w| w.0 = 0);
|
T::regs().uartimsc().write(|w| w.0 = 0);
|
||||||
T::Interrupt::steal().unpend();
|
T::Interrupt::unpend();
|
||||||
T::Interrupt::steal().enable();
|
unsafe { T::Interrupt::enable() };
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Self {
|
Self {
|
||||||
rx_dma,
|
rx_dma,
|
||||||
@ -269,11 +260,11 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
|
|||||||
fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
|
fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
for (i, b) in buffer.iter_mut().enumerate() {
|
for (i, b) in buffer.iter_mut().enumerate() {
|
||||||
if unsafe { r.uartfr().read().rxfe() } {
|
if r.uartfr().read().rxfe() {
|
||||||
return Ok(i);
|
return Ok(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
let dr = unsafe { r.uartdr().read() };
|
let dr = r.uartdr().read();
|
||||||
|
|
||||||
if dr.oe() {
|
if dr.oe() {
|
||||||
return Err(Error::Overrun);
|
return Err(Error::Overrun);
|
||||||
@ -294,8 +285,7 @@ impl<'d, T: Instance, M: Mode> UartRx<'d, T, M> {
|
|||||||
impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> {
|
impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if let Some(_) = self.rx_dma {
|
if let Some(_) = self.rx_dma {
|
||||||
unsafe {
|
T::Interrupt::disable();
|
||||||
T::Interrupt::steal().disable();
|
|
||||||
// clear dma flags. irq handlers use these to disambiguate among themselves.
|
// clear dma flags. irq handlers use these to disambiguate among themselves.
|
||||||
T::regs().uartdmacr().write_clear(|reg| {
|
T::regs().uartdmacr().write_clear(|reg| {
|
||||||
reg.set_rxdmae(true);
|
reg.set_rxdmae(true);
|
||||||
@ -304,7 +294,6 @@ impl<'d, T: Instance, M: Mode> Drop for UartRx<'d, T, M> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> UartRx<'d, T, Blocking> {
|
impl<'d, T: Instance> UartRx<'d, T, Blocking> {
|
||||||
@ -334,7 +323,7 @@ pub struct InterruptHandler<T: Instance> {
|
|||||||
_uart: PhantomData<T>,
|
_uart: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
let uart = T::regs();
|
let uart = T::regs();
|
||||||
if !uart.uartdmacr().read().rxdmae() {
|
if !uart.uartdmacr().read().rxdmae() {
|
||||||
@ -357,14 +346,12 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
|
|||||||
// clear error flags before we drain the fifo. errors that have accumulated
|
// clear error flags before we drain the fifo. errors that have accumulated
|
||||||
// in the flags will also be present in the fifo.
|
// in the flags will also be present in the fifo.
|
||||||
T::dma_state().rx_errs.store(0, Ordering::Relaxed);
|
T::dma_state().rx_errs.store(0, Ordering::Relaxed);
|
||||||
unsafe {
|
|
||||||
T::regs().uarticr().write(|w| {
|
T::regs().uarticr().write(|w| {
|
||||||
w.set_oeic(true);
|
w.set_oeic(true);
|
||||||
w.set_beic(true);
|
w.set_beic(true);
|
||||||
w.set_peic(true);
|
w.set_peic(true);
|
||||||
w.set_feic(true);
|
w.set_feic(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// then drain the fifo. we need to read at most 32 bytes. errors that apply
|
// then drain the fifo. we need to read at most 32 bytes. errors that apply
|
||||||
// to fifo bytes will be reported directly.
|
// to fifo bytes will be reported directly.
|
||||||
@ -381,7 +368,6 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
|
|||||||
// interrupt flags will have been raised, and those will be picked up immediately
|
// interrupt flags will have been raised, and those will be picked up immediately
|
||||||
// by the interrupt handler.
|
// by the interrupt handler.
|
||||||
let ch = self.rx_dma.as_mut().unwrap();
|
let ch = self.rx_dma.as_mut().unwrap();
|
||||||
let transfer = unsafe {
|
|
||||||
T::regs().uartimsc().write_set(|w| {
|
T::regs().uartimsc().write_set(|w| {
|
||||||
w.set_oeim(true);
|
w.set_oeim(true);
|
||||||
w.set_beim(true);
|
w.set_beim(true);
|
||||||
@ -392,9 +378,10 @@ impl<'d, T: Instance> UartRx<'d, T, Async> {
|
|||||||
reg.set_rxdmae(true);
|
reg.set_rxdmae(true);
|
||||||
reg.set_dmaonerr(true);
|
reg.set_dmaonerr(true);
|
||||||
});
|
});
|
||||||
|
let transfer = unsafe {
|
||||||
// If we don't assign future to a variable, the data register pointer
|
// If we don't assign future to a variable, the data register pointer
|
||||||
// is held across an await and makes the future non-Send.
|
// is held across an await and makes the future non-Send.
|
||||||
crate::dma::read(ch, T::regs().uartdr().ptr() as *const _, buffer, T::RX_DREQ)
|
crate::dma::read(ch, T::regs().uartdr().as_ptr() as *const _, buffer, T::RX_DREQ)
|
||||||
};
|
};
|
||||||
|
|
||||||
// wait for either the transfer to complete or an error to happen.
|
// wait for either the transfer to complete or an error to happen.
|
||||||
@ -577,7 +564,6 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
|
|||||||
config: Config,
|
config: Config,
|
||||||
) {
|
) {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
unsafe {
|
|
||||||
if let Some(pin) = &tx {
|
if let Some(pin) = &tx {
|
||||||
pin.io().ctrl().write(|w| {
|
pin.io().ctrl().write(|w| {
|
||||||
w.set_funcsel(2);
|
w.set_funcsel(2);
|
||||||
@ -652,7 +638,6 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
|
|||||||
w.set_rtsen(rts.is_some());
|
w.set_rtsen(rts.is_some());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// sets baudrate on runtime
|
/// sets baudrate on runtime
|
||||||
pub fn set_baudrate(&mut self, baudrate: u32) {
|
pub fn set_baudrate(&mut self, baudrate: u32) {
|
||||||
@ -676,7 +661,6 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
|
|||||||
baud_fbrd = 0;
|
baud_fbrd = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
|
||||||
// Load PL011's baud divisor registers
|
// Load PL011's baud divisor registers
|
||||||
r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd));
|
r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd));
|
||||||
r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
|
r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
|
||||||
@ -685,7 +669,6 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
|
|||||||
// divisors. We don't want to actually change LCR contents here.
|
// divisors. We don't want to actually change LCR contents here.
|
||||||
r.uartlcr_h().modify(|_| {});
|
r.uartlcr_h().modify(|_| {});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
|
impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
|
||||||
@ -733,7 +716,6 @@ mod eh02 {
|
|||||||
type Error = Error;
|
type Error = Error;
|
||||||
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
unsafe {
|
|
||||||
if r.uartfr().read().rxfe() {
|
if r.uartfr().read().rxfe() {
|
||||||
return Err(nb::Error::WouldBlock);
|
return Err(nb::Error::WouldBlock);
|
||||||
}
|
}
|
||||||
@ -753,30 +735,25 @@ mod eh02 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write<u8> for UartTx<'d, T, M> {
|
impl<'d, T: Instance, M: Mode> embedded_hal_02::serial::Write<u8> for UartTx<'d, T, M> {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::Error>> {
|
fn write(&mut self, word: u8) -> Result<(), nb::Error<Self::Error>> {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
unsafe {
|
|
||||||
if r.uartfr().read().txff() {
|
if r.uartfr().read().txff() {
|
||||||
return Err(nb::Error::WouldBlock);
|
return Err(nb::Error::WouldBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
r.uartdr().write(|w| w.set_data(word));
|
r.uartdr().write(|w| w.set_data(word));
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush(&mut self) -> Result<(), nb::Error<Self::Error>> {
|
fn flush(&mut self) -> Result<(), nb::Error<Self::Error>> {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
unsafe {
|
|
||||||
if !r.uartfr().read().txfe() {
|
if !r.uartfr().read().txfe() {
|
||||||
return Err(nb::Error::WouldBlock);
|
return Err(nb::Error::WouldBlock);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -856,7 +833,6 @@ mod eh1 {
|
|||||||
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> {
|
impl<'d, T: Instance, M: Mode> embedded_hal_nb::serial::Read for UartRx<'d, T, M> {
|
||||||
fn read(&mut self) -> nb::Result<u8, Self::Error> {
|
fn read(&mut self) -> nb::Result<u8, Self::Error> {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
unsafe {
|
|
||||||
let dr = r.uartdr().read();
|
let dr = r.uartdr().read();
|
||||||
|
|
||||||
if dr.oe() {
|
if dr.oe() {
|
||||||
@ -874,7 +850,6 @@ mod eh1 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::Write for UartTx<'d, T, M> {
|
impl<'d, T: Instance, M: Mode> embedded_hal_1::serial::Write for UartTx<'d, T, M> {
|
||||||
fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
|
fn write(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
|
||||||
@ -932,7 +907,7 @@ mod sealed {
|
|||||||
const TX_DREQ: u8;
|
const TX_DREQ: u8;
|
||||||
const RX_DREQ: u8;
|
const RX_DREQ: u8;
|
||||||
|
|
||||||
type Interrupt: crate::interrupt::Interrupt;
|
type Interrupt: interrupt::typelevel::Interrupt;
|
||||||
|
|
||||||
fn regs() -> pac::uart::Uart;
|
fn regs() -> pac::uart::Uart;
|
||||||
|
|
||||||
@ -970,7 +945,7 @@ macro_rules! impl_instance {
|
|||||||
const TX_DREQ: u8 = $tx_dreq;
|
const TX_DREQ: u8 = $tx_dreq;
|
||||||
const RX_DREQ: u8 = $rx_dreq;
|
const RX_DREQ: u8 = $rx_dreq;
|
||||||
|
|
||||||
type Interrupt = crate::interrupt::$irq;
|
type Interrupt = crate::interrupt::typelevel::$irq;
|
||||||
|
|
||||||
fn regs() -> pac::uart::Uart {
|
fn regs() -> pac::uart::Uart {
|
||||||
pac::$inst
|
pac::$inst
|
||||||
|
@ -4,15 +4,14 @@ use core::slice;
|
|||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use embassy_cortex_m::interrupt::{self, Binding};
|
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
use embassy_usb_driver as driver;
|
use embassy_usb_driver as driver;
|
||||||
use embassy_usb_driver::{
|
use embassy_usb_driver::{
|
||||||
Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
|
Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::interrupt::{Interrupt, InterruptExt};
|
use crate::interrupt::typelevel::{Binding, Interrupt};
|
||||||
use crate::{pac, peripherals, Peripheral, RegExt};
|
use crate::{interrupt, pac, peripherals, Peripheral, RegExt};
|
||||||
|
|
||||||
pub(crate) mod sealed {
|
pub(crate) mod sealed {
|
||||||
pub trait Instance {
|
pub trait Instance {
|
||||||
@ -22,7 +21,7 @@ pub(crate) mod sealed {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait Instance: sealed::Instance + 'static {
|
pub trait Instance: sealed::Instance + 'static {
|
||||||
type Interrupt: Interrupt;
|
type Interrupt: interrupt::typelevel::Interrupt;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::usb::sealed::Instance for peripherals::USB {
|
impl crate::usb::sealed::Instance for peripherals::USB {
|
||||||
@ -35,12 +34,12 @@ impl crate::usb::sealed::Instance for peripherals::USB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl crate::usb::Instance for peripherals::USB {
|
impl crate::usb::Instance for peripherals::USB {
|
||||||
type Interrupt = crate::interrupt::USBCTRL_IRQ;
|
type Interrupt = crate::interrupt::typelevel::USBCTRL_IRQ;
|
||||||
}
|
}
|
||||||
|
|
||||||
const EP_COUNT: usize = 16;
|
const EP_COUNT: usize = 16;
|
||||||
const EP_MEMORY_SIZE: usize = 4096;
|
const EP_MEMORY_SIZE: usize = 4096;
|
||||||
const EP_MEMORY: *mut u8 = pac::USBCTRL_DPRAM.0;
|
const EP_MEMORY: *mut u8 = pac::USBCTRL_DPRAM.as_ptr() as *mut u8;
|
||||||
|
|
||||||
const NEW_AW: AtomicWaker = AtomicWaker::new();
|
const NEW_AW: AtomicWaker = AtomicWaker::new();
|
||||||
static BUS_WAKER: AtomicWaker = NEW_AW;
|
static BUS_WAKER: AtomicWaker = NEW_AW;
|
||||||
@ -106,15 +105,13 @@ pub struct Driver<'d, T: Instance> {
|
|||||||
|
|
||||||
impl<'d, T: Instance> Driver<'d, T> {
|
impl<'d, T: Instance> Driver<'d, T> {
|
||||||
pub fn new(_usb: impl Peripheral<P = T> + 'd, _irq: impl Binding<T::Interrupt, InterruptHandler<T>>) -> Self {
|
pub fn new(_usb: impl Peripheral<P = T> + 'd, _irq: impl Binding<T::Interrupt, InterruptHandler<T>>) -> Self {
|
||||||
unsafe {
|
T::Interrupt::unpend();
|
||||||
T::Interrupt::steal().unpend();
|
unsafe { T::Interrupt::enable() };
|
||||||
T::Interrupt::steal().enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
unsafe {
|
unsafe {
|
||||||
// zero fill regs
|
// zero fill regs
|
||||||
let p = regs.0 as *mut u32;
|
let p = regs.as_ptr() as *mut u32;
|
||||||
for i in 0..0x9c / 4 {
|
for i in 0..0x9c / 4 {
|
||||||
p.add(i).write_volatile(0)
|
p.add(i).write_volatile(0)
|
||||||
}
|
}
|
||||||
@ -124,6 +121,7 @@ impl<'d, T: Instance> Driver<'d, T> {
|
|||||||
for i in 0..0x100 / 4 {
|
for i in 0..0x100 / 4 {
|
||||||
p.add(i).write_volatile(0)
|
p.add(i).write_volatile(0)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
regs.usb_muxing().write(|w| {
|
regs.usb_muxing().write(|w| {
|
||||||
w.set_to_phy(true);
|
w.set_to_phy(true);
|
||||||
@ -136,7 +134,6 @@ impl<'d, T: Instance> Driver<'d, T> {
|
|||||||
regs.main_ctrl().write(|w| {
|
regs.main_ctrl().write(|w| {
|
||||||
w.set_controller_en(true);
|
w.set_controller_en(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the bus so that it signals that power is available
|
// Initialize the bus so that it signals that power is available
|
||||||
BUS_WAKER.wake();
|
BUS_WAKER.wake();
|
||||||
@ -216,22 +213,18 @@ impl<'d, T: Instance> Driver<'d, T> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match D::dir() {
|
match D::dir() {
|
||||||
Direction::Out => unsafe {
|
Direction::Out => T::dpram().ep_out_control(index - 1).write(|w| {
|
||||||
T::dpram().ep_out_control(index - 1).write(|w| {
|
|
||||||
w.set_enable(false);
|
w.set_enable(false);
|
||||||
w.set_buffer_address(addr);
|
w.set_buffer_address(addr);
|
||||||
w.set_interrupt_per_buff(true);
|
w.set_interrupt_per_buff(true);
|
||||||
w.set_endpoint_type(ep_type_reg);
|
w.set_endpoint_type(ep_type_reg);
|
||||||
})
|
}),
|
||||||
},
|
Direction::In => T::dpram().ep_in_control(index - 1).write(|w| {
|
||||||
Direction::In => unsafe {
|
|
||||||
T::dpram().ep_in_control(index - 1).write(|w| {
|
|
||||||
w.set_enable(false);
|
w.set_enable(false);
|
||||||
w.set_buffer_address(addr);
|
w.set_buffer_address(addr);
|
||||||
w.set_interrupt_per_buff(true);
|
w.set_interrupt_per_buff(true);
|
||||||
w.set_endpoint_type(ep_type_reg);
|
w.set_endpoint_type(ep_type_reg);
|
||||||
})
|
}),
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Endpoint {
|
Ok(Endpoint {
|
||||||
@ -251,7 +244,7 @@ pub struct InterruptHandler<T: Instance> {
|
|||||||
_uart: PhantomData<T>,
|
_uart: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Instance> interrupt::Handler<T::Interrupt> for InterruptHandler<T> {
|
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
unsafe fn on_interrupt() {
|
unsafe fn on_interrupt() {
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
//let x = regs.istr().read().0;
|
//let x = regs.istr().read().0;
|
||||||
@ -318,7 +311,6 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
|
|||||||
|
|
||||||
fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
|
fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
unsafe {
|
|
||||||
regs.inte().write(|w| {
|
regs.inte().write(|w| {
|
||||||
w.set_bus_reset(true);
|
w.set_bus_reset(true);
|
||||||
w.set_buff_status(true);
|
w.set_buff_status(true);
|
||||||
@ -332,8 +324,8 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
|
|||||||
regs.sie_ctrl().write(|w| {
|
regs.sie_ctrl().write(|w| {
|
||||||
w.set_ep0_int_1buf(true);
|
w.set_ep0_int_1buf(true);
|
||||||
w.set_pullup_en(true);
|
w.set_pullup_en(true);
|
||||||
})
|
});
|
||||||
}
|
|
||||||
trace!("enabled");
|
trace!("enabled");
|
||||||
|
|
||||||
(
|
(
|
||||||
@ -358,7 +350,7 @@ pub struct Bus<'d, T: Instance> {
|
|||||||
|
|
||||||
impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
||||||
async fn poll(&mut self) -> Event {
|
async fn poll(&mut self) -> Event {
|
||||||
poll_fn(move |cx| unsafe {
|
poll_fn(move |cx| {
|
||||||
BUS_WAKER.register(cx.waker());
|
BUS_WAKER.register(cx.waker());
|
||||||
|
|
||||||
if !self.inited {
|
if !self.inited {
|
||||||
@ -428,14 +420,14 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
|||||||
|
|
||||||
let n = ep_addr.index();
|
let n = ep_addr.index();
|
||||||
match ep_addr.direction() {
|
match ep_addr.direction() {
|
||||||
Direction::In => unsafe {
|
Direction::In => {
|
||||||
T::dpram().ep_in_control(n - 1).modify(|w| w.set_enable(enabled));
|
T::dpram().ep_in_control(n - 1).modify(|w| w.set_enable(enabled));
|
||||||
T::dpram().ep_in_buffer_control(ep_addr.index()).write(|w| {
|
T::dpram().ep_in_buffer_control(ep_addr.index()).write(|w| {
|
||||||
w.set_pid(0, true); // first packet is DATA0, but PID is flipped before
|
w.set_pid(0, true); // first packet is DATA0, but PID is flipped before
|
||||||
});
|
});
|
||||||
EP_IN_WAKERS[n].wake();
|
EP_IN_WAKERS[n].wake();
|
||||||
},
|
}
|
||||||
Direction::Out => unsafe {
|
Direction::Out => {
|
||||||
T::dpram().ep_out_control(n - 1).modify(|w| w.set_enable(enabled));
|
T::dpram().ep_out_control(n - 1).modify(|w| w.set_enable(enabled));
|
||||||
|
|
||||||
T::dpram().ep_out_buffer_control(ep_addr.index()).write(|w| {
|
T::dpram().ep_out_buffer_control(ep_addr.index()).write(|w| {
|
||||||
@ -449,7 +441,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
|||||||
w.set_available(0, true);
|
w.set_available(0, true);
|
||||||
});
|
});
|
||||||
EP_OUT_WAKERS[n].wake();
|
EP_OUT_WAKERS[n].wake();
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -507,7 +499,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, In> {
|
|||||||
let index = self.info.addr.index();
|
let index = self.info.addr.index();
|
||||||
poll_fn(|cx| {
|
poll_fn(|cx| {
|
||||||
EP_IN_WAKERS[index].register(cx.waker());
|
EP_IN_WAKERS[index].register(cx.waker());
|
||||||
let val = unsafe { T::dpram().ep_in_control(self.info.addr.index() - 1).read() };
|
let val = T::dpram().ep_in_control(self.info.addr.index() - 1).read();
|
||||||
if val.enable() {
|
if val.enable() {
|
||||||
Poll::Ready(())
|
Poll::Ready(())
|
||||||
} else {
|
} else {
|
||||||
@ -529,7 +521,7 @@ impl<'d, T: Instance> driver::Endpoint for Endpoint<'d, T, Out> {
|
|||||||
let index = self.info.addr.index();
|
let index = self.info.addr.index();
|
||||||
poll_fn(|cx| {
|
poll_fn(|cx| {
|
||||||
EP_OUT_WAKERS[index].register(cx.waker());
|
EP_OUT_WAKERS[index].register(cx.waker());
|
||||||
let val = unsafe { T::dpram().ep_out_control(self.info.addr.index() - 1).read() };
|
let val = T::dpram().ep_out_control(self.info.addr.index() - 1).read();
|
||||||
if val.enable() {
|
if val.enable() {
|
||||||
Poll::Ready(())
|
Poll::Ready(())
|
||||||
} else {
|
} else {
|
||||||
@ -545,7 +537,7 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
|
|||||||
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
|
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
|
||||||
trace!("READ WAITING, buf.len() = {}", buf.len());
|
trace!("READ WAITING, buf.len() = {}", buf.len());
|
||||||
let index = self.info.addr.index();
|
let index = self.info.addr.index();
|
||||||
let val = poll_fn(|cx| unsafe {
|
let val = poll_fn(|cx| {
|
||||||
EP_OUT_WAKERS[index].register(cx.waker());
|
EP_OUT_WAKERS[index].register(cx.waker());
|
||||||
let val = T::dpram().ep_out_buffer_control(index).read();
|
let val = T::dpram().ep_out_buffer_control(index).read();
|
||||||
if val.available(0) {
|
if val.available(0) {
|
||||||
@ -564,7 +556,6 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
|
|||||||
|
|
||||||
trace!("READ OK, rx_len = {}", rx_len);
|
trace!("READ OK, rx_len = {}", rx_len);
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let pid = !val.pid(0);
|
let pid = !val.pid(0);
|
||||||
T::dpram().ep_out_buffer_control(index).write(|w| {
|
T::dpram().ep_out_buffer_control(index).write(|w| {
|
||||||
w.set_pid(0, pid);
|
w.set_pid(0, pid);
|
||||||
@ -576,7 +567,6 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
|
|||||||
w.set_length(0, self.info.max_packet_size);
|
w.set_length(0, self.info.max_packet_size);
|
||||||
w.set_available(0, true);
|
w.set_available(0, true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Ok(rx_len)
|
Ok(rx_len)
|
||||||
}
|
}
|
||||||
@ -591,7 +581,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
|
|||||||
trace!("WRITE WAITING");
|
trace!("WRITE WAITING");
|
||||||
|
|
||||||
let index = self.info.addr.index();
|
let index = self.info.addr.index();
|
||||||
let val = poll_fn(|cx| unsafe {
|
let val = poll_fn(|cx| {
|
||||||
EP_IN_WAKERS[index].register(cx.waker());
|
EP_IN_WAKERS[index].register(cx.waker());
|
||||||
let val = T::dpram().ep_in_buffer_control(index).read();
|
let val = T::dpram().ep_in_buffer_control(index).read();
|
||||||
if val.available(0) {
|
if val.available(0) {
|
||||||
@ -604,7 +594,6 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
|
|||||||
|
|
||||||
self.buf.write(buf);
|
self.buf.write(buf);
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let pid = !val.pid(0);
|
let pid = !val.pid(0);
|
||||||
T::dpram().ep_in_buffer_control(index).write(|w| {
|
T::dpram().ep_in_buffer_control(index).write(|w| {
|
||||||
w.set_pid(0, pid);
|
w.set_pid(0, pid);
|
||||||
@ -618,7 +607,6 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
|
|||||||
w.set_full(0, true);
|
w.set_full(0, true);
|
||||||
w.set_available(0, true);
|
w.set_available(0, true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
trace!("WRITE OK");
|
trace!("WRITE OK");
|
||||||
|
|
||||||
@ -640,9 +628,9 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
loop {
|
loop {
|
||||||
trace!("SETUP read waiting");
|
trace!("SETUP read waiting");
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
unsafe { regs.inte().write_set(|w| w.set_setup_req(true)) };
|
regs.inte().write_set(|w| w.set_setup_req(true));
|
||||||
|
|
||||||
poll_fn(|cx| unsafe {
|
poll_fn(|cx| {
|
||||||
EP_OUT_WAKERS[0].register(cx.waker());
|
EP_OUT_WAKERS[0].register(cx.waker());
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
if regs.sie_status().read().setup_rec() {
|
if regs.sie_status().read().setup_rec() {
|
||||||
@ -657,13 +645,11 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
EndpointBuffer::<T>::new(0, 8).read(&mut buf);
|
EndpointBuffer::<T>::new(0, 8).read(&mut buf);
|
||||||
|
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
unsafe {
|
|
||||||
regs.sie_status().write(|w| w.set_setup_rec(true));
|
regs.sie_status().write(|w| w.set_setup_rec(true));
|
||||||
|
|
||||||
// set PID to 0, so (after toggling) first DATA is PID 1
|
// set PID to 0, so (after toggling) first DATA is PID 1
|
||||||
T::dpram().ep_in_buffer_control(0).write(|w| w.set_pid(0, false));
|
T::dpram().ep_in_buffer_control(0).write(|w| w.set_pid(0, false));
|
||||||
T::dpram().ep_out_buffer_control(0).write(|w| w.set_pid(0, false));
|
T::dpram().ep_out_buffer_control(0).write(|w| w.set_pid(0, false));
|
||||||
}
|
|
||||||
|
|
||||||
trace!("SETUP read ok");
|
trace!("SETUP read ok");
|
||||||
return buf;
|
return buf;
|
||||||
@ -671,7 +657,6 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn data_out(&mut self, buf: &mut [u8], first: bool, last: bool) -> Result<usize, EndpointError> {
|
async fn data_out(&mut self, buf: &mut [u8], first: bool, last: bool) -> Result<usize, EndpointError> {
|
||||||
unsafe {
|
|
||||||
let bufcontrol = T::dpram().ep_out_buffer_control(0);
|
let bufcontrol = T::dpram().ep_out_buffer_control(0);
|
||||||
let pid = !bufcontrol.read().pid(0);
|
let pid = !bufcontrol.read().pid(0);
|
||||||
bufcontrol.write(|w| {
|
bufcontrol.write(|w| {
|
||||||
@ -684,10 +669,9 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
w.set_pid(0, pid);
|
w.set_pid(0, pid);
|
||||||
w.set_available(0, true);
|
w.set_available(0, true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
trace!("control: data_out len={} first={} last={}", buf.len(), first, last);
|
trace!("control: data_out len={} first={} last={}", buf.len(), first, last);
|
||||||
let val = poll_fn(|cx| unsafe {
|
let val = poll_fn(|cx| {
|
||||||
EP_OUT_WAKERS[0].register(cx.waker());
|
EP_OUT_WAKERS[0].register(cx.waker());
|
||||||
let val = T::dpram().ep_out_buffer_control(0).read();
|
let val = T::dpram().ep_out_buffer_control(0).read();
|
||||||
if val.available(0) {
|
if val.available(0) {
|
||||||
@ -717,7 +701,6 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
}
|
}
|
||||||
EndpointBuffer::<T>::new(0x100, 64).write(data);
|
EndpointBuffer::<T>::new(0x100, 64).write(data);
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let bufcontrol = T::dpram().ep_in_buffer_control(0);
|
let bufcontrol = T::dpram().ep_in_buffer_control(0);
|
||||||
let pid = !bufcontrol.read().pid(0);
|
let pid = !bufcontrol.read().pid(0);
|
||||||
bufcontrol.write(|w| {
|
bufcontrol.write(|w| {
|
||||||
@ -732,9 +715,8 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
w.set_full(0, true);
|
w.set_full(0, true);
|
||||||
w.set_available(0, true);
|
w.set_available(0, true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
poll_fn(|cx| unsafe {
|
poll_fn(|cx| {
|
||||||
EP_IN_WAKERS[0].register(cx.waker());
|
EP_IN_WAKERS[0].register(cx.waker());
|
||||||
let bufcontrol = T::dpram().ep_in_buffer_control(0);
|
let bufcontrol = T::dpram().ep_in_buffer_control(0);
|
||||||
if bufcontrol.read().available(0) {
|
if bufcontrol.read().available(0) {
|
||||||
@ -748,7 +730,6 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
|
|
||||||
if last {
|
if last {
|
||||||
// prepare status phase right away.
|
// prepare status phase right away.
|
||||||
unsafe {
|
|
||||||
let bufcontrol = T::dpram().ep_out_buffer_control(0);
|
let bufcontrol = T::dpram().ep_out_buffer_control(0);
|
||||||
bufcontrol.write(|w| {
|
bufcontrol.write(|w| {
|
||||||
w.set_length(0, 0);
|
w.set_length(0, 0);
|
||||||
@ -761,7 +742,6 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
w.set_available(0, true);
|
w.set_available(0, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -770,7 +750,6 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
trace!("control: accept");
|
trace!("control: accept");
|
||||||
|
|
||||||
let bufcontrol = T::dpram().ep_in_buffer_control(0);
|
let bufcontrol = T::dpram().ep_in_buffer_control(0);
|
||||||
unsafe {
|
|
||||||
bufcontrol.write(|w| {
|
bufcontrol.write(|w| {
|
||||||
w.set_length(0, 0);
|
w.set_length(0, 0);
|
||||||
w.set_pid(0, true);
|
w.set_pid(0, true);
|
||||||
@ -783,13 +762,12 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
w.set_full(0, true);
|
w.set_full(0, true);
|
||||||
w.set_available(0, true);
|
w.set_available(0, true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// wait for completion before returning, needed so
|
// wait for completion before returning, needed so
|
||||||
// set_address() doesn't happen early.
|
// set_address() doesn't happen early.
|
||||||
poll_fn(|cx| {
|
poll_fn(|cx| {
|
||||||
EP_IN_WAKERS[0].register(cx.waker());
|
EP_IN_WAKERS[0].register(cx.waker());
|
||||||
if unsafe { bufcontrol.read().available(0) } {
|
if bufcontrol.read().available(0) {
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
} else {
|
} else {
|
||||||
Poll::Ready(())
|
Poll::Ready(())
|
||||||
@ -802,7 +780,6 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
trace!("control: reject");
|
trace!("control: reject");
|
||||||
|
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
unsafe {
|
|
||||||
regs.ep_stall_arm().write_set(|w| {
|
regs.ep_stall_arm().write_set(|w| {
|
||||||
w.set_ep0_in(true);
|
w.set_ep0_in(true);
|
||||||
w.set_ep0_out(true);
|
w.set_ep0_out(true);
|
||||||
@ -810,13 +787,12 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
|
|||||||
T::dpram().ep_out_buffer_control(0).write(|w| w.set_stall(true));
|
T::dpram().ep_out_buffer_control(0).write(|w| w.set_stall(true));
|
||||||
T::dpram().ep_in_buffer_control(0).write(|w| w.set_stall(true));
|
T::dpram().ep_in_buffer_control(0).write(|w| w.set_stall(true));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
async fn accept_set_address(&mut self, addr: u8) {
|
async fn accept_set_address(&mut self, addr: u8) {
|
||||||
self.accept().await;
|
self.accept().await;
|
||||||
|
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
trace!("setting addr: {}", addr);
|
trace!("setting addr: {}", addr);
|
||||||
unsafe { regs.addr_endp().write(|w| w.set_address(addr)) }
|
regs.addr_endp().write(|w| w.set_address(addr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,19 +35,16 @@ impl Watchdog {
|
|||||||
/// * `cycles` - Total number of tick cycles before the next tick is generated.
|
/// * `cycles` - Total number of tick cycles before the next tick is generated.
|
||||||
/// It is expected to be the frequency in MHz of clk_ref.
|
/// It is expected to be the frequency in MHz of clk_ref.
|
||||||
pub fn enable_tick_generation(&mut self, cycles: u8) {
|
pub fn enable_tick_generation(&mut self, cycles: u8) {
|
||||||
unsafe {
|
|
||||||
let watchdog = pac::WATCHDOG;
|
let watchdog = pac::WATCHDOG;
|
||||||
watchdog.tick().write(|w| {
|
watchdog.tick().write(|w| {
|
||||||
w.set_enable(true);
|
w.set_enable(true);
|
||||||
w.set_cycles(cycles.into())
|
w.set_cycles(cycles.into())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Defines whether or not the watchdog timer should be paused when processor(s) are in debug mode
|
/// Defines whether or not the watchdog timer should be paused when processor(s) are in debug mode
|
||||||
/// or when JTAG is accessing bus fabric
|
/// or when JTAG is accessing bus fabric
|
||||||
pub fn pause_on_debug(&mut self, pause: bool) {
|
pub fn pause_on_debug(&mut self, pause: bool) {
|
||||||
unsafe {
|
|
||||||
let watchdog = pac::WATCHDOG;
|
let watchdog = pac::WATCHDOG;
|
||||||
watchdog.ctrl().write(|w| {
|
watchdog.ctrl().write(|w| {
|
||||||
w.set_pause_dbg0(pause);
|
w.set_pause_dbg0(pause);
|
||||||
@ -55,25 +52,20 @@ impl Watchdog {
|
|||||||
w.set_pause_jtag(pause);
|
w.set_pause_jtag(pause);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn load_counter(&self, counter: u32) {
|
fn load_counter(&self, counter: u32) {
|
||||||
unsafe {
|
|
||||||
let watchdog = pac::WATCHDOG;
|
let watchdog = pac::WATCHDOG;
|
||||||
watchdog.load().write_value(pac::watchdog::regs::Load(counter));
|
watchdog.load().write_value(pac::watchdog::regs::Load(counter));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn enable(&self, bit: bool) {
|
fn enable(&self, bit: bool) {
|
||||||
unsafe {
|
|
||||||
let watchdog = pac::WATCHDOG;
|
let watchdog = pac::WATCHDOG;
|
||||||
watchdog.ctrl().write(|w| w.set_enable(bit))
|
watchdog.ctrl().write(|w| w.set_enable(bit))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Configure which hardware will be reset by the watchdog
|
// Configure which hardware will be reset by the watchdog
|
||||||
// (everything except ROSC, XOSC)
|
// (everything except ROSC, XOSC)
|
||||||
unsafe fn configure_wdog_reset_triggers(&self) {
|
fn configure_wdog_reset_triggers(&self) {
|
||||||
let psm = pac::PSM;
|
let psm = pac::PSM;
|
||||||
psm.wdsel().write_value(pac::psm::regs::Wdsel(
|
psm.wdsel().write_value(pac::psm::regs::Wdsel(
|
||||||
0x0001ffff & !(0x01 << 0usize) & !(0x01 << 1usize),
|
0x0001ffff & !(0x01 << 0usize) & !(0x01 << 1usize),
|
||||||
@ -100,16 +92,13 @@ impl Watchdog {
|
|||||||
self.load_value = delay_us * 2;
|
self.load_value = delay_us * 2;
|
||||||
|
|
||||||
self.enable(false);
|
self.enable(false);
|
||||||
unsafe {
|
|
||||||
self.configure_wdog_reset_triggers();
|
self.configure_wdog_reset_triggers();
|
||||||
}
|
|
||||||
self.load_counter(self.load_value);
|
self.load_counter(self.load_value);
|
||||||
self.enable(true);
|
self.enable(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trigger a system reset
|
/// Trigger a system reset
|
||||||
pub fn trigger_reset(&mut self) {
|
pub fn trigger_reset(&mut self) {
|
||||||
unsafe {
|
|
||||||
self.configure_wdog_reset_triggers();
|
self.configure_wdog_reset_triggers();
|
||||||
self.pause_on_debug(false);
|
self.pause_on_debug(false);
|
||||||
self.enable(true);
|
self.enable(true);
|
||||||
@ -118,5 +107,4 @@ impl Watchdog {
|
|||||||
w.set_trigger(true);
|
w.set_trigger(true);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
45
embassy-stm32-wpan/Cargo.toml
Normal file
45
embassy-stm32-wpan/Cargo.toml
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
[package]
|
||||||
|
name = "embassy-stm32-wpan"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
|
[package.metadata.embassy_docs]
|
||||||
|
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-stm32-wpan-v$VERSION/embassy-stm32-wpan/src"
|
||||||
|
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-stm32-wpan/src"
|
||||||
|
target = "thumbv7em-none-eabihf"
|
||||||
|
features = ["stm32wb55rg"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" }
|
||||||
|
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
|
||||||
|
embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true }
|
||||||
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||||
|
embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common" }
|
||||||
|
embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||||
|
|
||||||
|
defmt = { version = "0.3", optional = true }
|
||||||
|
cortex-m = "0.7.6"
|
||||||
|
heapless = "0.7.16"
|
||||||
|
|
||||||
|
bit_field = "0.10.2"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt"]
|
||||||
|
|
||||||
|
stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ]
|
||||||
|
stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ]
|
||||||
|
stm32wb30ce = [ "embassy-stm32/stm32wb30ce" ]
|
||||||
|
stm32wb35cc = [ "embassy-stm32/stm32wb35cc" ]
|
||||||
|
stm32wb35ce = [ "embassy-stm32/stm32wb35ce" ]
|
||||||
|
stm32wb50cg = [ "embassy-stm32/stm32wb50cg" ]
|
||||||
|
stm32wb55cc = [ "embassy-stm32/stm32wb55cc" ]
|
||||||
|
stm32wb55ce = [ "embassy-stm32/stm32wb55ce" ]
|
||||||
|
stm32wb55cg = [ "embassy-stm32/stm32wb55cg" ]
|
||||||
|
stm32wb55rc = [ "embassy-stm32/stm32wb55rc" ]
|
||||||
|
stm32wb55re = [ "embassy-stm32/stm32wb55re" ]
|
||||||
|
stm32wb55rg = [ "embassy-stm32/stm32wb55rg" ]
|
||||||
|
stm32wb55vc = [ "embassy-stm32/stm32wb55vc" ]
|
||||||
|
stm32wb55ve = [ "embassy-stm32/stm32wb55ve" ]
|
||||||
|
stm32wb55vg = [ "embassy-stm32/stm32wb55vg" ]
|
||||||
|
stm32wb55vy = [ "embassy-stm32/stm32wb55vy" ]
|
34
embassy-stm32-wpan/build.rs
Normal file
34
embassy-stm32-wpan/build.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
use std::env;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
match env::vars()
|
||||||
|
.map(|(a, _)| a)
|
||||||
|
.filter(|x| x.starts_with("CARGO_FEATURE_STM32"))
|
||||||
|
.get_one()
|
||||||
|
{
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(GetOneError::None) => panic!("No stm32xx Cargo feature enabled"),
|
||||||
|
Err(GetOneError::Multiple) => panic!("Multiple stm32xx Cargo features enabled"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum GetOneError {
|
||||||
|
None,
|
||||||
|
Multiple,
|
||||||
|
}
|
||||||
|
|
||||||
|
trait IteratorExt: Iterator {
|
||||||
|
fn get_one(self) -> Result<Self::Item, GetOneError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Iterator> IteratorExt for T {
|
||||||
|
fn get_one(mut self) -> Result<Self::Item, GetOneError> {
|
||||||
|
match self.next() {
|
||||||
|
None => Err(GetOneError::None),
|
||||||
|
Some(res) => match self.next() {
|
||||||
|
Some(_) => Err(GetOneError::Multiple),
|
||||||
|
None => Ok(res),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
63
embassy-stm32-wpan/src/ble.rs
Normal file
63
embassy-stm32-wpan/src/ble.rs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use embassy_stm32::ipcc::Ipcc;
|
||||||
|
|
||||||
|
use crate::cmd::CmdPacket;
|
||||||
|
use crate::consts::TlPacketType;
|
||||||
|
use crate::evt::EvtBox;
|
||||||
|
use crate::tables::BleTable;
|
||||||
|
use crate::unsafe_linked_list::LinkedListNode;
|
||||||
|
use crate::{channels, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE};
|
||||||
|
|
||||||
|
pub struct Ble {
|
||||||
|
phantom: PhantomData<Ble>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ble {
|
||||||
|
pub(crate) fn new() -> Self {
|
||||||
|
unsafe {
|
||||||
|
LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr());
|
||||||
|
|
||||||
|
TL_BLE_TABLE.as_mut_ptr().write_volatile(BleTable {
|
||||||
|
pcmd_buffer: BLE_CMD_BUFFER.as_mut_ptr().cast(),
|
||||||
|
pcs_buffer: CS_BUFFER.as_ptr().cast(),
|
||||||
|
pevt_queue: EVT_QUEUE.as_ptr().cast(),
|
||||||
|
phci_acl_data_buffer: HCI_ACL_DATA_BUFFER.as_mut_ptr().cast(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Self { phantom: PhantomData }
|
||||||
|
}
|
||||||
|
/// `HW_IPCC_BLE_EvtNot`
|
||||||
|
pub async fn read(&self) -> EvtBox {
|
||||||
|
Ipcc::receive(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, || unsafe {
|
||||||
|
if let Some(node_ptr) = LinkedListNode::remove_head(EVT_QUEUE.as_mut_ptr()) {
|
||||||
|
Some(EvtBox::new(node_ptr.cast()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `TL_BLE_SendCmd`
|
||||||
|
pub async fn write(&self, opcode: u16, payload: &[u8]) {
|
||||||
|
Ipcc::send(channels::cpu1::IPCC_BLE_CMD_CHANNEL, || unsafe {
|
||||||
|
CmdPacket::write_into(BLE_CMD_BUFFER.as_mut_ptr(), TlPacketType::BleCmd, opcode, payload);
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `TL_BLE_SendAclData`
|
||||||
|
pub async fn acl_write(&self, handle: u16, payload: &[u8]) {
|
||||||
|
Ipcc::send(channels::cpu1::IPCC_HCI_ACL_DATA_CHANNEL, || unsafe {
|
||||||
|
CmdPacket::write_into(
|
||||||
|
HCI_ACL_DATA_BUFFER.as_mut_ptr() as *mut _,
|
||||||
|
TlPacketType::AclData,
|
||||||
|
handle,
|
||||||
|
payload,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
@ -50,36 +50,30 @@
|
|||||||
//!
|
//!
|
||||||
|
|
||||||
pub mod cpu1 {
|
pub mod cpu1 {
|
||||||
use crate::tl_mbox::ipcc::IpccChannel;
|
use embassy_stm32::ipcc::IpccChannel;
|
||||||
|
|
||||||
// Not used currently but reserved
|
|
||||||
pub const IPCC_BLE_CMD_CHANNEL: IpccChannel = IpccChannel::Channel1;
|
pub const IPCC_BLE_CMD_CHANNEL: IpccChannel = IpccChannel::Channel1;
|
||||||
// Not used currently but reserved
|
|
||||||
pub const IPCC_SYSTEM_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel2;
|
pub const IPCC_SYSTEM_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel2;
|
||||||
#[allow(dead_code)] // Not used currently but reserved
|
|
||||||
pub const IPCC_THREAD_OT_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
pub const IPCC_THREAD_OT_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
||||||
#[allow(dead_code)] // Not used currently but reserved
|
#[allow(dead_code)] // Not used currently but reserved
|
||||||
pub const IPCC_ZIGBEE_CMD_APPLI_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
pub const IPCC_ZIGBEE_CMD_APPLI_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
||||||
#[allow(dead_code)] // Not used currently but reserved
|
#[allow(dead_code)] // Not used currently but reserved
|
||||||
pub const IPCC_MAC_802_15_4_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
pub const IPCC_MAC_802_15_4_CMD_RSP_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
||||||
// Not used currently but reserved
|
|
||||||
pub const IPCC_MM_RELEASE_BUFFER_CHANNEL: IpccChannel = IpccChannel::Channel4;
|
|
||||||
#[allow(dead_code)] // Not used currently but reserved
|
#[allow(dead_code)] // Not used currently but reserved
|
||||||
|
pub const IPCC_MM_RELEASE_BUFFER_CHANNEL: IpccChannel = IpccChannel::Channel4;
|
||||||
pub const IPCC_THREAD_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5;
|
pub const IPCC_THREAD_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5;
|
||||||
#[allow(dead_code)] // Not used currently but reserved
|
#[allow(dead_code)] // Not used currently but reserved
|
||||||
pub const IPCC_LLDTESTS_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5;
|
pub const IPCC_LLDTESTS_CLI_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5;
|
||||||
#[allow(dead_code)] // Not used currently but reserved
|
#[allow(dead_code)] // Not used currently but reserved
|
||||||
pub const IPCC_BLE_LLD_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5;
|
pub const IPCC_BLE_LLD_CMD_CHANNEL: IpccChannel = IpccChannel::Channel5;
|
||||||
#[allow(dead_code)] // Not used currently but reserved
|
|
||||||
pub const IPCC_HCI_ACL_DATA_CHANNEL: IpccChannel = IpccChannel::Channel6;
|
pub const IPCC_HCI_ACL_DATA_CHANNEL: IpccChannel = IpccChannel::Channel6;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod cpu2 {
|
pub mod cpu2 {
|
||||||
use crate::tl_mbox::ipcc::IpccChannel;
|
use embassy_stm32::ipcc::IpccChannel;
|
||||||
|
|
||||||
pub const IPCC_BLE_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel1;
|
pub const IPCC_BLE_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel1;
|
||||||
pub const IPCC_SYSTEM_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel2;
|
pub const IPCC_SYSTEM_EVENT_CHANNEL: IpccChannel = IpccChannel::Channel2;
|
||||||
#[allow(dead_code)] // Not used currently but reserved
|
|
||||||
pub const IPCC_THREAD_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
pub const IPCC_THREAD_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
||||||
#[allow(dead_code)] // Not used currently but reserved
|
#[allow(dead_code)] // Not used currently but reserved
|
||||||
pub const IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
pub const IPCC_ZIGBEE_APPLI_NOTIF_ACK_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
||||||
@ -88,10 +82,8 @@ pub mod cpu2 {
|
|||||||
#[allow(dead_code)] // Not used currently but reserved
|
#[allow(dead_code)] // Not used currently but reserved
|
||||||
pub const IPCC_LDDTESTS_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
pub const IPCC_LDDTESTS_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
||||||
#[allow(dead_code)] // Not used currently but reserved
|
#[allow(dead_code)] // Not used currently but reserved
|
||||||
pub const IPCC_BLE_LLD_M0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
pub const IPCC_BLE_LLDÇM0_CMD_CHANNEL: IpccChannel = IpccChannel::Channel3;
|
||||||
#[allow(dead_code)] // Not used currently but reserved
|
|
||||||
pub const IPCC_TRACES_CHANNEL: IpccChannel = IpccChannel::Channel4;
|
pub const IPCC_TRACES_CHANNEL: IpccChannel = IpccChannel::Channel4;
|
||||||
#[allow(dead_code)] // Not used currently but reserved
|
|
||||||
pub const IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel5;
|
pub const IPCC_THREAD_CLI_NOTIFICATION_ACK_CHANNEL: IpccChannel = IpccChannel::Channel5;
|
||||||
#[allow(dead_code)] // Not used currently but reserved
|
#[allow(dead_code)] // Not used currently but reserved
|
||||||
pub const IPCC_LLDTESTS_CLI_RSP_CHANNEL: IpccChannel = IpccChannel::Channel5;
|
pub const IPCC_LLDTESTS_CLI_RSP_CHANNEL: IpccChannel = IpccChannel::Channel5;
|
104
embassy-stm32-wpan/src/cmd.rs
Normal file
104
embassy-stm32-wpan/src/cmd.rs
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
use core::ptr;
|
||||||
|
|
||||||
|
use crate::consts::TlPacketType;
|
||||||
|
use crate::PacketHeader;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct Cmd {
|
||||||
|
pub cmd_code: u16,
|
||||||
|
pub payload_len: u8,
|
||||||
|
pub payload: [u8; 255],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Cmd {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
cmd_code: 0,
|
||||||
|
payload_len: 0,
|
||||||
|
payload: [0u8; 255],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Default)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct CmdSerial {
|
||||||
|
pub ty: u8,
|
||||||
|
pub cmd: Cmd,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Default)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct CmdSerialStub {
|
||||||
|
pub ty: u8,
|
||||||
|
pub cmd_code: u16,
|
||||||
|
pub payload_len: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Default)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct CmdPacket {
|
||||||
|
pub header: PacketHeader,
|
||||||
|
pub cmdserial: CmdSerial,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CmdPacket {
|
||||||
|
pub unsafe fn write_into(cmd_buf: *mut CmdPacket, packet_type: TlPacketType, cmd_code: u16, payload: &[u8]) {
|
||||||
|
let p_cmd_serial = &mut (*cmd_buf).cmdserial as *mut _ as *mut CmdSerialStub;
|
||||||
|
let p_payload = &mut (*cmd_buf).cmdserial.cmd.payload as *mut _;
|
||||||
|
|
||||||
|
ptr::write_volatile(
|
||||||
|
p_cmd_serial,
|
||||||
|
CmdSerialStub {
|
||||||
|
ty: packet_type as u8,
|
||||||
|
cmd_code: cmd_code,
|
||||||
|
payload_len: payload.len() as u8,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
ptr::copy_nonoverlapping(payload as *const _ as *const u8, p_payload, payload.len());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct AclDataSerial {
|
||||||
|
pub ty: u8,
|
||||||
|
pub handle: u16,
|
||||||
|
pub length: u16,
|
||||||
|
pub acl_data: [u8; 1],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct AclDataSerialStub {
|
||||||
|
pub ty: u8,
|
||||||
|
pub handle: u16,
|
||||||
|
pub length: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct AclDataPacket {
|
||||||
|
pub header: PacketHeader,
|
||||||
|
pub acl_data_serial: AclDataSerial,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AclDataPacket {
|
||||||
|
pub unsafe fn write_into(cmd_buf: *mut AclDataPacket, packet_type: TlPacketType, handle: u16, payload: &[u8]) {
|
||||||
|
let p_cmd_serial = &mut (*cmd_buf).acl_data_serial as *mut _ as *mut AclDataSerialStub;
|
||||||
|
let p_payload = &mut (*cmd_buf).acl_data_serial.acl_data as *mut _;
|
||||||
|
|
||||||
|
ptr::write_volatile(
|
||||||
|
p_cmd_serial,
|
||||||
|
AclDataSerialStub {
|
||||||
|
ty: packet_type as u8,
|
||||||
|
handle: handle,
|
||||||
|
length: payload.len() as u16,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
ptr::copy_nonoverlapping(payload as *const _ as *const u8, p_payload, payload.len());
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,6 @@
|
|||||||
#[derive(PartialEq)]
|
use core::convert::TryFrom;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub enum TlPacketType {
|
pub enum TlPacketType {
|
||||||
BleCmd = 0x01,
|
BleCmd = 0x01,
|
195
embassy-stm32-wpan/src/evt.rs
Normal file
195
embassy-stm32-wpan/src/evt.rs
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
use core::{ptr, slice};
|
||||||
|
|
||||||
|
use super::PacketHeader;
|
||||||
|
use crate::mm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The payload of `Evt` for a command status event
|
||||||
|
*/
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct CsEvt {
|
||||||
|
pub status: u8,
|
||||||
|
pub num_cmd: u8,
|
||||||
|
pub cmd_code: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The payload of `Evt` for a command complete event
|
||||||
|
*/
|
||||||
|
#[derive(Copy, Clone, Default)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct CcEvt {
|
||||||
|
pub num_cmd: u8,
|
||||||
|
pub cmd_code: u16,
|
||||||
|
pub payload: [u8; 1],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CcEvt {
|
||||||
|
pub fn write(&self, buf: &mut [u8]) {
|
||||||
|
unsafe {
|
||||||
|
let len = core::mem::size_of::<CcEvt>();
|
||||||
|
assert!(buf.len() >= len);
|
||||||
|
|
||||||
|
let self_ptr: *const CcEvt = self;
|
||||||
|
let self_buf_ptr: *const u8 = self_ptr.cast();
|
||||||
|
|
||||||
|
core::ptr::copy(self_buf_ptr, buf.as_mut_ptr(), len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Default)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct AsynchEvt {
|
||||||
|
sub_evt_code: u16,
|
||||||
|
payload: [u8; 1],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Default)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct Evt {
|
||||||
|
pub evt_code: u8,
|
||||||
|
pub payload_len: u8,
|
||||||
|
pub payload: [u8; 1],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Default)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct EvtSerial {
|
||||||
|
pub kind: u8,
|
||||||
|
pub evt: Evt,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Default)]
|
||||||
|
pub struct EvtStub {
|
||||||
|
pub kind: u8,
|
||||||
|
pub evt_code: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This format shall be used for all events (asynchronous and command response) reported
|
||||||
|
/// by the CPU2 except for the command response of a system command where the header is not there
|
||||||
|
/// and the format to be used shall be `EvtSerial`.
|
||||||
|
///
|
||||||
|
/// ### Note:
|
||||||
|
/// Be careful that the asynchronous events reported by the CPU2 on the system channel do
|
||||||
|
/// include the header and shall use `EvtPacket` format. Only the command response format on the
|
||||||
|
/// system channel is different.
|
||||||
|
#[derive(Copy, Clone, Default)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct EvtPacket {
|
||||||
|
pub header: PacketHeader,
|
||||||
|
pub evt_serial: EvtSerial,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EvtPacket {
|
||||||
|
pub fn kind(&self) -> u8 {
|
||||||
|
self.evt_serial.kind
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn evt(&self) -> &Evt {
|
||||||
|
&self.evt_serial.evt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// smart pointer to the [`EvtPacket`] that will dispose of [`EvtPacket`] buffer automatically
|
||||||
|
/// on [`Drop`]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct EvtBox {
|
||||||
|
ptr: *mut EvtPacket,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for EvtBox {}
|
||||||
|
impl EvtBox {
|
||||||
|
pub(super) fn new(ptr: *mut EvtPacket) -> Self {
|
||||||
|
Self { ptr }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns information about the event
|
||||||
|
pub fn stub(&self) -> EvtStub {
|
||||||
|
unsafe {
|
||||||
|
let p_evt_stub = &(*self.ptr).evt_serial as *const _ as *const EvtStub;
|
||||||
|
|
||||||
|
ptr::read_volatile(p_evt_stub)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn payload<'a>(&self) -> &'a [u8] {
|
||||||
|
unsafe {
|
||||||
|
let p_payload_len = &(*self.ptr).evt_serial.evt.payload_len as *const u8;
|
||||||
|
let p_payload = &(*self.ptr).evt_serial.evt.payload as *const u8;
|
||||||
|
|
||||||
|
let payload_len = ptr::read_volatile(p_payload_len);
|
||||||
|
|
||||||
|
slice::from_raw_parts(p_payload, payload_len as usize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: bring back acl
|
||||||
|
|
||||||
|
// /// writes an underlying [`EvtPacket`] into the provided buffer.
|
||||||
|
// /// Returns the number of bytes that were written.
|
||||||
|
// /// Returns an error if event kind is unknown or if provided buffer size is not enough.
|
||||||
|
// #[allow(clippy::result_unit_err)]
|
||||||
|
// pub fn write(&self, buf: &mut [u8]) -> Result<usize, ()> {
|
||||||
|
// unsafe {
|
||||||
|
// let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?;
|
||||||
|
//
|
||||||
|
// let evt_data: *const EvtPacket = self.ptr.cast();
|
||||||
|
// let evt_serial: *const EvtSerial = &(*evt_data).evt_serial;
|
||||||
|
// let evt_serial_buf: *const u8 = evt_serial.cast();
|
||||||
|
//
|
||||||
|
// let acl_data: *const AclDataPacket = self.ptr.cast();
|
||||||
|
// let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial;
|
||||||
|
// let acl_serial_buf: *const u8 = acl_serial.cast();
|
||||||
|
//
|
||||||
|
// if let TlPacketType::AclData = evt_kind {
|
||||||
|
// let len = (*acl_serial).length as usize + 5;
|
||||||
|
// if len > buf.len() {
|
||||||
|
// return Err(());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// core::ptr::copy(evt_serial_buf, buf.as_mut_ptr(), len);
|
||||||
|
//
|
||||||
|
// Ok(len)
|
||||||
|
// } else {
|
||||||
|
// let len = (*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE;
|
||||||
|
// if len > buf.len() {
|
||||||
|
// return Err(());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// core::ptr::copy(acl_serial_buf, buf.as_mut_ptr(), len);
|
||||||
|
//
|
||||||
|
// Ok(len)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// /// returns the size of a buffer required to hold this event
|
||||||
|
// #[allow(clippy::result_unit_err)]
|
||||||
|
// pub fn size(&self) -> Result<usize, ()> {
|
||||||
|
// unsafe {
|
||||||
|
// let evt_kind = TlPacketType::try_from((*self.ptr).evt_serial.kind)?;
|
||||||
|
//
|
||||||
|
// let evt_data: *const EvtPacket = self.ptr.cast();
|
||||||
|
// let evt_serial: *const EvtSerial = &(*evt_data).evt_serial;
|
||||||
|
//
|
||||||
|
// let acl_data: *const AclDataPacket = self.ptr.cast();
|
||||||
|
// let acl_serial: *const AclDataSerial = &(*acl_data).acl_data_serial;
|
||||||
|
//
|
||||||
|
// if let TlPacketType::AclData = evt_kind {
|
||||||
|
// Ok((*acl_serial).length as usize + 5)
|
||||||
|
// } else {
|
||||||
|
// Ok((*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for EvtBox {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
trace!("evt box drop packet");
|
||||||
|
|
||||||
|
unsafe { mm::MemoryManager::drop_event_packet(self.ptr) };
|
||||||
|
}
|
||||||
|
}
|
@ -195,9 +195,6 @@ macro_rules! unwrap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "defmt-timestamp-uptime")]
|
|
||||||
defmt::timestamp! {"{=u64:us}", crate::time::Instant::now().as_micros() }
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
pub struct NoneError;
|
pub struct NoneError;
|
||||||
|
|
255
embassy-stm32-wpan/src/lib.rs
Normal file
255
embassy-stm32-wpan/src/lib.rs
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
#![no_std]
|
||||||
|
|
||||||
|
// This must go FIRST so that all the other modules see its macros.
|
||||||
|
pub mod fmt;
|
||||||
|
|
||||||
|
use core::mem::MaybeUninit;
|
||||||
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
|
|
||||||
|
use ble::Ble;
|
||||||
|
use cmd::CmdPacket;
|
||||||
|
use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
|
||||||
|
use embassy_stm32::interrupt;
|
||||||
|
use embassy_stm32::interrupt::typelevel::Interrupt;
|
||||||
|
use embassy_stm32::ipcc::{Config, Ipcc, ReceiveInterruptHandler, TransmitInterruptHandler};
|
||||||
|
use embassy_stm32::peripherals::IPCC;
|
||||||
|
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||||
|
use embassy_sync::channel::Channel;
|
||||||
|
use embassy_sync::signal::Signal;
|
||||||
|
use evt::{CcEvt, EvtBox};
|
||||||
|
use mm::MemoryManager;
|
||||||
|
use sys::Sys;
|
||||||
|
use tables::{
|
||||||
|
BleTable, DeviceInfoTable, Mac802_15_4Table, MemManagerTable, RefTable, SysTable, ThreadTable, TracesTable,
|
||||||
|
};
|
||||||
|
use unsafe_linked_list::LinkedListNode;
|
||||||
|
|
||||||
|
pub mod ble;
|
||||||
|
pub mod channels;
|
||||||
|
pub mod cmd;
|
||||||
|
pub mod consts;
|
||||||
|
pub mod evt;
|
||||||
|
pub mod mm;
|
||||||
|
pub mod shci;
|
||||||
|
pub mod sys;
|
||||||
|
pub mod tables;
|
||||||
|
pub mod unsafe_linked_list;
|
||||||
|
|
||||||
|
#[link_section = "TL_REF_TABLE"]
|
||||||
|
pub static mut TL_REF_TABLE: MaybeUninit<RefTable> = MaybeUninit::uninit();
|
||||||
|
|
||||||
|
#[link_section = "MB_MEM1"]
|
||||||
|
static mut TL_DEVICE_INFO_TABLE: MaybeUninit<DeviceInfoTable> = MaybeUninit::uninit();
|
||||||
|
|
||||||
|
#[link_section = "MB_MEM1"]
|
||||||
|
static mut TL_BLE_TABLE: MaybeUninit<BleTable> = MaybeUninit::uninit();
|
||||||
|
|
||||||
|
#[link_section = "MB_MEM1"]
|
||||||
|
static mut TL_THREAD_TABLE: MaybeUninit<ThreadTable> = MaybeUninit::uninit();
|
||||||
|
|
||||||
|
#[link_section = "MB_MEM1"]
|
||||||
|
static mut TL_SYS_TABLE: MaybeUninit<SysTable> = MaybeUninit::uninit();
|
||||||
|
|
||||||
|
#[link_section = "MB_MEM1"]
|
||||||
|
static mut TL_MEM_MANAGER_TABLE: MaybeUninit<MemManagerTable> = MaybeUninit::uninit();
|
||||||
|
|
||||||
|
#[link_section = "MB_MEM1"]
|
||||||
|
static mut TL_TRACES_TABLE: MaybeUninit<TracesTable> = MaybeUninit::uninit();
|
||||||
|
|
||||||
|
#[link_section = "MB_MEM1"]
|
||||||
|
static mut TL_MAC_802_15_4_TABLE: MaybeUninit<Mac802_15_4Table> = MaybeUninit::uninit();
|
||||||
|
|
||||||
|
#[link_section = "MB_MEM2"]
|
||||||
|
static mut FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
|
||||||
|
|
||||||
|
// Not in shared RAM
|
||||||
|
static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
|
||||||
|
|
||||||
|
#[allow(dead_code)] // Not used currently but reserved
|
||||||
|
#[link_section = "MB_MEM2"]
|
||||||
|
static mut TRACES_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
|
||||||
|
|
||||||
|
type PacketHeader = LinkedListNode;
|
||||||
|
|
||||||
|
const TL_PACKET_HEADER_SIZE: usize = core::mem::size_of::<PacketHeader>();
|
||||||
|
const TL_EVT_HEADER_SIZE: usize = 3;
|
||||||
|
const TL_CS_EVT_SIZE: usize = core::mem::size_of::<evt::CsEvt>();
|
||||||
|
|
||||||
|
#[link_section = "MB_MEM2"]
|
||||||
|
static mut CS_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE]> =
|
||||||
|
MaybeUninit::uninit();
|
||||||
|
|
||||||
|
#[link_section = "MB_MEM2"]
|
||||||
|
static mut EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
|
||||||
|
|
||||||
|
#[link_section = "MB_MEM2"]
|
||||||
|
static mut SYSTEM_EVT_QUEUE: MaybeUninit<LinkedListNode> = MaybeUninit::uninit();
|
||||||
|
|
||||||
|
#[link_section = "MB_MEM2"]
|
||||||
|
pub static mut SYS_CMD_BUF: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Queue length of BLE Event
|
||||||
|
* This parameter defines the number of asynchronous events that can be stored in the HCI layer before
|
||||||
|
* being reported to the application. When a command is sent to the BLE core coprocessor, the HCI layer
|
||||||
|
* is waiting for the event with the Num_HCI_Command_Packets set to 1. The receive queue shall be large
|
||||||
|
* enough to store all asynchronous events received in between.
|
||||||
|
* When CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE is set to 27, this allow to store three 255 bytes long asynchronous events
|
||||||
|
* between the HCI command and its event.
|
||||||
|
* This parameter depends on the value given to CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE. When the queue size is to small,
|
||||||
|
* the system may hang if the queue is full with asynchronous events and the HCI layer is still waiting
|
||||||
|
* for a CC/CS event, In that case, the notification TL_BLE_HCI_ToNot() is called to indicate
|
||||||
|
* to the application a HCI command did not receive its command event within 30s (Default HCI Timeout).
|
||||||
|
*/
|
||||||
|
const CFG_TLBLE_EVT_QUEUE_LENGTH: usize = 5;
|
||||||
|
const CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE: usize = 255;
|
||||||
|
const TL_BLE_EVENT_FRAME_SIZE: usize = TL_EVT_HEADER_SIZE + CFG_TLBLE_MOST_EVENT_PAYLOAD_SIZE;
|
||||||
|
|
||||||
|
const fn divc(x: usize, y: usize) -> usize {
|
||||||
|
((x) + (y) - 1) / (y)
|
||||||
|
}
|
||||||
|
|
||||||
|
const POOL_SIZE: usize = CFG_TLBLE_EVT_QUEUE_LENGTH * 4 * divc(TL_PACKET_HEADER_SIZE + TL_BLE_EVENT_FRAME_SIZE, 4);
|
||||||
|
|
||||||
|
#[link_section = "MB_MEM2"]
|
||||||
|
static mut EVT_POOL: MaybeUninit<[u8; POOL_SIZE]> = MaybeUninit::uninit();
|
||||||
|
|
||||||
|
#[link_section = "MB_MEM2"]
|
||||||
|
static mut SYS_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> =
|
||||||
|
MaybeUninit::uninit();
|
||||||
|
|
||||||
|
#[link_section = "MB_MEM2"]
|
||||||
|
static mut BLE_SPARE_EVT_BUF: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255]> =
|
||||||
|
MaybeUninit::uninit();
|
||||||
|
|
||||||
|
#[link_section = "MB_MEM2"]
|
||||||
|
static mut BLE_CMD_BUFFER: MaybeUninit<CmdPacket> = MaybeUninit::uninit();
|
||||||
|
|
||||||
|
#[link_section = "MB_MEM2"]
|
||||||
|
// fuck these "magic" numbers from ST ---v---v
|
||||||
|
static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; TL_PACKET_HEADER_SIZE + 5 + 251]> = MaybeUninit::uninit();
|
||||||
|
|
||||||
|
// TODO: remove these items
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
/// current event that is produced during IPCC IRQ handler execution
|
||||||
|
/// on SYS channel
|
||||||
|
static EVT_CHANNEL: Channel<CriticalSectionRawMutex, EvtBox, 32> = Channel::new();
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
/// last received Command Complete event
|
||||||
|
static LAST_CC_EVT: Signal<CriticalSectionRawMutex, CcEvt> = Signal::new();
|
||||||
|
|
||||||
|
static STATE: Signal<CriticalSectionRawMutex, ()> = Signal::new();
|
||||||
|
|
||||||
|
pub struct TlMbox<'d> {
|
||||||
|
_ipcc: PeripheralRef<'d, IPCC>,
|
||||||
|
|
||||||
|
pub sys_subsystem: Sys,
|
||||||
|
pub mm_subsystem: MemoryManager,
|
||||||
|
pub ble_subsystem: Ble,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d> TlMbox<'d> {
|
||||||
|
pub fn init(
|
||||||
|
ipcc: impl Peripheral<P = IPCC> + 'd,
|
||||||
|
_irqs: impl interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_RX, ReceiveInterruptHandler>
|
||||||
|
+ interrupt::typelevel::Binding<interrupt::typelevel::IPCC_C1_TX, TransmitInterruptHandler>,
|
||||||
|
config: Config,
|
||||||
|
) -> Self {
|
||||||
|
into_ref!(ipcc);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
TL_REF_TABLE.as_mut_ptr().write_volatile(RefTable {
|
||||||
|
device_info_table: TL_DEVICE_INFO_TABLE.as_ptr(),
|
||||||
|
ble_table: TL_BLE_TABLE.as_ptr(),
|
||||||
|
thread_table: TL_THREAD_TABLE.as_ptr(),
|
||||||
|
sys_table: TL_SYS_TABLE.as_ptr(),
|
||||||
|
mem_manager_table: TL_MEM_MANAGER_TABLE.as_ptr(),
|
||||||
|
traces_table: TL_TRACES_TABLE.as_ptr(),
|
||||||
|
mac_802_15_4_table: TL_MAC_802_15_4_TABLE.as_ptr(),
|
||||||
|
// zigbee_table: TL_ZIGBEE_TABLE.as_ptr(),
|
||||||
|
// lld_tests_table: TL_LLD_TESTS_TABLE.as_ptr(),
|
||||||
|
// ble_lld_table: TL_BLE_LLD_TABLE.as_ptr(),
|
||||||
|
});
|
||||||
|
|
||||||
|
TL_SYS_TABLE
|
||||||
|
.as_mut_ptr()
|
||||||
|
.write_volatile(MaybeUninit::zeroed().assume_init());
|
||||||
|
TL_DEVICE_INFO_TABLE
|
||||||
|
.as_mut_ptr()
|
||||||
|
.write_volatile(MaybeUninit::zeroed().assume_init());
|
||||||
|
TL_BLE_TABLE
|
||||||
|
.as_mut_ptr()
|
||||||
|
.write_volatile(MaybeUninit::zeroed().assume_init());
|
||||||
|
TL_THREAD_TABLE
|
||||||
|
.as_mut_ptr()
|
||||||
|
.write_volatile(MaybeUninit::zeroed().assume_init());
|
||||||
|
TL_MEM_MANAGER_TABLE
|
||||||
|
.as_mut_ptr()
|
||||||
|
.write_volatile(MaybeUninit::zeroed().assume_init());
|
||||||
|
|
||||||
|
TL_TRACES_TABLE
|
||||||
|
.as_mut_ptr()
|
||||||
|
.write_volatile(MaybeUninit::zeroed().assume_init());
|
||||||
|
TL_MAC_802_15_4_TABLE
|
||||||
|
.as_mut_ptr()
|
||||||
|
.write_volatile(MaybeUninit::zeroed().assume_init());
|
||||||
|
// TL_ZIGBEE_TABLE
|
||||||
|
// .as_mut_ptr()
|
||||||
|
// .write_volatile(MaybeUninit::zeroed().assume_init());
|
||||||
|
// TL_LLD_TESTS_TABLE
|
||||||
|
// .as_mut_ptr()
|
||||||
|
// .write_volatile(MaybeUninit::zeroed().assume_init());
|
||||||
|
// TL_BLE_LLD_TABLE
|
||||||
|
// .as_mut_ptr()
|
||||||
|
// .write_volatile(MaybeUninit::zeroed().assume_init());
|
||||||
|
|
||||||
|
EVT_POOL
|
||||||
|
.as_mut_ptr()
|
||||||
|
.write_volatile(MaybeUninit::zeroed().assume_init());
|
||||||
|
SYS_SPARE_EVT_BUF
|
||||||
|
.as_mut_ptr()
|
||||||
|
.write_volatile(MaybeUninit::zeroed().assume_init());
|
||||||
|
BLE_SPARE_EVT_BUF
|
||||||
|
.as_mut_ptr()
|
||||||
|
.write_volatile(MaybeUninit::zeroed().assume_init());
|
||||||
|
|
||||||
|
{
|
||||||
|
BLE_CMD_BUFFER
|
||||||
|
.as_mut_ptr()
|
||||||
|
.write_volatile(MaybeUninit::zeroed().assume_init());
|
||||||
|
HCI_ACL_DATA_BUFFER
|
||||||
|
.as_mut_ptr()
|
||||||
|
.write_volatile(MaybeUninit::zeroed().assume_init());
|
||||||
|
CS_BUFFER
|
||||||
|
.as_mut_ptr()
|
||||||
|
.write_volatile(MaybeUninit::zeroed().assume_init());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
|
Ipcc::enable(config);
|
||||||
|
|
||||||
|
let sys = sys::Sys::new();
|
||||||
|
let ble = ble::Ble::new();
|
||||||
|
let mm = mm::MemoryManager::new();
|
||||||
|
|
||||||
|
// enable interrupts
|
||||||
|
interrupt::typelevel::IPCC_C1_RX::unpend();
|
||||||
|
interrupt::typelevel::IPCC_C1_TX::unpend();
|
||||||
|
|
||||||
|
unsafe { interrupt::typelevel::IPCC_C1_RX::enable() };
|
||||||
|
unsafe { interrupt::typelevel::IPCC_C1_TX::enable() };
|
||||||
|
|
||||||
|
STATE.reset();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
_ipcc: ipcc,
|
||||||
|
sys_subsystem: sys,
|
||||||
|
ble_subsystem: ble,
|
||||||
|
mm_subsystem: mm,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
77
embassy-stm32-wpan/src/mm.rs
Normal file
77
embassy-stm32-wpan/src/mm.rs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
//! Memory manager routines
|
||||||
|
|
||||||
|
use core::future::poll_fn;
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
use core::task::Poll;
|
||||||
|
|
||||||
|
use cortex_m::interrupt;
|
||||||
|
use embassy_stm32::ipcc::Ipcc;
|
||||||
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
|
|
||||||
|
use crate::evt::EvtPacket;
|
||||||
|
use crate::tables::MemManagerTable;
|
||||||
|
use crate::unsafe_linked_list::LinkedListNode;
|
||||||
|
use crate::{
|
||||||
|
channels, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUF_QUEUE, LOCAL_FREE_BUF_QUEUE, POOL_SIZE, SYS_SPARE_EVT_BUF,
|
||||||
|
TL_MEM_MANAGER_TABLE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static MM_WAKER: AtomicWaker = AtomicWaker::new();
|
||||||
|
|
||||||
|
pub struct MemoryManager {
|
||||||
|
phantom: PhantomData<MemoryManager>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemoryManager {
|
||||||
|
pub(crate) fn new() -> Self {
|
||||||
|
unsafe {
|
||||||
|
LinkedListNode::init_head(FREE_BUF_QUEUE.as_mut_ptr());
|
||||||
|
LinkedListNode::init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr());
|
||||||
|
|
||||||
|
TL_MEM_MANAGER_TABLE.as_mut_ptr().write_volatile(MemManagerTable {
|
||||||
|
spare_ble_buffer: BLE_SPARE_EVT_BUF.as_ptr().cast(),
|
||||||
|
spare_sys_buffer: SYS_SPARE_EVT_BUF.as_ptr().cast(),
|
||||||
|
blepool: EVT_POOL.as_ptr().cast(),
|
||||||
|
blepoolsize: POOL_SIZE as u32,
|
||||||
|
pevt_free_buffer_queue: FREE_BUF_QUEUE.as_mut_ptr(),
|
||||||
|
traces_evt_pool: core::ptr::null(),
|
||||||
|
tracespoolsize: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Self { phantom: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// SAFETY: passing a pointer to something other than an event packet is UB
|
||||||
|
pub(crate) unsafe fn drop_event_packet(evt: *mut EvtPacket) {
|
||||||
|
interrupt::free(|_| unsafe {
|
||||||
|
LinkedListNode::insert_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), evt as *mut _);
|
||||||
|
});
|
||||||
|
|
||||||
|
MM_WAKER.wake();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn run_queue(&self) {
|
||||||
|
loop {
|
||||||
|
poll_fn(|cx| unsafe {
|
||||||
|
MM_WAKER.register(cx.waker());
|
||||||
|
if LinkedListNode::is_empty(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) {
|
||||||
|
Poll::Pending
|
||||||
|
} else {
|
||||||
|
Poll::Ready(())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
Ipcc::send(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, || {
|
||||||
|
interrupt::free(|_| unsafe {
|
||||||
|
// CS required while moving nodes
|
||||||
|
while let Some(node_ptr) = LinkedListNode::remove_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) {
|
||||||
|
LinkedListNode::insert_head(FREE_BUF_QUEUE.as_mut_ptr(), node_ptr);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +1,10 @@
|
|||||||
//! HCI commands for system channel
|
use core::{mem, slice};
|
||||||
|
|
||||||
use super::cmd::CmdPacket;
|
use super::{TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE};
|
||||||
use super::consts::TlPacketType;
|
|
||||||
use super::{channels, TL_CS_EVT_SIZE, TL_EVT_HEADER_SIZE, TL_PACKET_HEADER_SIZE, TL_SYS_TABLE};
|
|
||||||
use crate::tl_mbox::ipcc::Ipcc;
|
|
||||||
|
|
||||||
const SCHI_OPCODE_BLE_INIT: u16 = 0xfc66;
|
pub const SCHI_OPCODE_BLE_INIT: u16 = 0xfc66;
|
||||||
pub const TL_BLE_EVT_CS_PACKET_SIZE: usize = TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE;
|
|
||||||
#[allow(dead_code)]
|
|
||||||
const TL_BLE_EVT_CS_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_BLE_EVT_CS_PACKET_SIZE;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
pub struct ShciBleInitCmdParam {
|
pub struct ShciBleInitCmdParam {
|
||||||
/// NOT USED CURRENTLY
|
/// NOT USED CURRENTLY
|
||||||
@ -38,6 +32,12 @@ pub struct ShciBleInitCmdParam {
|
|||||||
pub hw_version: u8,
|
pub hw_version: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ShciBleInitCmdParam {
|
||||||
|
pub fn payload<'a>(&self) -> &'a [u8] {
|
||||||
|
unsafe { slice::from_raw_parts(self as *const _ as *const u8, mem::size_of::<Self>()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for ShciBleInitCmdParam {
|
impl Default for ShciBleInitCmdParam {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -63,39 +63,19 @@ impl Default for ShciBleInitCmdParam {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
pub struct ShciHeader {
|
pub struct ShciHeader {
|
||||||
metadata: [u32; 3],
|
metadata: [u32; 3],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
pub struct ShciBleInitCmdPacket {
|
pub struct ShciBleInitCmdPacket {
|
||||||
header: ShciHeader,
|
pub header: ShciHeader,
|
||||||
param: ShciBleInitCmdParam,
|
pub param: ShciBleInitCmdParam,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shci_ble_init(param: ShciBleInitCmdParam) {
|
pub const TL_BLE_EVT_CS_PACKET_SIZE: usize = TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE;
|
||||||
let mut packet = ShciBleInitCmdPacket {
|
#[allow(dead_code)] // Not used currently but reserved
|
||||||
header: ShciHeader::default(),
|
const TL_BLE_EVT_CS_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_BLE_EVT_CS_PACKET_SIZE;
|
||||||
param,
|
|
||||||
};
|
|
||||||
|
|
||||||
let packet_ptr: *mut ShciBleInitCmdPacket = &mut packet;
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let cmd_ptr: *mut CmdPacket = packet_ptr.cast();
|
|
||||||
|
|
||||||
(*cmd_ptr).cmd_serial.cmd.cmd_code = SCHI_OPCODE_BLE_INIT;
|
|
||||||
(*cmd_ptr).cmd_serial.cmd.payload_len = core::mem::size_of::<ShciBleInitCmdParam>() as u8;
|
|
||||||
|
|
||||||
let cmd_buf = &mut *(*TL_SYS_TABLE.as_mut_ptr()).pcmd_buffer;
|
|
||||||
core::ptr::write(cmd_buf, *cmd_ptr);
|
|
||||||
|
|
||||||
cmd_buf.cmd_serial.ty = TlPacketType::SysCmd as u8;
|
|
||||||
|
|
||||||
Ipcc::c1_set_flag_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL);
|
|
||||||
Ipcc::c1_set_tx_channel(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, true);
|
|
||||||
}
|
|
||||||
}
|
|
70
embassy-stm32-wpan/src/sys.rs
Normal file
70
embassy-stm32-wpan/src/sys.rs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use crate::cmd::CmdPacket;
|
||||||
|
use crate::consts::TlPacketType;
|
||||||
|
use crate::evt::EvtBox;
|
||||||
|
use crate::shci::{ShciBleInitCmdParam, SCHI_OPCODE_BLE_INIT};
|
||||||
|
use crate::tables::{SysTable, WirelessFwInfoTable};
|
||||||
|
use crate::unsafe_linked_list::LinkedListNode;
|
||||||
|
use crate::{channels, Ipcc, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_DEVICE_INFO_TABLE, TL_SYS_TABLE};
|
||||||
|
|
||||||
|
pub struct Sys {
|
||||||
|
phantom: PhantomData<Sys>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sys {
|
||||||
|
/// TL_Sys_Init
|
||||||
|
pub(crate) fn new() -> Self {
|
||||||
|
unsafe {
|
||||||
|
LinkedListNode::init_head(SYSTEM_EVT_QUEUE.as_mut_ptr());
|
||||||
|
|
||||||
|
TL_SYS_TABLE.as_mut_ptr().write_volatile(SysTable {
|
||||||
|
pcmd_buffer: SYS_CMD_BUF.as_mut_ptr(),
|
||||||
|
sys_queue: SYSTEM_EVT_QUEUE.as_ptr(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Self { phantom: PhantomData }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns CPU2 wireless firmware information (if present).
|
||||||
|
pub fn wireless_fw_info(&self) -> Option<WirelessFwInfoTable> {
|
||||||
|
let info = unsafe { TL_DEVICE_INFO_TABLE.as_mut_ptr().read_volatile().wireless_fw_info_table };
|
||||||
|
|
||||||
|
// Zero version indicates that CPU2 wasn't active and didn't fill the information table
|
||||||
|
if info.version != 0 {
|
||||||
|
Some(info)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(&self, opcode: u16, payload: &[u8]) {
|
||||||
|
unsafe {
|
||||||
|
CmdPacket::write_into(SYS_CMD_BUF.as_mut_ptr(), TlPacketType::SysCmd, opcode, payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn shci_c2_ble_init(&self, param: ShciBleInitCmdParam) {
|
||||||
|
debug!("sending SHCI");
|
||||||
|
|
||||||
|
Ipcc::send(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, || {
|
||||||
|
self.write(SCHI_OPCODE_BLE_INIT, param.payload());
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
Ipcc::flush(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `HW_IPCC_SYS_EvtNot`
|
||||||
|
pub async fn read(&self) -> EvtBox {
|
||||||
|
Ipcc::receive(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL, || unsafe {
|
||||||
|
if let Some(node_ptr) = LinkedListNode::remove_head(SYSTEM_EVT_QUEUE.as_mut_ptr()) {
|
||||||
|
Some(EvtBox::new(node_ptr.cast()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
175
embassy-stm32-wpan/src/tables.rs
Normal file
175
embassy-stm32-wpan/src/tables.rs
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
use bit_field::BitField;
|
||||||
|
|
||||||
|
use crate::cmd::{AclDataPacket, CmdPacket};
|
||||||
|
use crate::unsafe_linked_list::LinkedListNode;
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct SafeBootInfoTable {
|
||||||
|
version: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct RssInfoTable {
|
||||||
|
pub version: u32,
|
||||||
|
pub memory_size: u32,
|
||||||
|
pub rss_info: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Version
|
||||||
|
* [0:3] = Build - 0: Untracked - 15:Released - x: Tracked version
|
||||||
|
* [4:7] = branch - 0: Mass Market - x: ...
|
||||||
|
* [8:15] = Subversion
|
||||||
|
* [16:23] = Version minor
|
||||||
|
* [24:31] = Version major
|
||||||
|
*
|
||||||
|
* Memory Size
|
||||||
|
* [0:7] = Flash ( Number of 4k sector)
|
||||||
|
* [8:15] = Reserved ( Shall be set to 0 - may be used as flash extension )
|
||||||
|
* [16:23] = SRAM2b ( Number of 1k sector)
|
||||||
|
* [24:31] = SRAM2a ( Number of 1k sector)
|
||||||
|
*/
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
#[repr(C, packed)]
|
||||||
|
pub struct WirelessFwInfoTable {
|
||||||
|
pub version: u32,
|
||||||
|
pub memory_size: u32,
|
||||||
|
pub thread_info: u32,
|
||||||
|
pub ble_info: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WirelessFwInfoTable {
|
||||||
|
pub fn version_major(&self) -> u8 {
|
||||||
|
let version = self.version;
|
||||||
|
(version.get_bits(24..31) & 0xff) as u8
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn version_minor(&self) -> u8 {
|
||||||
|
let version = self.version;
|
||||||
|
(version.clone().get_bits(16..23) & 0xff) as u8
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subversion(&self) -> u8 {
|
||||||
|
let version = self.version;
|
||||||
|
(version.clone().get_bits(8..15) & 0xff) as u8
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Size of FLASH, expressed in number of 4K sectors.
|
||||||
|
pub fn flash_size(&self) -> u8 {
|
||||||
|
let memory_size = self.memory_size;
|
||||||
|
(memory_size.clone().get_bits(0..7) & 0xff) as u8
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Size of SRAM2a, expressed in number of 1K sectors.
|
||||||
|
pub fn sram2a_size(&self) -> u8 {
|
||||||
|
let memory_size = self.memory_size;
|
||||||
|
(memory_size.clone().get_bits(24..31) & 0xff) as u8
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Size of SRAM2b, expressed in number of 1K sectors.
|
||||||
|
pub fn sram2b_size(&self) -> u8 {
|
||||||
|
let memory_size = self.memory_size;
|
||||||
|
(memory_size.clone().get_bits(16..23) & 0xff) as u8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
#[repr(C, align(4))]
|
||||||
|
pub struct DeviceInfoTable {
|
||||||
|
pub safe_boot_info_table: SafeBootInfoTable,
|
||||||
|
pub rss_info_table: RssInfoTable,
|
||||||
|
pub wireless_fw_info_table: WirelessFwInfoTable,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C, align(4))]
|
||||||
|
pub struct BleTable {
|
||||||
|
pub pcmd_buffer: *mut CmdPacket,
|
||||||
|
pub pcs_buffer: *const u8,
|
||||||
|
pub pevt_queue: *const u8,
|
||||||
|
pub phci_acl_data_buffer: *mut AclDataPacket,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C, align(4))]
|
||||||
|
pub struct ThreadTable {
|
||||||
|
pub nostack_buffer: *const u8,
|
||||||
|
pub clicmdrsp_buffer: *const u8,
|
||||||
|
pub otcmdrsp_buffer: *const u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: use later
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C, align(4))]
|
||||||
|
pub struct LldTestsTable {
|
||||||
|
pub clicmdrsp_buffer: *const u8,
|
||||||
|
pub m0cmd_buffer: *const u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: use later
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C, align(4))]
|
||||||
|
pub struct BleLldTable {
|
||||||
|
pub cmdrsp_buffer: *const u8,
|
||||||
|
pub m0cmd_buffer: *const u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: use later
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C, align(4))]
|
||||||
|
pub struct ZigbeeTable {
|
||||||
|
pub notif_m0_to_m4_buffer: *const u8,
|
||||||
|
pub appli_cmd_m4_to_m0_bufer: *const u8,
|
||||||
|
pub request_m0_to_m4_buffer: *const u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C, align(4))]
|
||||||
|
pub struct SysTable {
|
||||||
|
pub pcmd_buffer: *mut CmdPacket,
|
||||||
|
pub sys_queue: *const LinkedListNode,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C, align(4))]
|
||||||
|
pub struct MemManagerTable {
|
||||||
|
pub spare_ble_buffer: *const u8,
|
||||||
|
pub spare_sys_buffer: *const u8,
|
||||||
|
|
||||||
|
pub blepool: *const u8,
|
||||||
|
pub blepoolsize: u32,
|
||||||
|
|
||||||
|
pub pevt_free_buffer_queue: *mut LinkedListNode,
|
||||||
|
|
||||||
|
pub traces_evt_pool: *const u8,
|
||||||
|
pub tracespoolsize: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C, align(4))]
|
||||||
|
pub struct TracesTable {
|
||||||
|
pub traces_queue: *const u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C, align(4))]
|
||||||
|
pub struct Mac802_15_4Table {
|
||||||
|
pub p_cmdrsp_buffer: *const u8,
|
||||||
|
pub p_notack_buffer: *const u8,
|
||||||
|
pub evt_queue: *const u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reference table. Contains pointers to all other tables.
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct RefTable {
|
||||||
|
pub device_info_table: *const DeviceInfoTable,
|
||||||
|
pub ble_table: *const BleTable,
|
||||||
|
pub thread_table: *const ThreadTable,
|
||||||
|
pub sys_table: *const SysTable,
|
||||||
|
pub mem_manager_table: *const MemManagerTable,
|
||||||
|
pub traces_table: *const TracesTable,
|
||||||
|
pub mac_802_15_4_table: *const Mac802_15_4Table,
|
||||||
|
}
|
257
embassy-stm32-wpan/src/unsafe_linked_list.rs
Normal file
257
embassy-stm32-wpan/src/unsafe_linked_list.rs
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
//! Unsafe linked list.
|
||||||
|
//! Translated from ST's C by `c2rust` tool.
|
||||||
|
|
||||||
|
#![allow(
|
||||||
|
dead_code,
|
||||||
|
mutable_transmutes,
|
||||||
|
non_camel_case_types,
|
||||||
|
non_snake_case,
|
||||||
|
non_upper_case_globals,
|
||||||
|
unused_assignments,
|
||||||
|
unused_mut
|
||||||
|
)]
|
||||||
|
|
||||||
|
use core::ptr;
|
||||||
|
|
||||||
|
use cortex_m::interrupt;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
#[repr(C, packed(4))]
|
||||||
|
pub struct LinkedListNode {
|
||||||
|
pub next: *mut LinkedListNode,
|
||||||
|
pub prev: *mut LinkedListNode,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for LinkedListNode {
|
||||||
|
fn default() -> Self {
|
||||||
|
LinkedListNode {
|
||||||
|
next: core::ptr::null_mut(),
|
||||||
|
prev: core::ptr::null_mut(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LinkedListNode {
|
||||||
|
pub unsafe fn init_head(mut p_list_head: *mut LinkedListNode) {
|
||||||
|
ptr::write_volatile(
|
||||||
|
p_list_head,
|
||||||
|
LinkedListNode {
|
||||||
|
next: p_list_head,
|
||||||
|
prev: p_list_head,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn is_empty(mut p_list_head: *mut LinkedListNode) -> bool {
|
||||||
|
interrupt::free(|_| ptr::read_volatile(p_list_head).next == p_list_head)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Insert `node` after `list_head` and before the next node
|
||||||
|
pub unsafe fn insert_head(mut p_list_head: *mut LinkedListNode, mut p_node: *mut LinkedListNode) {
|
||||||
|
interrupt::free(|_| {
|
||||||
|
let mut list_head = ptr::read_volatile(p_list_head);
|
||||||
|
if p_list_head != list_head.next {
|
||||||
|
let mut node_next = ptr::read_volatile(list_head.next);
|
||||||
|
let node = LinkedListNode {
|
||||||
|
next: list_head.next,
|
||||||
|
prev: p_list_head,
|
||||||
|
};
|
||||||
|
|
||||||
|
list_head.next = p_node;
|
||||||
|
node_next.prev = p_node;
|
||||||
|
|
||||||
|
// All nodes must be written because they will all be seen by another core
|
||||||
|
ptr::write_volatile(p_node, node);
|
||||||
|
ptr::write_volatile(node.next, node_next);
|
||||||
|
ptr::write_volatile(p_list_head, list_head);
|
||||||
|
} else {
|
||||||
|
let node = LinkedListNode {
|
||||||
|
next: list_head.next,
|
||||||
|
prev: p_list_head,
|
||||||
|
};
|
||||||
|
|
||||||
|
list_head.next = p_node;
|
||||||
|
list_head.prev = p_node;
|
||||||
|
|
||||||
|
// All nodes must be written because they will all be seen by another core
|
||||||
|
ptr::write_volatile(p_node, node);
|
||||||
|
ptr::write_volatile(p_list_head, list_head);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Insert `node` before `list_tail` and after the second-to-last node
|
||||||
|
pub unsafe fn insert_tail(mut p_list_tail: *mut LinkedListNode, mut p_node: *mut LinkedListNode) {
|
||||||
|
interrupt::free(|_| {
|
||||||
|
let mut list_tail = ptr::read_volatile(p_list_tail);
|
||||||
|
if p_list_tail != list_tail.prev {
|
||||||
|
let mut node_prev = ptr::read_volatile(list_tail.prev);
|
||||||
|
let node = LinkedListNode {
|
||||||
|
next: p_list_tail,
|
||||||
|
prev: list_tail.prev,
|
||||||
|
};
|
||||||
|
|
||||||
|
list_tail.prev = p_node;
|
||||||
|
node_prev.next = p_node;
|
||||||
|
|
||||||
|
// All nodes must be written because they will all be seen by another core
|
||||||
|
ptr::write_volatile(p_node, node);
|
||||||
|
ptr::write_volatile(node.prev, node_prev);
|
||||||
|
ptr::write_volatile(p_list_tail, list_tail);
|
||||||
|
} else {
|
||||||
|
let node = LinkedListNode {
|
||||||
|
next: p_list_tail,
|
||||||
|
prev: list_tail.prev,
|
||||||
|
};
|
||||||
|
|
||||||
|
list_tail.prev = p_node;
|
||||||
|
list_tail.next = p_node;
|
||||||
|
|
||||||
|
// All nodes must be written because they will all be seen by another core
|
||||||
|
ptr::write_volatile(p_node, node);
|
||||||
|
ptr::write_volatile(p_list_tail, list_tail);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove `node` from the linked list
|
||||||
|
pub unsafe fn remove_node(mut p_node: *mut LinkedListNode) {
|
||||||
|
interrupt::free(|_| {
|
||||||
|
// trace!("remove node: {:x}", p_node);
|
||||||
|
// apparently linked list nodes are not always aligned.
|
||||||
|
// if more hardfaults occur, more of these may need to be converted to unaligned.
|
||||||
|
let node = ptr::read_unaligned(p_node);
|
||||||
|
// trace!("remove node: prev/next {:x}/{:x}", node.prev, node.next);
|
||||||
|
|
||||||
|
if node.next != node.prev {
|
||||||
|
let mut node_next = ptr::read_volatile(node.next);
|
||||||
|
let mut node_prev = ptr::read_volatile(node.prev);
|
||||||
|
|
||||||
|
node_prev.next = node.next;
|
||||||
|
node_next.prev = node.prev;
|
||||||
|
|
||||||
|
ptr::write_volatile(node.next, node_next);
|
||||||
|
ptr::write_volatile(node.prev, node_prev);
|
||||||
|
} else {
|
||||||
|
let mut node_next = ptr::read_volatile(node.next);
|
||||||
|
|
||||||
|
node_next.next = node.next;
|
||||||
|
node_next.prev = node.prev;
|
||||||
|
|
||||||
|
ptr::write_volatile(node.next, node_next);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove `list_head` and return a pointer to the `node`.
|
||||||
|
pub unsafe fn remove_head(mut p_list_head: *mut LinkedListNode) -> Option<*mut LinkedListNode> {
|
||||||
|
interrupt::free(|_| {
|
||||||
|
let list_head = ptr::read_volatile(p_list_head);
|
||||||
|
|
||||||
|
if list_head.next == p_list_head {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
// Allowed because a removed node is not seen by another core
|
||||||
|
let p_node = list_head.next;
|
||||||
|
Self::remove_node(p_node);
|
||||||
|
|
||||||
|
Some(p_node)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove `list_tail` and return a pointer to the `node`.
|
||||||
|
pub unsafe fn remove_tail(mut p_list_tail: *mut LinkedListNode) -> Option<*mut LinkedListNode> {
|
||||||
|
interrupt::free(|_| {
|
||||||
|
let list_tail = ptr::read_volatile(p_list_tail);
|
||||||
|
|
||||||
|
if list_tail.prev == p_list_tail {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
// Allowed because a removed node is not seen by another core
|
||||||
|
let p_node = list_tail.prev;
|
||||||
|
Self::remove_node(p_node);
|
||||||
|
|
||||||
|
Some(p_node)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn insert_node_after(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) {
|
||||||
|
interrupt::free(|_| {
|
||||||
|
(*node).next = (*ref_node).next;
|
||||||
|
(*node).prev = ref_node;
|
||||||
|
(*ref_node).next = node;
|
||||||
|
(*(*node).next).prev = node;
|
||||||
|
});
|
||||||
|
|
||||||
|
todo!("this function has not been converted to volatile semantics");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn insert_node_before(mut node: *mut LinkedListNode, mut ref_node: *mut LinkedListNode) {
|
||||||
|
interrupt::free(|_| {
|
||||||
|
(*node).next = ref_node;
|
||||||
|
(*node).prev = (*ref_node).prev;
|
||||||
|
(*ref_node).prev = node;
|
||||||
|
(*(*node).prev).next = node;
|
||||||
|
});
|
||||||
|
|
||||||
|
todo!("this function has not been converted to volatile semantics");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn get_size(mut list_head: *mut LinkedListNode) -> usize {
|
||||||
|
interrupt::free(|_| {
|
||||||
|
let mut size = 0;
|
||||||
|
let mut temp: *mut LinkedListNode = core::ptr::null_mut::<LinkedListNode>();
|
||||||
|
|
||||||
|
temp = (*list_head).next;
|
||||||
|
while temp != list_head {
|
||||||
|
size += 1;
|
||||||
|
temp = (*temp).next
|
||||||
|
}
|
||||||
|
|
||||||
|
size
|
||||||
|
});
|
||||||
|
|
||||||
|
todo!("this function has not been converted to volatile semantics");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn get_next_node(mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode {
|
||||||
|
interrupt::free(|_| {
|
||||||
|
let ref_node = ptr::read_volatile(p_ref_node);
|
||||||
|
|
||||||
|
// Allowed because a removed node is not seen by another core
|
||||||
|
ref_node.next
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn get_prev_node(mut p_ref_node: *mut LinkedListNode) -> *mut LinkedListNode {
|
||||||
|
interrupt::free(|_| {
|
||||||
|
let ref_node = ptr::read_volatile(p_ref_node);
|
||||||
|
|
||||||
|
// Allowed because a removed node is not seen by another core
|
||||||
|
ref_node.prev
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
unsafe fn debug_linked_list(mut p_node: *mut LinkedListNode) {
|
||||||
|
info!("iterating list from node: {:x}", p_node);
|
||||||
|
let mut p_current_node = p_node;
|
||||||
|
let mut i = 0;
|
||||||
|
loop {
|
||||||
|
let current_node = ptr::read_volatile(p_current_node);
|
||||||
|
info!(
|
||||||
|
"node (prev, current, next): {:x}, {:x}, {:x}",
|
||||||
|
current_node.prev, p_current_node, current_node.next
|
||||||
|
);
|
||||||
|
|
||||||
|
i += 1;
|
||||||
|
if i > 10 || current_node.next == p_node {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
p_current_node = current_node.next;
|
||||||
|
}
|
||||||
|
}
|
@ -32,11 +32,9 @@ flavors = [
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
|
||||||
embassy-executor = { version = "0.2.0", path = "../embassy-executor" }
|
|
||||||
embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true }
|
embassy-time = { version = "0.1.0", path = "../embassy-time", optional = true }
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||||
embassy-cortex-m = { version = "0.1.0", path = "../embassy-cortex-m", features = ["prio-bits-4"]}
|
embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common", features = ["cortex-m", "prio-bits-4"] }
|
||||||
embassy-hal-common = {version = "0.1.0", path = "../embassy-hal-common" }
|
|
||||||
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||||
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
|
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
|
||||||
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true }
|
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true }
|
||||||
@ -59,7 +57,7 @@ sdio-host = "0.5.0"
|
|||||||
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
|
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
|
||||||
critical-section = "1.1"
|
critical-section = "1.1"
|
||||||
atomic-polyfill = "1.0.1"
|
atomic-polyfill = "1.0.1"
|
||||||
stm32-metapac = "9"
|
stm32-metapac = "10"
|
||||||
vcell = "0.1.3"
|
vcell = "0.1.3"
|
||||||
bxcan = "0.7.0"
|
bxcan = "0.7.0"
|
||||||
nb = "1.0.0"
|
nb = "1.0.0"
|
||||||
@ -76,11 +74,13 @@ critical-section = { version = "1.1", features = ["std"] }
|
|||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
proc-macro2 = "1.0.36"
|
proc-macro2 = "1.0.36"
|
||||||
quote = "1.0.15"
|
quote = "1.0.15"
|
||||||
stm32-metapac = { version = "9", default-features = false, features = ["metadata"]}
|
stm32-metapac = { version = "10", default-features = false, features = ["metadata"]}
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["stm32-metapac/rt"]
|
default = ["rt"]
|
||||||
defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-executor/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "embedded-io?/defmt", "embassy-usb-driver?/defmt", "embassy-net-driver/defmt"]
|
rt = ["stm32-metapac/rt"]
|
||||||
|
|
||||||
|
defmt = ["dep:defmt", "bxcan/unstable-defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt", "embedded-io?/defmt", "embassy-usb-driver?/defmt", "embassy-net-driver/defmt"]
|
||||||
memory-x = ["stm32-metapac/memory-x"]
|
memory-x = ["stm32-metapac/memory-x"]
|
||||||
exti = []
|
exti = []
|
||||||
|
|
||||||
@ -99,7 +99,7 @@ time-driver-tim12 = ["_time-driver"]
|
|||||||
time-driver-tim15 = ["_time-driver"]
|
time-driver-tim15 = ["_time-driver"]
|
||||||
|
|
||||||
# Enable nightly-only features
|
# Enable nightly-only features
|
||||||
nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "dep:embedded-io", "dep:embassy-usb-driver", "embassy-embedded-hal/nightly"]
|
nightly = ["embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "dep:embedded-io", "dep:embassy-usb-driver", "embassy-embedded-hal/nightly"]
|
||||||
|
|
||||||
# Reexport stm32-metapac at `embassy_stm32::pac`.
|
# Reexport stm32-metapac at `embassy_stm32::pac`.
|
||||||
# This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version.
|
# This is unstable because semver-minor (non-breaking) releases of embassy-stm32 may major-bump (breaking) the stm32-metapac version.
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user