aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.github/ci/build-nightly.sh2
-rwxr-xr-x.github/ci/build-xtensa.sh2
-rwxr-xr-x.github/ci/build.sh2
-rwxr-xr-x.github/ci/crlf.sh17
-rwxr-xr-x.github/ci/doc.sh54
-rwxr-xr-x.github/ci/janitor.sh15
-rw-r--r--cyw43-pio/Cargo.toml3
-rw-r--r--cyw43/CHANGELOG.md3
-rw-r--r--cyw43/Cargo.toml2
-rw-r--r--cyw43/src/control.rs2
-rw-r--r--docs/examples/basic/Cargo.toml2
-rw-r--r--embassy-boot-nrf/CHANGELOG.md4
-rw-r--r--embassy-boot-nrf/Cargo.toml7
-rw-r--r--embassy-boot/Cargo.toml2
-rw-r--r--embassy-embedded-hal/Cargo.toml1
-rw-r--r--embassy-embedded-hal/src/adapter/yielding_async.rs2
-rw-r--r--embassy-executor/Cargo.toml6
-rw-r--r--embassy-executor/src/raw/mod.rs2
-rw-r--r--embassy-executor/tests/ui/spawn_nonsend.rs2
-rw-r--r--embassy-executor/tests/ui/spawn_nonsend.stderr22
-rw-r--r--embassy-executor/tests/ui/unsafe_op_in_unsafe_task.stderr2
-rw-r--r--embassy-futures/Cargo.toml4
-rw-r--r--embassy-hal-internal/Cargo.toml3
-rw-r--r--embassy-hal-internal/src/atomic_ring_buffer.rs43
-rw-r--r--embassy-imxrt/Cargo.toml2
-rw-r--r--embassy-net-driver-channel/Cargo.toml4
-rw-r--r--embassy-net-driver/Cargo.toml3
-rw-r--r--embassy-net-enc28j60/Cargo.toml4
-rw-r--r--embassy-net-wiznet/Cargo.toml3
-rw-r--r--embassy-net/Cargo.toml2
-rw-r--r--embassy-nrf/CHANGELOG.md10
-rw-r--r--embassy-nrf/Cargo.toml5
-rw-r--r--embassy-nrf/src/buffered_uarte.rs229
-rw-r--r--embassy-nrf/src/chips/nrf51.rs5
-rw-r--r--embassy-nrf/src/chips/nrf52805.rs7
-rw-r--r--embassy-nrf/src/chips/nrf52810.rs5
-rw-r--r--embassy-nrf/src/chips/nrf52811.rs5
-rw-r--r--embassy-nrf/src/chips/nrf52820.rs5
-rw-r--r--embassy-nrf/src/chips/nrf52832.rs6
-rw-r--r--embassy-nrf/src/chips/nrf52833.rs6
-rw-r--r--embassy-nrf/src/chips/nrf52840.rs6
-rw-r--r--embassy-nrf/src/chips/nrf5340_app.rs5
-rw-r--r--embassy-nrf/src/chips/nrf5340_net.rs5
-rw-r--r--embassy-nrf/src/chips/nrf9120.rs5
-rw-r--r--embassy-nrf/src/chips/nrf9160.rs5
-rw-r--r--embassy-nrf/src/egu.rs42
-rw-r--r--embassy-nrf/src/embassy_net_802154_driver.rs8
-rw-r--r--embassy-nrf/src/gpio.rs31
-rw-r--r--embassy-nrf/src/gpiote.rs18
-rw-r--r--embassy-nrf/src/i2s.rs178
-rw-r--r--embassy-nrf/src/ipc.rs132
-rw-r--r--embassy-nrf/src/lib.rs4
-rw-r--r--embassy-nrf/src/pdm.rs107
-rw-r--r--embassy-nrf/src/ppi/dppi.rs9
-rw-r--r--embassy-nrf/src/ppi/mod.rs8
-rw-r--r--embassy-nrf/src/ppi/ppi.rs9
-rw-r--r--embassy-nrf/src/pwm.rs147
-rw-r--r--embassy-nrf/src/qdec.rs39
-rwxr-xr-xembassy-nrf/src/qspi.rs113
-rw-r--r--embassy-nrf/src/radio/ieee802154.rs58
-rw-r--r--embassy-nrf/src/rng.rs56
-rw-r--r--embassy-nrf/src/rtc.rs274
-rw-r--r--embassy-nrf/src/saadc.rs13
-rw-r--r--embassy-nrf/src/spim.rs64
-rw-r--r--embassy-nrf/src/spis.rs50
-rw-r--r--embassy-nrf/src/timer.rs110
-rw-r--r--embassy-nrf/src/twim.rs77
-rw-r--r--embassy-nrf/src/twis.rs67
-rw-r--r--embassy-nrf/src/uarte.rs148
-rw-r--r--embassy-nrf/src/usb/mod.rs149
-rw-r--r--embassy-nrf/src/usb/vbus_detect.rs2
-rw-r--r--embassy-nrf/src/wdt.rs19
-rw-r--r--embassy-nxp/CHANGELOG.md1
-rw-r--r--embassy-nxp/Cargo.toml2
-rw-r--r--embassy-nxp/src/chips/lpc55.rs30
-rw-r--r--embassy-nxp/src/dma.rs5
-rw-r--r--embassy-nxp/src/dma/lpc55.rs377
-rw-r--r--embassy-nxp/src/lib.rs72
-rw-r--r--embassy-nxp/src/usart/lpc55.rs310
-rw-r--r--embassy-rp/CHANGELOG.md2
-rw-r--r--embassy-rp/Cargo.toml4
-rw-r--r--embassy-rp/src/lib.rs14
-rw-r--r--embassy-rp/src/rom_data/rp235x.rs32
-rw-r--r--embassy-stm32/CHANGELOG.md9
-rw-r--r--embassy-stm32/Cargo.toml12
-rw-r--r--embassy-stm32/src/rcc/bd.rs10
-rw-r--r--embassy-stm32/src/rcc/c0.rs14
-rw-r--r--embassy-stm32/src/rcc/mco.rs23
-rw-r--r--embassy-stm32/src/rtc/low_power.rs36
-rw-r--r--embassy-stm32/src/rtc/mod.rs21
-rw-r--r--embassy-stm32/src/rtc/v2.rs8
-rw-r--r--embassy-stm32/src/timer/qei.rs100
-rw-r--r--embassy-stm32/src/usart/buffered.rs67
-rw-r--r--embassy-stm32/src/usart/mod.rs71
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs118
-rw-r--r--embassy-sync/Cargo.toml2
-rw-r--r--embassy-sync/src/blocking_mutex/mod.rs4
-rw-r--r--embassy-sync/src/blocking_mutex/raw.rs4
-rw-r--r--embassy-sync/src/rwlock.rs2
-rw-r--r--embassy-sync/tests/ui/sync_impl/lazy_lock_function.stderr8
-rw-r--r--embassy-time-driver/src/lib.rs2
-rw-r--r--embassy-time/CHANGELOG.md2
-rw-r--r--embassy-time/Cargo.toml5
-rw-r--r--embassy-time/src/duration.rs5
-rw-r--r--embassy-time/src/instant.rs25
-rw-r--r--embassy-usb-dfu/Cargo.toml3
-rw-r--r--embassy-usb-driver/Cargo.toml3
-rw-r--r--embassy-usb-driver/src/lib.rs4
-rw-r--r--embassy-usb-synopsys-otg/Cargo.toml4
-rw-r--r--embassy-usb/Cargo.toml1
-rw-r--r--examples/boot/application/nrf/Cargo.toml4
-rw-r--r--examples/lpc55s69/src/bin/usart_async.rs70
-rw-r--r--examples/mimxrt1011/Cargo.toml2
-rw-r--r--examples/mimxrt1062-evk/Cargo.toml2
-rw-r--r--examples/mimxrt6/Cargo.toml2
-rw-r--r--examples/nrf-rtos-trace/Cargo.toml2
-rw-r--r--examples/nrf51/Cargo.toml2
-rw-r--r--examples/nrf52810/Cargo.toml2
-rw-r--r--examples/nrf52810/src/bin/saadc_lowpower.rs62
-rw-r--r--examples/nrf52840-edf/Cargo.toml2
-rw-r--r--examples/nrf52840-rtic/Cargo.toml2
-rw-r--r--examples/nrf52840/Cargo.toml3
-rw-r--r--examples/nrf52840/src/bin/ethernet_enc28j60.rs2
-rw-r--r--examples/nrf52840/src/bin/rtc.rs56
-rw-r--r--examples/nrf52840/src/bin/sixlowpan.rs2
-rw-r--r--examples/nrf52840/src/bin/uart_split.rs2
-rw-r--r--examples/nrf52840/src/bin/usb_ethernet.rs2
-rw-r--r--examples/nrf52840/src/bin/usb_serial.rs6
-rw-r--r--examples/nrf52840/src/bin/usb_serial_multitask.rs2
-rw-r--r--examples/nrf52840/src/bin/usb_serial_winusb.rs6
-rw-r--r--examples/nrf52840/src/bin/wifi_esp_hosted.rs2
-rw-r--r--examples/nrf5340/Cargo.toml2
-rw-r--r--examples/nrf54l15/Cargo.toml2
-rw-r--r--examples/nrf9151/ns/Cargo.toml2
-rw-r--r--examples/nrf9151/s/Cargo.toml2
-rw-r--r--examples/nrf9160/Cargo.toml2
-rw-r--r--examples/nrf9160/src/bin/modem_tcp_client.rs2
-rw-r--r--examples/rp235x/src/bin/multicore_stack_overflow.rs72
-rw-r--r--examples/stm32f4/src/bin/mco.rs18
-rw-r--r--examples/stm32h5/src/bin/mco.rs29
-rw-r--r--examples/stm32h7/src/bin/camera.rs11
-rw-r--r--examples/stm32h7/src/bin/mco.rs10
-rw-r--r--examples/stm32h7rs/src/bin/mco.rs10
-rw-r--r--examples/stm32l4/src/bin/mco.rs10
-rw-r--r--rust-toolchain-nightly.toml2
-rw-r--r--rust-toolchain.toml2
-rw-r--r--tests/nrf/Cargo.toml2
-rw-r--r--tests/nrf/src/bin/ethernet_enc28j60_perf.rs2
-rw-r--r--tests/nrf/src/bin/wifi_esp_hosted_perf.rs2
-rw-r--r--tests/perf-client/Cargo.toml1
-rw-r--r--tests/perf-server/Cargo.toml1
-rw-r--r--tests/stm32/src/bin/afio.rs10
-rw-r--r--tests/utils/Cargo.toml1
153 files changed, 3140 insertions, 1165 deletions
diff --git a/.github/ci/build-nightly.sh b/.github/ci/build-nightly.sh
index 2d7c4db3f..8cca1b445 100755
--- a/.github/ci/build-nightly.sh
+++ b/.github/ci/build-nightly.sh
@@ -23,7 +23,7 @@ fi
23hashtime restore /ci/cache/filetime.json || true 23hashtime restore /ci/cache/filetime.json || true
24hashtime save /ci/cache/filetime.json 24hashtime save /ci/cache/filetime.json
25 25
26cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 280829ad163f1444999468a57d28fb7c412babbe 26cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 676e6d602bf016dc71f1e98f2c7f191d7bd20707
27 27
28./ci-nightly.sh 28./ci-nightly.sh
29 29
diff --git a/.github/ci/build-xtensa.sh b/.github/ci/build-xtensa.sh
index b6626639d..dbd2f7ffc 100755
--- a/.github/ci/build-xtensa.sh
+++ b/.github/ci/build-xtensa.sh
@@ -25,7 +25,7 @@ fi
25hashtime restore /ci/cache/filetime.json || true 25hashtime restore /ci/cache/filetime.json || true
26hashtime save /ci/cache/filetime.json 26hashtime save /ci/cache/filetime.json
27 27
28cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 280829ad163f1444999468a57d28fb7c412babbe 28cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 676e6d602bf016dc71f1e98f2c7f191d7bd20707
29 29
30./ci-xtensa.sh 30./ci-xtensa.sh
31 31
diff --git a/.github/ci/build.sh b/.github/ci/build.sh
index 59bcefed6..d5e0e0bd2 100755
--- a/.github/ci/build.sh
+++ b/.github/ci/build.sh
@@ -28,7 +28,7 @@ fi
28hashtime restore /ci/cache/filetime.json || true 28hashtime restore /ci/cache/filetime.json || true
29hashtime save /ci/cache/filetime.json 29hashtime save /ci/cache/filetime.json
30 30
31cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 280829ad163f1444999468a57d28fb7c412babbe 31cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 676e6d602bf016dc71f1e98f2c7f191d7bd20707
32 32
33./ci.sh 33./ci.sh
34 34
diff --git a/.github/ci/crlf.sh b/.github/ci/crlf.sh
deleted file mode 100755
index 69838ce88..000000000
--- a/.github/ci/crlf.sh
+++ /dev/null
@@ -1,17 +0,0 @@
1#!/bin/bash
2## on push branch~=gh-readonly-queue/main/.*
3## on pull_request
4
5set -euo pipefail
6
7FILES_WITH_CRLF=$(find ! -path "./.git/*" -not -type d | xargs file -N | (grep " CRLF " || true))
8
9if [ -z "$FILES_WITH_CRLF" ]; then
10 echo -e "No files with CRLF endings found."
11 exit 0
12else
13 NR_FILES=$(echo "$FILES_WITH_CRLF" | wc -l)
14 echo -e "ERROR: Found ${NR_FILES} files with CRLF endings."
15 echo "$FILES_WITH_CRLF"
16 exit "$NR_FILES"
17fi
diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh
index 876c261a1..dab47e86d 100755
--- a/.github/ci/doc.sh
+++ b/.github/ci/doc.sh
@@ -9,62 +9,14 @@ set -euxo pipefail
9export RUSTUP_HOME=/ci/cache/rustup 9export RUSTUP_HOME=/ci/cache/rustup
10export CARGO_HOME=/ci/cache/cargo 10export CARGO_HOME=/ci/cache/cargo
11export CARGO_TARGET_DIR=/ci/cache/target 11export CARGO_TARGET_DIR=/ci/cache/target
12export BUILDER_THREADS=4 12export PATH=$CARGO_HOME/bin:$PATH
13export BUILDER_COMPRESS=true
14mv rust-toolchain-nightly.toml rust-toolchain.toml 13mv rust-toolchain-nightly.toml rust-toolchain.toml
15 14
16# force rustup to download the toolchain before starting building. 15cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 676e6d602bf016dc71f1e98f2c7f191d7bd20707
17# Otherwise, the docs builder is running multiple instances of cargo rustdoc concurrently.
18# They all see the toolchain is not installed and try to install it in parallel
19# which makes rustup very sad
20rustc --version > /dev/null
21 16
22docserver build -i ./embassy-boot -o webroot/crates/embassy-boot/git.zup 17cargo embassy-devtool doc -o webroot
23docserver build -i ./embassy-boot-nrf -o webroot/crates/embassy-boot-nrf/git.zup
24docserver build -i ./embassy-boot-rp -o webroot/crates/embassy-boot-rp/git.zup
25docserver build -i ./embassy-boot-stm32 -o webroot/crates/embassy-boot-stm32/git.zup
26docserver build -i ./embassy-embedded-hal -o webroot/crates/embassy-embedded-hal/git.zup
27docserver build -i ./embassy-executor -o webroot/crates/embassy-executor/git.zup
28docserver build -i ./embassy-futures -o webroot/crates/embassy-futures/git.zup
29docserver build -i ./embassy-nrf -o webroot/crates/embassy-nrf/git.zup
30docserver build -i ./embassy-rp -o webroot/crates/embassy-rp/git.zup
31docserver build -i ./embassy-mspm0 -o webroot/crates/embassy-mspm0/git.zup
32docserver build -i ./embassy-nxp -o webroot/crates/embassy-nxp/git.zup
33docserver build -i ./embassy-sync -o webroot/crates/embassy-sync/git.zup
34docserver build -i ./cyw43 -o webroot/crates/cyw43/git.zup
35docserver build -i ./cyw43-pio -o webroot/crates/cyw43-pio/git.zup
36docserver build -i ./embassy-stm32-wpan -o webroot/crates/embassy-stm32-wpan/git.zup --output-static webroot/static
37
38docserver build -i ./embassy-time -o webroot/crates/embassy-time/git.zup
39docserver build -i ./embassy-time-driver -o webroot/crates/embassy-time-driver/git.zup
40docserver build -i ./embassy-time-queue-utils -o webroot/crates/embassy-time-queue-utils/git.zup
41
42docserver build -i ./embassy-usb -o webroot/crates/embassy-usb/git.zup
43docserver build -i ./embassy-usb-dfu -o webroot/crates/embassy-usb-dfu/git.zup
44docserver build -i ./embassy-usb-driver -o webroot/crates/embassy-usb-driver/git.zup
45docserver build -i ./embassy-usb-logger -o webroot/crates/embassy-usb-logger/git.zup
46docserver build -i ./embassy-usb-synopsys-otg -o webroot/crates/embassy-usb-synopsys-otg/git.zup
47
48docserver build -i ./embassy-net -o webroot/crates/embassy-net/git.zup
49docserver build -i ./embassy-net-nrf91 -o webroot/crates/embassy-net-nrf91/git.zup
50docserver build -i ./embassy-net-driver -o webroot/crates/embassy-net-driver/git.zup
51docserver build -i ./embassy-net-driver-channel -o webroot/crates/embassy-net-driver-channel/git.zup
52docserver build -i ./embassy-net-wiznet -o webroot/crates/embassy-net-wiznet/git.zup
53docserver build -i ./embassy-net-ppp -o webroot/crates/embassy-net-ppp/git.zup
54docserver build -i ./embassy-net-tuntap -o webroot/crates/embassy-net-tuntap/git.zup
55docserver build -i ./embassy-net-enc28j60 -o webroot/crates/embassy-net-enc28j60/git.zup
56docserver build -i ./embassy-net-esp-hosted -o webroot/crates/embassy-net-esp-hosted/git.zup
57docserver build -i ./embassy-net-adin1110 -o webroot/crates/embassy-net-adin1110/git.zup
58 18
59export KUBECONFIG=/ci/secrets/kubeconfig.yml 19export KUBECONFIG=/ci/secrets/kubeconfig.yml
60POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name}) 20POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name})
61kubectl cp webroot/crates $POD:/data 21kubectl cp webroot/crates $POD:/data
62kubectl cp webroot/static $POD:/data 22kubectl cp webroot/static $POD:/data
63
64# build and upload stm32 last
65# so that it doesn't prevent other crates from getting docs updates when it breaks.
66
67rm -rf webroot
68docserver build -i ./embassy-stm32 -o webroot/crates/embassy-stm32/git.zup
69POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name})
70kubectl cp webroot/crates $POD:/data
diff --git a/.github/ci/janitor.sh b/.github/ci/janitor.sh
new file mode 100755
index 000000000..305c6b227
--- /dev/null
+++ b/.github/ci/janitor.sh
@@ -0,0 +1,15 @@
1#!/bin/bash
2## on push branch~=gh-readonly-queue/main/.*
3## on pull_request
4
5set -euo pipefail
6
7export RUSTUP_HOME=/ci/cache/rustup
8export CARGO_HOME=/ci/cache/cargo
9export CARGO_TARGET_DIR=/ci/cache/target
10export PATH=$CARGO_HOME/bin:$PATH
11
12cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 676e6d602bf016dc71f1e98f2c7f191d7bd20707
13
14cargo embassy-devtool check-crlf
15cargo embassy-devtool check-manifest
diff --git a/cyw43-pio/Cargo.toml b/cyw43-pio/Cargo.toml
index 40dd02f61..6ab5c453e 100644
--- a/cyw43-pio/Cargo.toml
+++ b/cyw43-pio/Cargo.toml
@@ -15,6 +15,9 @@ embassy-rp = { version = "0.8.0", path = "../embassy-rp" }
15fixed = "1.23.1" 15fixed = "1.23.1"
16defmt = { version = "1.0.1", optional = true } 16defmt = { version = "1.0.1", optional = true }
17 17
18[features]
19defmt = ["dep:defmt"]
20
18[package.metadata.embassy] 21[package.metadata.embassy]
19build = [ 22build = [
20 {target = "thumbv6m-none-eabi", features = ["embassy-rp/rp2040"]}, 23 {target = "thumbv6m-none-eabi", features = ["embassy-rp/rp2040"]},
diff --git a/cyw43/CHANGELOG.md b/cyw43/CHANGELOG.md
index dcf84b9ba..1045fd30b 100644
--- a/cyw43/CHANGELOG.md
+++ b/cyw43/CHANGELOG.md
@@ -9,8 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9## Unreleased - ReleaseDate 9## Unreleased - ReleaseDate
10 10
11- Updated documentation for Control::join() #4678 11- Updated documentation for Control::join() #4678
12- Bump bt-hci to 0.5.0. 12- Bump bt-hci to 0.6.0.
13- Add error handling to HCI transport implementation. 13- Add error handling to HCI transport implementation.
14- Reset WPA security on AP creation #4709
14 15
15## 0.5.0 - 2025-08-28 16## 0.5.0 - 2025-08-28
16 17
diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml
index 0d0c26089..c59c15a71 100644
--- a/cyw43/Cargo.toml
+++ b/cyw43/Cargo.toml
@@ -36,7 +36,7 @@ heapless = "0.8.0"
36 36
37# Bluetooth deps 37# Bluetooth deps
38embedded-io-async = { version = "0.6.0", optional = true } 38embedded-io-async = { version = "0.6.0", optional = true }
39bt-hci = { version = "0.5.0", optional = true } 39bt-hci = { version = "0.6.0", optional = true }
40 40
41[package.metadata.embassy] 41[package.metadata.embassy]
42build = [ 42build = [
diff --git a/cyw43/src/control.rs b/cyw43/src/control.rs
index e4dc0804f..fd0d4d532 100644
--- a/cyw43/src/control.rs
+++ b/cyw43/src/control.rs
@@ -470,6 +470,8 @@ impl<'a> Control<'a> {
470 pfi.passphrase[..passphrase.as_bytes().len()].copy_from_slice(passphrase.as_bytes()); 470 pfi.passphrase[..passphrase.as_bytes().len()].copy_from_slice(passphrase.as_bytes());
471 self.ioctl(IoctlType::Set, Ioctl::SetWsecPmk, 0, &mut pfi.to_bytes()) 471 self.ioctl(IoctlType::Set, Ioctl::SetWsecPmk, 0, &mut pfi.to_bytes())
472 .await; 472 .await;
473 } else {
474 self.ioctl_set_u32(Ioctl::SetAuth, 0, 0).await;
473 } 475 }
474 476
475 // Change mutlicast rate from 1 Mbps to 11 Mbps 477 // Change mutlicast rate from 1 Mbps to 11 Mbps
diff --git a/docs/examples/basic/Cargo.toml b/docs/examples/basic/Cargo.toml
index b6dbeda2a..b90180853 100644
--- a/docs/examples/basic/Cargo.toml
+++ b/docs/examples/basic/Cargo.toml
@@ -9,7 +9,7 @@ publish = false
9[dependencies] 9[dependencies]
10embassy-executor = { version = "0.9.0", path = "../../../embassy-executor", features = ["defmt", "arch-cortex-m", "executor-thread"] } 10embassy-executor = { version = "0.9.0", path = "../../../embassy-executor", features = ["defmt", "arch-cortex-m", "executor-thread"] }
11embassy-time = { version = "0.5.0", path = "../../../embassy-time", features = ["defmt"] } 11embassy-time = { version = "0.5.0", path = "../../../embassy-time", features = ["defmt"] }
12embassy-nrf = { version = "0.7.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } 12embassy-nrf = { version = "0.8.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] }
13 13
14defmt = "1.0.1" 14defmt = "1.0.1"
15defmt-rtt = "1.0.0" 15defmt-rtt = "1.0.0"
diff --git a/embassy-boot-nrf/CHANGELOG.md b/embassy-boot-nrf/CHANGELOG.md
index 8cc1e73c0..54b7c8067 100644
--- a/embassy-boot-nrf/CHANGELOG.md
+++ b/embassy-boot-nrf/CHANGELOG.md
@@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8<!-- next-header --> 8<!-- next-header -->
9## Unreleased - ReleaseDate 9## Unreleased - ReleaseDate
10 10
11## 0.9.0 - 2025-09-30
12
13- Bumped embassy-nrf to 0.8.0
14
11## 0.8.0 - 2025-08-26 15## 0.8.0 - 2025-08-26
12 16
13## 0.1.1 - 2025-08-15 17## 0.1.1 - 2025-08-15
diff --git a/embassy-boot-nrf/Cargo.toml b/embassy-boot-nrf/Cargo.toml
index 3b631ef0c..466f18631 100644
--- a/embassy-boot-nrf/Cargo.toml
+++ b/embassy-boot-nrf/Cargo.toml
@@ -1,7 +1,7 @@
1[package] 1[package]
2edition = "2021" 2edition = "2021"
3name = "embassy-boot-nrf" 3name = "embassy-boot-nrf"
4version = "0.8.0" 4version = "0.9.0"
5description = "Bootloader lib for nRF chips" 5description = "Bootloader lib for nRF chips"
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7repository = "https://github.com/embassy-rs/embassy" 7repository = "https://github.com/embassy-rs/embassy"
@@ -36,7 +36,7 @@ defmt = { version = "1.0.1", optional = true }
36log = { version = "0.4.17", optional = true } 36log = { version = "0.4.17", optional = true }
37 37
38embassy-sync = { version = "0.7.2", path = "../embassy-sync" } 38embassy-sync = { version = "0.7.2", path = "../embassy-sync" }
39embassy-nrf = { version = "0.7.0", path = "../embassy-nrf", default-features = false } 39embassy-nrf = { version = "0.8.0", path = "../embassy-nrf", default-features = false }
40embassy-boot = { version = "0.6.1", path = "../embassy-boot" } 40embassy-boot = { version = "0.6.1", path = "../embassy-boot" }
41cortex-m = { version = "0.7.6" } 41cortex-m = { version = "0.7.6" }
42cortex-m-rt = { version = "0.7" } 42cortex-m-rt = { version = "0.7" }
@@ -52,6 +52,7 @@ defmt = [
52 "embassy-boot/defmt", 52 "embassy-boot/defmt",
53 "embassy-nrf/defmt", 53 "embassy-nrf/defmt",
54] 54]
55log = ["dep:log"]
55softdevice = [ 56softdevice = [
56 "nrf-softdevice-mbr", 57 "dep:nrf-softdevice-mbr",
57] 58]
diff --git a/embassy-boot/Cargo.toml b/embassy-boot/Cargo.toml
index ed0242c13..a18438c81 100644
--- a/embassy-boot/Cargo.toml
+++ b/embassy-boot/Cargo.toml
@@ -45,6 +45,8 @@ critical-section = { version = "1.1.1", features = ["std"] }
45ed25519-dalek = { version = "2", default-features = false, features = ["std", "rand_core", "digest"] } 45ed25519-dalek = { version = "2", default-features = false, features = ["std", "rand_core", "digest"] }
46 46
47[features] 47[features]
48defmt = ["dep:defmt"]
49log = ["dep:log"]
48ed25519-dalek = ["dep:ed25519-dalek", "_verify"] 50ed25519-dalek = ["dep:ed25519-dalek", "_verify"]
49ed25519-salty = ["dep:salty", "_verify"] 51ed25519-salty = ["dep:salty", "_verify"]
50flash-erase-zero = [] 52flash-erase-zero = []
diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml
index a66e01717..8b8122567 100644
--- a/embassy-embedded-hal/Cargo.toml
+++ b/embassy-embedded-hal/Cargo.toml
@@ -25,6 +25,7 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-embed
25target = "x86_64-unknown-linux-gnu" 25target = "x86_64-unknown-linux-gnu"
26 26
27[features] 27[features]
28defmt = ["dep:defmt"]
28time = ["dep:embassy-time"] 29time = ["dep:embassy-time"]
29 30
30[dependencies] 31[dependencies]
diff --git a/embassy-embedded-hal/src/adapter/yielding_async.rs b/embassy-embedded-hal/src/adapter/yielding_async.rs
index 87f822a63..e0ca3aedc 100644
--- a/embassy-embedded-hal/src/adapter/yielding_async.rs
+++ b/embassy-embedded-hal/src/adapter/yielding_async.rs
@@ -2,7 +2,7 @@ use embassy_futures::yield_now;
2 2
3/// Wrapper that yields for each operation to the wrapped instance 3/// Wrapper that yields for each operation to the wrapped instance
4/// 4///
5/// This can be used in combination with BlockingAsync<T> to enforce yields 5/// This can be used in combination with [super::BlockingAsync] to enforce yields
6/// between long running blocking operations. 6/// between long running blocking operations.
7pub struct YieldingAsync<T> { 7pub struct YieldingAsync<T> {
8 wrapped: T, 8 wrapped: T,
diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml
index f6dce5c0e..61d060630 100644
--- a/embassy-executor/Cargo.toml
+++ b/embassy-executor/Cargo.toml
@@ -123,6 +123,12 @@ rustversion = "1.0.21"
123## Enable nightly-only features 123## Enable nightly-only features
124nightly = ["embassy-executor-macros/nightly"] 124nightly = ["embassy-executor-macros/nightly"]
125 125
126## Enable defmt logging
127defmt = ["dep:defmt"]
128
129## Enable log logging
130log = ["dep:log"]
131
126# Enables turbo wakers, which requires patching core. Not surfaced in the docs by default due to 132# Enables turbo wakers, which requires patching core. Not surfaced in the docs by default due to
127# being an complicated advanced and undocumented feature. 133# being an complicated advanced and undocumented feature.
128# See: https://github.com/embassy-rs/embassy/pull/1263 134# See: https://github.com/embassy-rs/embassy/pull/1263
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index 9f36c60bc..dbd70cbf4 100644
--- a/embassy-executor/src/raw/mod.rs
+++ b/embassy-executor/src/raw/mod.rs
@@ -564,8 +564,6 @@ impl Executor {
564 /// 564 ///
565 /// # Safety 565 /// # Safety
566 /// 566 ///
567 /// You must call `initialize` before calling this method.
568 ///
569 /// You must NOT call `poll` reentrantly on the same executor. 567 /// You must NOT call `poll` reentrantly on the same executor.
570 /// 568 ///
571 /// In particular, note that `poll` may call the pender synchronously. Therefore, you 569 /// In particular, note that `poll` may call the pender synchronously. Therefore, you
diff --git a/embassy-executor/tests/ui/spawn_nonsend.rs b/embassy-executor/tests/ui/spawn_nonsend.rs
index 601041941..a06c0b37a 100644
--- a/embassy-executor/tests/ui/spawn_nonsend.rs
+++ b/embassy-executor/tests/ui/spawn_nonsend.rs
@@ -1,7 +1,5 @@
1#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))] 1#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))]
2 2
3use core::future::Future;
4
5use embassy_executor::SendSpawner; 3use embassy_executor::SendSpawner;
6 4
7#[embassy_executor::task] 5#[embassy_executor::task]
diff --git a/embassy-executor/tests/ui/spawn_nonsend.stderr b/embassy-executor/tests/ui/spawn_nonsend.stderr
index 25bd7d78d..31efadd49 100644
--- a/embassy-executor/tests/ui/spawn_nonsend.stderr
+++ b/embassy-executor/tests/ui/spawn_nonsend.stderr
@@ -1,27 +1,19 @@
1warning: unused import: `core::future::Future`
2 --> tests/ui/spawn_nonsend.rs:3:5
3 |
43 | use core::future::Future;
5 | ^^^^^^^^^^^^^^^^^^^^
6 |
7 = note: `#[warn(unused_imports)]` on by default
8
9error[E0277]: `*mut ()` cannot be sent between threads safely 1error[E0277]: `*mut ()` cannot be sent between threads safely
10 --> tests/ui/spawn_nonsend.rs:13:13 2 --> tests/ui/spawn_nonsend.rs:11:13
11 | 3 |
127 | #[embassy_executor::task] 4 5 | #[embassy_executor::task]
13 | ------------------------- within this `impl Sized` 5 | ------------------------- within this `impl Sized`
14... 6...
1513 | s.spawn(task(core::ptr::null_mut()).unwrap()); 711 | s.spawn(task(core::ptr::null_mut()).unwrap());
16 | ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*mut ()` cannot be sent between threads safely 8 | ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*mut ()` cannot be sent between threads safely
17 | | 9 | |
18 | required by a bound introduced by this call 10 | required by a bound introduced by this call
19 | 11 |
20 = help: within `impl Sized`, the trait `Send` is not implemented for `*mut ()` 12 = help: within `impl Sized`, the trait `Send` is not implemented for `*mut ()`
21note: required because it's used within this closure 13note: required because it's used within this closure
22 --> tests/ui/spawn_nonsend.rs:7:1 14 --> tests/ui/spawn_nonsend.rs:5:1
23 | 15 |
247 | #[embassy_executor::task] 16 5 | #[embassy_executor::task]
25 | ^^^^^^^^^^^^^^^^^^^^^^^^^ 17 | ^^^^^^^^^^^^^^^^^^^^^^^^^
26note: required because it appears within the type `impl Sized` 18note: required because it appears within the type `impl Sized`
27 --> src/raw/mod.rs 19 --> src/raw/mod.rs
@@ -29,9 +21,9 @@ note: required because it appears within the type `impl Sized`
29 | pub unsafe fn _spawn_async_fn<FutFn>(&'static self, future: FutFn) -> Result<SpawnToken<impl Sized>, SpawnError> 21 | pub unsafe fn _spawn_async_fn<FutFn>(&'static self, future: FutFn) -> Result<SpawnToken<impl Sized>, SpawnError>
30 | ^^^^^^^^^^ 22 | ^^^^^^^^^^
31note: required because it appears within the type `impl Sized` 23note: required because it appears within the type `impl Sized`
32 --> tests/ui/spawn_nonsend.rs:7:1 24 --> tests/ui/spawn_nonsend.rs:5:1
33 | 25 |
347 | #[embassy_executor::task] 26 5 | #[embassy_executor::task]
35 | ^^^^^^^^^^^^^^^^^^^^^^^^^ 27 | ^^^^^^^^^^^^^^^^^^^^^^^^^
36note: required by a bound in `SendSpawner::spawn` 28note: required by a bound in `SendSpawner::spawn`
37 --> src/spawner.rs 29 --> src/spawner.rs
diff --git a/embassy-executor/tests/ui/unsafe_op_in_unsafe_task.stderr b/embassy-executor/tests/ui/unsafe_op_in_unsafe_task.stderr
index d987a4b95..033395584 100644
--- a/embassy-executor/tests/ui/unsafe_op_in_unsafe_task.stderr
+++ b/embassy-executor/tests/ui/unsafe_op_in_unsafe_task.stderr
@@ -4,7 +4,7 @@ error[E0133]: call to unsafe function `std::ptr::const_ptr::<impl *const T>::rea
47 | (&x as *const i32).read(); 47 | (&x as *const i32).read();
5 | ^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function 5 | ^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
6 | 6 |
7 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html> 7 = note: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
8 = note: consult the function's documentation for information on how to avoid undefined behavior 8 = note: consult the function's documentation for information on how to avoid undefined behavior
9note: an unsafe function restricts its caller, but its body is safe by default 9note: an unsafe function restricts its caller, but its body is safe by default
10 --> tests/ui/unsafe_op_in_unsafe_task.rs:5:1 10 --> tests/ui/unsafe_op_in_unsafe_task.rs:5:1
diff --git a/embassy-futures/Cargo.toml b/embassy-futures/Cargo.toml
index 2d62b28e5..07d5219cf 100644
--- a/embassy-futures/Cargo.toml
+++ b/embassy-futures/Cargo.toml
@@ -26,3 +26,7 @@ features = ["defmt"]
26[dependencies] 26[dependencies]
27defmt = { version = "1.0.1", optional = true } 27defmt = { version = "1.0.1", optional = true }
28log = { version = "0.4.14", optional = true } 28log = { version = "0.4.14", optional = true }
29
30[features]
31defmt = ["dep:defmt"]
32log = ["dep:log"]
diff --git a/embassy-hal-internal/Cargo.toml b/embassy-hal-internal/Cargo.toml
index b4c52ccfa..11dcc2466 100644
--- a/embassy-hal-internal/Cargo.toml
+++ b/embassy-hal-internal/Cargo.toml
@@ -14,6 +14,9 @@ categories = [
14 14
15[features] 15[features]
16 16
17defmt = ["dep:defmt"]
18log = ["dep:log"]
19
17# Define the number of NVIC priority bits. 20# Define the number of NVIC priority bits.
18prio-bits-0 = [] 21prio-bits-0 = []
19prio-bits-1 = [] 22prio-bits-1 = []
diff --git a/embassy-hal-internal/src/atomic_ring_buffer.rs b/embassy-hal-internal/src/atomic_ring_buffer.rs
index 00b7a1249..8c3889b85 100644
--- a/embassy-hal-internal/src/atomic_ring_buffer.rs
+++ b/embassy-hal-internal/src/atomic_ring_buffer.rs
@@ -133,6 +133,18 @@ impl RingBuffer {
133 self.len.load(Ordering::Relaxed) 133 self.len.load(Ordering::Relaxed)
134 } 134 }
135 135
136 /// Return number of items available to read.
137 pub fn available(&self) -> usize {
138 let end = self.end.load(Ordering::Relaxed);
139 let len = self.len.load(Ordering::Relaxed);
140 let start = self.start.load(Ordering::Relaxed);
141 if end >= start {
142 end - start
143 } else {
144 2 * len - start + end
145 }
146 }
147
136 /// Check if buffer is full. 148 /// Check if buffer is full.
137 pub fn is_full(&self) -> bool { 149 pub fn is_full(&self) -> bool {
138 let len = self.len.load(Ordering::Relaxed); 150 let len = self.len.load(Ordering::Relaxed);
@@ -142,6 +154,11 @@ impl RingBuffer {
142 self.wrap(start + len) == end 154 self.wrap(start + len) == end
143 } 155 }
144 156
157 /// Check if buffer is at least half full.
158 pub fn is_half_full(&self) -> bool {
159 self.available() >= self.len.load(Ordering::Relaxed) / 2
160 }
161
145 /// Check if buffer is empty. 162 /// Check if buffer is empty.
146 pub fn is_empty(&self) -> bool { 163 pub fn is_empty(&self) -> bool {
147 let start = self.start.load(Ordering::Relaxed); 164 let start = self.start.load(Ordering::Relaxed);
@@ -394,6 +411,7 @@ mod tests {
394 rb.init(b.as_mut_ptr(), 4); 411 rb.init(b.as_mut_ptr(), 4);
395 412
396 assert_eq!(rb.is_empty(), true); 413 assert_eq!(rb.is_empty(), true);
414 assert_eq!(rb.is_half_full(), false);
397 assert_eq!(rb.is_full(), false); 415 assert_eq!(rb.is_full(), false);
398 416
399 rb.writer().push(|buf| { 417 rb.writer().push(|buf| {
@@ -406,6 +424,7 @@ mod tests {
406 }); 424 });
407 425
408 assert_eq!(rb.is_empty(), false); 426 assert_eq!(rb.is_empty(), false);
427 assert_eq!(rb.is_half_full(), true);
409 assert_eq!(rb.is_full(), true); 428 assert_eq!(rb.is_full(), true);
410 429
411 rb.writer().push(|buf| { 430 rb.writer().push(|buf| {
@@ -415,6 +434,7 @@ mod tests {
415 }); 434 });
416 435
417 assert_eq!(rb.is_empty(), false); 436 assert_eq!(rb.is_empty(), false);
437 assert_eq!(rb.is_half_full(), true);
418 assert_eq!(rb.is_full(), true); 438 assert_eq!(rb.is_full(), true);
419 439
420 rb.reader().pop(|buf| { 440 rb.reader().pop(|buf| {
@@ -424,6 +444,7 @@ mod tests {
424 }); 444 });
425 445
426 assert_eq!(rb.is_empty(), false); 446 assert_eq!(rb.is_empty(), false);
447 assert_eq!(rb.is_half_full(), true);
427 assert_eq!(rb.is_full(), false); 448 assert_eq!(rb.is_full(), false);
428 449
429 rb.reader().pop(|buf| { 450 rb.reader().pop(|buf| {
@@ -432,6 +453,7 @@ mod tests {
432 }); 453 });
433 454
434 assert_eq!(rb.is_empty(), false); 455 assert_eq!(rb.is_empty(), false);
456 assert_eq!(rb.is_half_full(), true);
435 assert_eq!(rb.is_full(), false); 457 assert_eq!(rb.is_full(), false);
436 458
437 rb.reader().pop(|buf| { 459 rb.reader().pop(|buf| {
@@ -447,6 +469,7 @@ mod tests {
447 }); 469 });
448 470
449 assert_eq!(rb.is_empty(), true); 471 assert_eq!(rb.is_empty(), true);
472 assert_eq!(rb.is_half_full(), false);
450 assert_eq!(rb.is_full(), false); 473 assert_eq!(rb.is_full(), false);
451 474
452 rb.reader().pop(|buf| { 475 rb.reader().pop(|buf| {
@@ -460,14 +483,28 @@ mod tests {
460 1 483 1
461 }); 484 });
462 485
486 assert_eq!(rb.is_empty(), false);
487 assert_eq!(rb.is_half_full(), false);
488 assert_eq!(rb.is_full(), false);
489
463 rb.writer().push(|buf| { 490 rb.writer().push(|buf| {
464 assert_eq!(3, buf.len()); 491 assert_eq!(3, buf.len());
465 buf[0] = 11; 492 buf[0] = 11;
466 buf[1] = 12; 493 1
467 2 494 });
495
496 assert_eq!(rb.is_empty(), false);
497 assert_eq!(rb.is_half_full(), true);
498 assert_eq!(rb.is_full(), false);
499
500 rb.writer().push(|buf| {
501 assert_eq!(2, buf.len());
502 buf[0] = 12;
503 1
468 }); 504 });
469 505
470 assert_eq!(rb.is_empty(), false); 506 assert_eq!(rb.is_empty(), false);
507 assert_eq!(rb.is_half_full(), true);
471 assert_eq!(rb.is_full(), false); 508 assert_eq!(rb.is_full(), false);
472 509
473 rb.writer().push(|buf| { 510 rb.writer().push(|buf| {
@@ -477,6 +514,7 @@ mod tests {
477 }); 514 });
478 515
479 assert_eq!(rb.is_empty(), false); 516 assert_eq!(rb.is_empty(), false);
517 assert_eq!(rb.is_half_full(), true);
480 assert_eq!(rb.is_full(), true); 518 assert_eq!(rb.is_full(), true);
481 } 519 }
482 } 520 }
@@ -490,6 +528,7 @@ mod tests {
490 rb.init(b.as_mut_ptr(), b.len()); 528 rb.init(b.as_mut_ptr(), b.len());
491 529
492 assert_eq!(rb.is_empty(), true); 530 assert_eq!(rb.is_empty(), true);
531 assert_eq!(rb.is_half_full(), true);
493 assert_eq!(rb.is_full(), true); 532 assert_eq!(rb.is_full(), true);
494 533
495 rb.writer().push(|buf| { 534 rb.writer().push(|buf| {
diff --git a/embassy-imxrt/Cargo.toml b/embassy-imxrt/Cargo.toml
index 8a9c1252e..7561640dd 100644
--- a/embassy-imxrt/Cargo.toml
+++ b/embassy-imxrt/Cargo.toml
@@ -2,7 +2,7 @@
2name = "embassy-imxrt" 2name = "embassy-imxrt"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "2021"
5license = "MIT" 5license = "MIT OR Apache-2.0"
6description = "Embassy Hardware Abstraction Layer (HAL) for the IMXRT microcontroller" 6description = "Embassy Hardware Abstraction Layer (HAL) for the IMXRT microcontroller"
7keywords = ["embedded", "async", "imxrt", "rt600", "embedded-hal"] 7keywords = ["embedded", "async", "imxrt", "rt600", "embedded-hal"]
8categories = ["embedded", "hardware-support", "no-std", "asynchronous"] 8categories = ["embedded", "hardware-support", "no-std", "asynchronous"]
diff --git a/embassy-net-driver-channel/Cargo.toml b/embassy-net-driver-channel/Cargo.toml
index cf498c59f..1e40c2d87 100644
--- a/embassy-net-driver-channel/Cargo.toml
+++ b/embassy-net-driver-channel/Cargo.toml
@@ -28,3 +28,7 @@ log = { version = "0.4.14", optional = true }
28embassy-sync = { version = "0.7.2", path = "../embassy-sync" } 28embassy-sync = { version = "0.7.2", path = "../embassy-sync" }
29embassy-futures = { version = "0.1.2", path = "../embassy-futures" } 29embassy-futures = { version = "0.1.2", path = "../embassy-futures" }
30embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } 30embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
31
32[features]
33defmt = ["dep:defmt"]
34log = ["dep:log"]
diff --git a/embassy-net-driver/Cargo.toml b/embassy-net-driver/Cargo.toml
index 34bc6c91a..a36e412ad 100644
--- a/embassy-net-driver/Cargo.toml
+++ b/embassy-net-driver/Cargo.toml
@@ -23,3 +23,6 @@ features = ["defmt"]
23 23
24[dependencies] 24[dependencies]
25defmt = { version = "1.0.1", optional = true } 25defmt = { version = "1.0.1", optional = true }
26
27[features]
28defmt = ["dep:defmt"]
diff --git a/embassy-net-enc28j60/Cargo.toml b/embassy-net-enc28j60/Cargo.toml
index a3e3285a3..e7bad118b 100644
--- a/embassy-net-enc28j60/Cargo.toml
+++ b/embassy-net-enc28j60/Cargo.toml
@@ -19,6 +19,10 @@ embassy-futures = { version = "0.1.2", path = "../embassy-futures" }
19defmt = { version = "1.0.1", optional = true } 19defmt = { version = "1.0.1", optional = true }
20log = { version = "0.4.14", optional = true } 20log = { version = "0.4.14", optional = true }
21 21
22[features]
23defmt = ["dep:defmt", "embassy-net-driver/defmt"]
24log = ["dep:log"]
25
22[package.metadata.embassy_docs] 26[package.metadata.embassy_docs]
23src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-enc28j60-v$VERSION/embassy-net-enc28j60/src/" 27src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-enc28j60-v$VERSION/embassy-net-enc28j60/src/"
24src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-enc28j60/src/" 28src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-enc28j60/src/"
diff --git a/embassy-net-wiznet/Cargo.toml b/embassy-net-wiznet/Cargo.toml
index 36c349df1..6e6dccebd 100644
--- a/embassy-net-wiznet/Cargo.toml
+++ b/embassy-net-wiznet/Cargo.toml
@@ -17,6 +17,9 @@ embassy-time = { version = "0.5.0", path = "../embassy-time" }
17embassy-futures = { version = "0.1.2", path = "../embassy-futures" } 17embassy-futures = { version = "0.1.2", path = "../embassy-futures" }
18defmt = { version = "1.0.1", optional = true } 18defmt = { version = "1.0.1", optional = true }
19 19
20[features]
21defmt = ["dep:defmt", "embassy-net-driver-channel/defmt"]
22
20[package.metadata.embassy_docs] 23[package.metadata.embassy_docs]
21src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-wiznet-v$VERSION/embassy-net-wiznet/src/" 24src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-wiznet-v$VERSION/embassy-net-wiznet/src/"
22src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-wiznet/src/" 25src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-wiznet/src/"
diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml
index 61a2c858a..31ce7e9a6 100644
--- a/embassy-net/Cargo.toml
+++ b/embassy-net/Cargo.toml
@@ -53,6 +53,8 @@ features = ["defmt", "tcp", "udp", "raw", "dns", "icmp", "dhcpv4", "proto-ipv6",
53[features] 53[features]
54## Enable defmt 54## Enable defmt
55defmt = ["dep:defmt", "smoltcp/defmt", "embassy-net-driver/defmt", "embassy-time/defmt", "heapless/defmt-03", "defmt?/ip_in_core"] 55defmt = ["dep:defmt", "smoltcp/defmt", "embassy-net-driver/defmt", "embassy-time/defmt", "heapless/defmt-03", "defmt?/ip_in_core"]
56## Enable log
57log = ["dep:log"]
56 58
57## Trace all raw received and transmitted packets using defmt or log. 59## Trace all raw received and transmitted packets using defmt or log.
58packet-trace = [] 60packet-trace = []
diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md
index befa34ecf..b3d4045fa 100644
--- a/embassy-nrf/CHANGELOG.md
+++ b/embassy-nrf/CHANGELOG.md
@@ -8,8 +8,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8<!-- next-header --> 8<!-- next-header -->
9## Unreleased - ReleaseDate 9## Unreleased - ReleaseDate
10 10
11## 0.8.0 - 2025-09-30
12
13- changed: Remove `T: Instance` generic params in all drivers.
11- changed: nrf54l: Disable glitch detection and enable DC/DC in init. 14- changed: nrf54l: Disable glitch detection and enable DC/DC in init.
12- changed: Add embassy-net-driver-channel implementation for IEEE 802.15.4 15- changed: Add embassy-net-driver-channel implementation for IEEE 802.15.4
16- changed: add persist() method for gpio and ppi
17- added: basic RTC driver
18- changed: add persist() method for gpio, gpiote, timer and ppi
19- changed: impl Drop for Timer
20- added: expose `regs` for timer driver
21- added: timer driver CC `clear_events` method
22- changed: Saadc reset in Drop impl, anomaly 241 - high power usage
13 23
14## 0.7.0 - 2025-08-26 24## 0.7.0 - 2025-08-26
15 25
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index 4afd28fbd..362fabcf7 100644
--- a/embassy-nrf/Cargo.toml
+++ b/embassy-nrf/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "embassy-nrf" 2name = "embassy-nrf"
3version = "0.7.0" 3version = "0.8.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6description = "Embassy Hardware Abstraction Layer (HAL) for nRF series microcontrollers" 6description = "Embassy Hardware Abstraction Layer (HAL) for nRF series microcontrollers"
@@ -34,6 +34,7 @@ build = [
34 {target = "thumbv7em-none-eabi", features = ["defmt", "gpiote", "nrf52840", "time"]}, 34 {target = "thumbv7em-none-eabi", features = ["defmt", "gpiote", "nrf52840", "time"]},
35 {target = "thumbv7em-none-eabi", features = ["defmt", "gpiote", "nrf52840", "time-driver-rtc1"]}, 35 {target = "thumbv7em-none-eabi", features = ["defmt", "gpiote", "nrf52840", "time-driver-rtc1"]},
36 {target = "thumbv7em-none-eabi", features = ["defmt", "gpiote", "nrf52840", "time", "time-driver-rtc1"]}, 36 {target = "thumbv7em-none-eabi", features = ["defmt", "gpiote", "nrf52840", "time", "time-driver-rtc1"]},
37 {target = "thumbv7em-none-eabi", features = ["defmt", "gpiote", "nrf52840", "time", "time-driver-rtc1","qspi-multiwrite-flash"]},
37 {target = "thumbv6m-none-eabi", features = ["defmt", "nrf51", "time", "time-driver-rtc1"]}, 38 {target = "thumbv6m-none-eabi", features = ["defmt", "nrf51", "time", "time-driver-rtc1"]},
38 {target = "thumbv6m-none-eabi", features = ["defmt", "nrf51", "time"]}, 39 {target = "thumbv6m-none-eabi", features = ["defmt", "nrf51", "time"]},
39 {target = "thumbv6m-none-eabi", features = ["nrf51", "time"]}, 40 {target = "thumbv6m-none-eabi", features = ["nrf51", "time"]},
@@ -66,6 +67,8 @@ time = ["dep:embassy-time", "embassy-embedded-hal/time"]
66 67
67## Enable defmt 68## Enable defmt
68defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt", "embassy-usb-driver/defmt", "embassy-embedded-hal/defmt"] 69defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt", "embassy-usb-driver/defmt", "embassy-embedded-hal/defmt"]
70## Enable log
71log = ["dep:log"]
69 72
70## Reexport the PAC for the currently enabled chip at `embassy_nrf::pac` (unstable) 73## Reexport the PAC for the currently enabled chip at `embassy_nrf::pac` (unstable)
71unstable-pac = [] 74unstable-pac = []
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs
index 29e126903..40c679190 100644
--- a/embassy-nrf/src/buffered_uarte.rs
+++ b/embassy-nrf/src/buffered_uarte.rs
@@ -23,6 +23,7 @@ pub use pac::uarte::vals::{Baudrate, ConfigParity as Parity};
23 23
24use crate::gpio::{AnyPin, Pin as GpioPin}; 24use crate::gpio::{AnyPin, Pin as GpioPin};
25use crate::interrupt::typelevel::Interrupt; 25use crate::interrupt::typelevel::Interrupt;
26use crate::interrupt::InterruptExt;
26use crate::ppi::{ 27use crate::ppi::{
27 self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task, 28 self, AnyConfigurableChannel, AnyGroup, Channel, ConfigurableChannel, Event, Group, Ppi, PpiGroup, Task,
28}; 29};
@@ -207,21 +208,21 @@ impl<U: UarteInstance> interrupt::typelevel::Handler<U::Interrupt> for Interrupt
207} 208}
208 209
209/// Buffered UARTE driver. 210/// Buffered UARTE driver.
210pub struct BufferedUarte<'d, U: UarteInstance, T: TimerInstance> { 211pub struct BufferedUarte<'d> {
211 tx: BufferedUarteTx<'d, U>, 212 tx: BufferedUarteTx<'d>,
212 rx: BufferedUarteRx<'d, U, T>, 213 rx: BufferedUarteRx<'d>,
213} 214}
214 215
215impl<'d, U: UarteInstance, T: TimerInstance> Unpin for BufferedUarte<'d, U, T> {} 216impl<'d> Unpin for BufferedUarte<'d> {}
216 217
217impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> { 218impl<'d> BufferedUarte<'d> {
218 /// Create a new BufferedUarte without hardware flow control. 219 /// Create a new BufferedUarte without hardware flow control.
219 /// 220 ///
220 /// # Panics 221 /// # Panics
221 /// 222 ///
222 /// Panics if `rx_buffer.len()` is odd. 223 /// Panics if `rx_buffer.len()` is odd.
223 #[allow(clippy::too_many_arguments)] 224 #[allow(clippy::too_many_arguments)]
224 pub fn new( 225 pub fn new<U: UarteInstance, T: TimerInstance>(
225 uarte: Peri<'d, U>, 226 uarte: Peri<'d, U>,
226 timer: Peri<'d, T>, 227 timer: Peri<'d, T>,
227 ppi_ch1: Peri<'d, impl ConfigurableChannel>, 228 ppi_ch1: Peri<'d, impl ConfigurableChannel>,
@@ -256,7 +257,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
256 /// 257 ///
257 /// Panics if `rx_buffer.len()` is odd. 258 /// Panics if `rx_buffer.len()` is odd.
258 #[allow(clippy::too_many_arguments)] 259 #[allow(clippy::too_many_arguments)]
259 pub fn new_with_rtscts( 260 pub fn new_with_rtscts<U: UarteInstance, T: TimerInstance>(
260 uarte: Peri<'d, U>, 261 uarte: Peri<'d, U>,
261 timer: Peri<'d, T>, 262 timer: Peri<'d, T>,
262 ppi_ch1: Peri<'d, impl ConfigurableChannel>, 263 ppi_ch1: Peri<'d, impl ConfigurableChannel>,
@@ -288,7 +289,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
288 } 289 }
289 290
290 #[allow(clippy::too_many_arguments)] 291 #[allow(clippy::too_many_arguments)]
291 fn new_inner( 292 fn new_inner<U: UarteInstance, T: TimerInstance>(
292 peri: Peri<'d, U>, 293 peri: Peri<'d, U>,
293 timer: Peri<'d, T>, 294 timer: Peri<'d, T>,
294 ppi_ch1: Peri<'d, AnyConfigurableChannel>, 295 ppi_ch1: Peri<'d, AnyConfigurableChannel>,
@@ -302,30 +303,33 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
302 rx_buffer: &'d mut [u8], 303 rx_buffer: &'d mut [u8],
303 tx_buffer: &'d mut [u8], 304 tx_buffer: &'d mut [u8],
304 ) -> Self { 305 ) -> Self {
305 configure(U::regs(), config, cts.is_some()); 306 let r = U::regs();
307 let irq = U::Interrupt::IRQ;
308 let state = U::state();
309
310 configure(r, config, cts.is_some());
306 311
307 let tx = BufferedUarteTx::new_innerer(unsafe { peri.clone_unchecked() }, txd, cts, tx_buffer); 312 let tx = BufferedUarteTx::new_innerer(unsafe { peri.clone_unchecked() }, txd, cts, tx_buffer);
308 let rx = BufferedUarteRx::new_innerer(peri, timer, ppi_ch1, ppi_ch2, ppi_group, rxd, rts, rx_buffer); 313 let rx = BufferedUarteRx::new_innerer(peri, timer, ppi_ch1, ppi_ch2, ppi_group, rxd, rts, rx_buffer);
309 314
310 U::regs().enable().write(|w| w.set_enable(vals::Enable::ENABLED)); 315 r.enable().write(|w| w.set_enable(vals::Enable::ENABLED));
311 U::Interrupt::pend(); 316 irq.pend();
312 unsafe { U::Interrupt::enable() }; 317 unsafe { irq.enable() };
313 318
314 U::state().tx_rx_refcount.store(2, Ordering::Relaxed); 319 state.tx_rx_refcount.store(2, Ordering::Relaxed);
315 320
316 Self { tx, rx } 321 Self { tx, rx }
317 } 322 }
318 323
319 /// Adjust the baud rate to the provided value. 324 /// Adjust the baud rate to the provided value.
320 pub fn set_baudrate(&mut self, baudrate: Baudrate) { 325 pub fn set_baudrate(&mut self, baudrate: Baudrate) {
321 let r = U::regs(); 326 self.tx.set_baudrate(baudrate);
322 r.baudrate().write(|w| w.set_baudrate(baudrate));
323 } 327 }
324 328
325 /// Split the UART in reader and writer parts. 329 /// Split the UART in reader and writer parts.
326 /// 330 ///
327 /// This allows reading and writing concurrently from independent tasks. 331 /// This allows reading and writing concurrently from independent tasks.
328 pub fn split(self) -> (BufferedUarteRx<'d, U, T>, BufferedUarteTx<'d, U>) { 332 pub fn split(self) -> (BufferedUarteRx<'d>, BufferedUarteTx<'d>) {
329 (self.rx, self.tx) 333 (self.rx, self.tx)
330 } 334 }
331 335
@@ -333,7 +337,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
333 /// 337 ///
334 /// The returned halves borrow from `self`, so you can drop them and go back to using 338 /// The returned halves borrow from `self`, so you can drop them and go back to using
335 /// the "un-split" `self`. This allows temporarily splitting the UART. 339 /// the "un-split" `self`. This allows temporarily splitting the UART.
336 pub fn split_by_ref(&mut self) -> (&mut BufferedUarteRx<'d, U, T>, &mut BufferedUarteTx<'d, U>) { 340 pub fn split_by_ref(&mut self) -> (&mut BufferedUarteRx<'d>, &mut BufferedUarteTx<'d>) {
337 (&mut self.rx, &mut self.tx) 341 (&mut self.rx, &mut self.tx)
338 } 342 }
339 343
@@ -369,13 +373,17 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarte<'d, U, T> {
369} 373}
370 374
371/// Reader part of the buffered UARTE driver. 375/// Reader part of the buffered UARTE driver.
372pub struct BufferedUarteTx<'d, U: UarteInstance> { 376pub struct BufferedUarteTx<'d> {
373 _peri: Peri<'d, U>, 377 r: pac::uarte::Uarte,
378 _irq: interrupt::Interrupt,
379 state: &'static crate::uarte::State,
380 buffered_state: &'static State,
381 _p: PhantomData<&'d ()>,
374} 382}
375 383
376impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> { 384impl<'d> BufferedUarteTx<'d> {
377 /// Create a new BufferedUarteTx without hardware flow control. 385 /// Create a new BufferedUarteTx without hardware flow control.
378 pub fn new( 386 pub fn new<U: UarteInstance>(
379 uarte: Peri<'d, U>, 387 uarte: Peri<'d, U>,
380 txd: Peri<'d, impl GpioPin>, 388 txd: Peri<'d, impl GpioPin>,
381 _irq: impl interrupt::typelevel::Binding<U::Interrupt, InterruptHandler<U>> + 'd, 389 _irq: impl interrupt::typelevel::Binding<U::Interrupt, InterruptHandler<U>> + 'd,
@@ -390,7 +398,7 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> {
390 /// # Panics 398 /// # Panics
391 /// 399 ///
392 /// Panics if `rx_buffer.len()` is odd. 400 /// Panics if `rx_buffer.len()` is odd.
393 pub fn new_with_cts( 401 pub fn new_with_cts<U: UarteInstance>(
394 uarte: Peri<'d, U>, 402 uarte: Peri<'d, U>,
395 txd: Peri<'d, impl GpioPin>, 403 txd: Peri<'d, impl GpioPin>,
396 cts: Peri<'d, impl GpioPin>, 404 cts: Peri<'d, impl GpioPin>,
@@ -401,41 +409,48 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> {
401 Self::new_inner(uarte, txd.into(), Some(cts.into()), config, tx_buffer) 409 Self::new_inner(uarte, txd.into(), Some(cts.into()), config, tx_buffer)
402 } 410 }
403 411
404 fn new_inner( 412 fn new_inner<U: UarteInstance>(
405 peri: Peri<'d, U>, 413 peri: Peri<'d, U>,
406 txd: Peri<'d, AnyPin>, 414 txd: Peri<'d, AnyPin>,
407 cts: Option<Peri<'d, AnyPin>>, 415 cts: Option<Peri<'d, AnyPin>>,
408 config: Config, 416 config: Config,
409 tx_buffer: &'d mut [u8], 417 tx_buffer: &'d mut [u8],
410 ) -> Self { 418 ) -> Self {
411 configure(U::regs(), config, cts.is_some()); 419 let r = U::regs();
420 let irq = U::Interrupt::IRQ;
421 let state = U::state();
422 let _buffered_state = U::buffered_state();
423
424 configure(r, config, cts.is_some());
412 425
413 let this = Self::new_innerer(peri, txd, cts, tx_buffer); 426 let this = Self::new_innerer(peri, txd, cts, tx_buffer);
414 427
415 U::regs().enable().write(|w| w.set_enable(vals::Enable::ENABLED)); 428 r.enable().write(|w| w.set_enable(vals::Enable::ENABLED));
416 U::Interrupt::pend(); 429 irq.pend();
417 unsafe { U::Interrupt::enable() }; 430 unsafe { irq.enable() };
418 431
419 U::state().tx_rx_refcount.store(1, Ordering::Relaxed); 432 state.tx_rx_refcount.store(1, Ordering::Relaxed);
420 433
421 this 434 this
422 } 435 }
423 436
424 fn new_innerer( 437 fn new_innerer<U: UarteInstance>(
425 peri: Peri<'d, U>, 438 _peri: Peri<'d, U>,
426 txd: Peri<'d, AnyPin>, 439 txd: Peri<'d, AnyPin>,
427 cts: Option<Peri<'d, AnyPin>>, 440 cts: Option<Peri<'d, AnyPin>>,
428 tx_buffer: &'d mut [u8], 441 tx_buffer: &'d mut [u8],
429 ) -> Self { 442 ) -> Self {
430 let r = U::regs(); 443 let r = U::regs();
444 let irq = U::Interrupt::IRQ;
445 let state = U::state();
446 let buffered_state = U::buffered_state();
431 447
432 configure_tx_pins(r, txd, cts); 448 configure_tx_pins(r, txd, cts);
433 449
434 // Initialize state 450 // Initialize state
435 let s = U::buffered_state(); 451 buffered_state.tx_count.store(0, Ordering::Relaxed);
436 s.tx_count.store(0, Ordering::Relaxed);
437 let len = tx_buffer.len(); 452 let len = tx_buffer.len();
438 unsafe { s.tx_buf.init(tx_buffer.as_mut_ptr(), len) }; 453 unsafe { buffered_state.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
439 454
440 r.events_txstarted().write_value(0); 455 r.events_txstarted().write_value(0);
441 456
@@ -444,15 +459,21 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> {
444 w.set_endtx(true); 459 w.set_endtx(true);
445 }); 460 });
446 461
447 Self { _peri: peri } 462 Self {
463 r,
464 _irq: irq,
465 state,
466 buffered_state,
467 _p: PhantomData,
468 }
448 } 469 }
449 470
450 /// Write a buffer into this writer, returning how many bytes were written. 471 /// Write a buffer into this writer, returning how many bytes were written.
451 pub fn write<'a>(&'a mut self, buf: &'a [u8]) -> impl Future<Output = Result<usize, Error>> + 'a { 472 pub fn write<'a>(&'a mut self, buf: &'a [u8]) -> impl Future<Output = Result<usize, Error>> + 'a + use<'a, 'd> {
452 poll_fn(move |cx| { 473 poll_fn(move |cx| {
453 //trace!("poll_write: {:?}", buf.len()); 474 //trace!("poll_write: {:?}", buf.len());
454 let ss = U::state(); 475 let ss = self.state;
455 let s = U::buffered_state(); 476 let s = self.buffered_state;
456 let mut tx = unsafe { s.tx_buf.writer() }; 477 let mut tx = unsafe { s.tx_buf.writer() };
457 478
458 let tx_buf = tx.push_slice(); 479 let tx_buf = tx.push_slice();
@@ -469,7 +490,7 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> {
469 //trace!("poll_write: queued {:?}", n); 490 //trace!("poll_write: queued {:?}", n);
470 491
471 compiler_fence(Ordering::SeqCst); 492 compiler_fence(Ordering::SeqCst);
472 U::Interrupt::pend(); 493 self._irq.pend();
473 494
474 Poll::Ready(Ok(n)) 495 Poll::Ready(Ok(n))
475 }) 496 })
@@ -478,7 +499,7 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> {
478 /// Try writing a buffer without waiting, returning how many bytes were written. 499 /// Try writing a buffer without waiting, returning how many bytes were written.
479 pub fn try_write(&mut self, buf: &[u8]) -> Result<usize, Error> { 500 pub fn try_write(&mut self, buf: &[u8]) -> Result<usize, Error> {
480 //trace!("poll_write: {:?}", buf.len()); 501 //trace!("poll_write: {:?}", buf.len());
481 let s = U::buffered_state(); 502 let s = self.buffered_state;
482 let mut tx = unsafe { s.tx_buf.writer() }; 503 let mut tx = unsafe { s.tx_buf.writer() };
483 504
484 let tx_buf = tx.push_slice(); 505 let tx_buf = tx.push_slice();
@@ -493,17 +514,17 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> {
493 //trace!("poll_write: queued {:?}", n); 514 //trace!("poll_write: queued {:?}", n);
494 515
495 compiler_fence(Ordering::SeqCst); 516 compiler_fence(Ordering::SeqCst);
496 U::Interrupt::pend(); 517 self._irq.pend();
497 518
498 Ok(n) 519 Ok(n)
499 } 520 }
500 521
501 /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination. 522 /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination.
502 pub fn flush(&mut self) -> impl Future<Output = Result<(), Error>> + '_ { 523 pub fn flush(&mut self) -> impl Future<Output = Result<(), Error>> + '_ {
524 let ss = self.state;
525 let s = self.buffered_state;
503 poll_fn(move |cx| { 526 poll_fn(move |cx| {
504 //trace!("poll_flush"); 527 //trace!("poll_flush");
505 let ss = U::state();
506 let s = U::buffered_state();
507 if !s.tx_buf.is_empty() { 528 if !s.tx_buf.is_empty() {
508 //trace!("poll_flush: pending"); 529 //trace!("poll_flush: pending");
509 ss.tx_waker.register(cx.waker()); 530 ss.tx_waker.register(cx.waker());
@@ -513,11 +534,16 @@ impl<'d, U: UarteInstance> BufferedUarteTx<'d, U> {
513 Poll::Ready(Ok(())) 534 Poll::Ready(Ok(()))
514 }) 535 })
515 } 536 }
537
538 /// Adjust the baud rate to the provided value.
539 pub fn set_baudrate(&mut self, baudrate: Baudrate) {
540 self.r.baudrate().write(|w| w.set_baudrate(baudrate));
541 }
516} 542}
517 543
518impl<'a, U: UarteInstance> Drop for BufferedUarteTx<'a, U> { 544impl<'a> Drop for BufferedUarteTx<'a> {
519 fn drop(&mut self) { 545 fn drop(&mut self) {
520 let r = U::regs(); 546 let r = self.r;
521 547
522 r.intenclr().write(|w| { 548 r.intenclr().write(|w| {
523 w.set_txdrdy(true); 549 w.set_txdrdy(true);
@@ -528,31 +554,34 @@ impl<'a, U: UarteInstance> Drop for BufferedUarteTx<'a, U> {
528 r.tasks_stoptx().write_value(1); 554 r.tasks_stoptx().write_value(1);
529 while r.events_txstopped().read() == 0 {} 555 while r.events_txstopped().read() == 0 {}
530 556
531 let s = U::buffered_state(); 557 let s = self.buffered_state;
532 unsafe { s.tx_buf.deinit() } 558 unsafe { s.tx_buf.deinit() }
533 559
534 let s = U::state(); 560 let s = self.state;
535 drop_tx_rx(r, s); 561 drop_tx_rx(r, s);
536 } 562 }
537} 563}
538 564
539/// Reader part of the buffered UARTE driver. 565/// Reader part of the buffered UARTE driver.
540pub struct BufferedUarteRx<'d, U: UarteInstance, T: TimerInstance> { 566pub struct BufferedUarteRx<'d> {
541 _peri: Peri<'d, U>, 567 r: pac::uarte::Uarte,
542 timer: Timer<'d, T>, 568 state: &'static crate::uarte::State,
569 buffered_state: &'static State,
570 timer: Timer<'d>,
543 _ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 1>, 571 _ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 1>,
544 _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 2>, 572 _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 2>,
545 _ppi_group: PpiGroup<'d, AnyGroup>, 573 _ppi_group: PpiGroup<'d, AnyGroup>,
574 _p: PhantomData<&'d ()>,
546} 575}
547 576
548impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> { 577impl<'d> BufferedUarteRx<'d> {
549 /// Create a new BufferedUarte without hardware flow control. 578 /// Create a new BufferedUarte without hardware flow control.
550 /// 579 ///
551 /// # Panics 580 /// # Panics
552 /// 581 ///
553 /// Panics if `rx_buffer.len()` is odd. 582 /// Panics if `rx_buffer.len()` is odd.
554 #[allow(clippy::too_many_arguments)] 583 #[allow(clippy::too_many_arguments)]
555 pub fn new( 584 pub fn new<U: UarteInstance, T: TimerInstance>(
556 uarte: Peri<'d, U>, 585 uarte: Peri<'d, U>,
557 timer: Peri<'d, T>, 586 timer: Peri<'d, T>,
558 ppi_ch1: Peri<'d, impl ConfigurableChannel>, 587 ppi_ch1: Peri<'d, impl ConfigurableChannel>,
@@ -582,7 +611,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
582 /// 611 ///
583 /// Panics if `rx_buffer.len()` is odd. 612 /// Panics if `rx_buffer.len()` is odd.
584 #[allow(clippy::too_many_arguments)] 613 #[allow(clippy::too_many_arguments)]
585 pub fn new_with_rts( 614 pub fn new_with_rts<U: UarteInstance, T: TimerInstance>(
586 uarte: Peri<'d, U>, 615 uarte: Peri<'d, U>,
587 timer: Peri<'d, T>, 616 timer: Peri<'d, T>,
588 ppi_ch1: Peri<'d, impl ConfigurableChannel>, 617 ppi_ch1: Peri<'d, impl ConfigurableChannel>,
@@ -608,7 +637,7 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
608 } 637 }
609 638
610 #[allow(clippy::too_many_arguments)] 639 #[allow(clippy::too_many_arguments)]
611 fn new_inner( 640 fn new_inner<U: UarteInstance, T: TimerInstance>(
612 peri: Peri<'d, U>, 641 peri: Peri<'d, U>,
613 timer: Peri<'d, T>, 642 timer: Peri<'d, T>,
614 ppi_ch1: Peri<'d, AnyConfigurableChannel>, 643 ppi_ch1: Peri<'d, AnyConfigurableChannel>,
@@ -619,22 +648,27 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
619 config: Config, 648 config: Config,
620 rx_buffer: &'d mut [u8], 649 rx_buffer: &'d mut [u8],
621 ) -> Self { 650 ) -> Self {
622 configure(U::regs(), config, rts.is_some()); 651 let r = U::regs();
652 let irq = U::Interrupt::IRQ;
653 let state = U::state();
654 let _buffered_state = U::buffered_state();
655
656 configure(r, config, rts.is_some());
623 657
624 let this = Self::new_innerer(peri, timer, ppi_ch1, ppi_ch2, ppi_group, rxd, rts, rx_buffer); 658 let this = Self::new_innerer(peri, timer, ppi_ch1, ppi_ch2, ppi_group, rxd, rts, rx_buffer);
625 659
626 U::regs().enable().write(|w| w.set_enable(vals::Enable::ENABLED)); 660 r.enable().write(|w| w.set_enable(vals::Enable::ENABLED));
627 U::Interrupt::pend(); 661 irq.pend();
628 unsafe { U::Interrupt::enable() }; 662 unsafe { irq.enable() };
629 663
630 U::state().tx_rx_refcount.store(1, Ordering::Relaxed); 664 state.tx_rx_refcount.store(1, Ordering::Relaxed);
631 665
632 this 666 this
633 } 667 }
634 668
635 #[allow(clippy::too_many_arguments)] 669 #[allow(clippy::too_many_arguments)]
636 fn new_innerer( 670 fn new_innerer<U: UarteInstance, T: TimerInstance>(
637 peri: Peri<'d, U>, 671 _peri: Peri<'d, U>,
638 timer: Peri<'d, T>, 672 timer: Peri<'d, T>,
639 ppi_ch1: Peri<'d, AnyConfigurableChannel>, 673 ppi_ch1: Peri<'d, AnyConfigurableChannel>,
640 ppi_ch2: Peri<'d, AnyConfigurableChannel>, 674 ppi_ch2: Peri<'d, AnyConfigurableChannel>,
@@ -646,16 +680,17 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
646 assert!(rx_buffer.len() % 2 == 0); 680 assert!(rx_buffer.len() % 2 == 0);
647 681
648 let r = U::regs(); 682 let r = U::regs();
683 let state = U::state();
684 let buffered_state = U::buffered_state();
649 685
650 configure_rx_pins(r, rxd, rts); 686 configure_rx_pins(r, rxd, rts);
651 687
652 // Initialize state 688 // Initialize state
653 let s = U::buffered_state(); 689 buffered_state.rx_started_count.store(0, Ordering::Relaxed);
654 s.rx_started_count.store(0, Ordering::Relaxed); 690 buffered_state.rx_ended_count.store(0, Ordering::Relaxed);
655 s.rx_ended_count.store(0, Ordering::Relaxed); 691 buffered_state.rx_started.store(false, Ordering::Relaxed);
656 s.rx_started.store(false, Ordering::Relaxed);
657 let rx_len = rx_buffer.len().min(EASY_DMA_SIZE * 2); 692 let rx_len = rx_buffer.len().min(EASY_DMA_SIZE * 2);
658 unsafe { s.rx_buf.init(rx_buffer.as_mut_ptr(), rx_len) }; 693 unsafe { buffered_state.rx_buf.init(rx_buffer.as_mut_ptr(), rx_len) };
659 694
660 // clear errors 695 // clear errors
661 let errors = r.errorsrc().read(); 696 let errors = r.errorsrc().read();
@@ -683,7 +718,9 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
683 let mut ppi_ch1 = Ppi::new_one_to_one(ppi_ch1, Event::from_reg(r.events_rxdrdy()), timer.task_count()); 718 let mut ppi_ch1 = Ppi::new_one_to_one(ppi_ch1, Event::from_reg(r.events_rxdrdy()), timer.task_count());
684 ppi_ch1.enable(); 719 ppi_ch1.enable();
685 720
686 s.rx_ppi_ch.store(ppi_ch2.number() as u8, Ordering::Relaxed); 721 buffered_state
722 .rx_ppi_ch
723 .store(ppi_ch2.number() as u8, Ordering::Relaxed);
687 let mut ppi_group = PpiGroup::new(ppi_group); 724 let mut ppi_group = PpiGroup::new(ppi_group);
688 let mut ppi_ch2 = Ppi::new_one_to_two( 725 let mut ppi_ch2 = Ppi::new_one_to_two(
689 ppi_ch2, 726 ppi_ch2,
@@ -695,11 +732,14 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
695 ppi_group.add_channel(&ppi_ch2); 732 ppi_group.add_channel(&ppi_ch2);
696 733
697 Self { 734 Self {
698 _peri: peri, 735 r,
736 state,
737 buffered_state,
699 timer, 738 timer,
700 _ppi_ch1: ppi_ch1, 739 _ppi_ch1: ppi_ch1,
701 _ppi_ch2: ppi_ch2, 740 _ppi_ch2: ppi_ch2,
702 _ppi_group: ppi_group, 741 _ppi_group: ppi_group,
742 _p: PhantomData,
703 } 743 }
704 } 744 }
705 745
@@ -714,17 +754,17 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
714 754
715 /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty. 755 /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty.
716 pub fn fill_buf(&mut self) -> impl Future<Output = Result<&'_ [u8], Error>> { 756 pub fn fill_buf(&mut self) -> impl Future<Output = Result<&'_ [u8], Error>> {
757 let r = self.r;
758 let s = self.buffered_state;
759 let ss = self.state;
760 let timer = &self.timer;
717 poll_fn(move |cx| { 761 poll_fn(move |cx| {
718 compiler_fence(Ordering::SeqCst); 762 compiler_fence(Ordering::SeqCst);
719 //trace!("poll_read"); 763 //trace!("poll_read");
720 764
721 let r = U::regs();
722 let s = U::buffered_state();
723 let ss = U::state();
724
725 // Read the RXDRDY counter. 765 // Read the RXDRDY counter.
726 T::regs().tasks_capture(0).write_value(1); 766 timer.cc(0).capture();
727 let mut end = T::regs().cc(0).read() as usize; 767 let mut end = timer.cc(0).read() as usize;
728 //trace!(" rxdrdy count = {:?}", end); 768 //trace!(" rxdrdy count = {:?}", end);
729 769
730 // We've set a compare channel that resets the counter to 0 when it reaches `len*2`. 770 // We've set a compare channel that resets the counter to 0 when it reaches `len*2`.
@@ -771,24 +811,24 @@ impl<'d, U: UarteInstance, T: TimerInstance> BufferedUarteRx<'d, U, T> {
771 return; 811 return;
772 } 812 }
773 813
774 let s = U::buffered_state(); 814 let s = self.buffered_state;
775 let mut rx = unsafe { s.rx_buf.reader() }; 815 let mut rx = unsafe { s.rx_buf.reader() };
776 rx.pop_done(amt); 816 rx.pop_done(amt);
777 U::regs().intenset().write(|w| w.set_rxstarted(true)); 817 self.r.intenset().write(|w| w.set_rxstarted(true));
778 } 818 }
779 819
780 /// we are ready to read if there is data in the buffer 820 /// we are ready to read if there is data in the buffer
781 fn read_ready() -> Result<bool, Error> { 821 fn read_ready(&self) -> Result<bool, Error> {
782 let state = U::buffered_state(); 822 let state = self.buffered_state;
783 Ok(!state.rx_buf.is_empty()) 823 Ok(!state.rx_buf.is_empty())
784 } 824 }
785} 825}
786 826
787impl<'a, U: UarteInstance, T: TimerInstance> Drop for BufferedUarteRx<'a, U, T> { 827impl<'a> Drop for BufferedUarteRx<'a> {
788 fn drop(&mut self) { 828 fn drop(&mut self) {
789 self._ppi_group.disable_all(); 829 self._ppi_group.disable_all();
790 830
791 let r = U::regs(); 831 let r = self.r;
792 832
793 self.timer.stop(); 833 self.timer.stop();
794 834
@@ -801,10 +841,10 @@ impl<'a, U: UarteInstance, T: TimerInstance> Drop for BufferedUarteRx<'a, U, T>
801 r.tasks_stoprx().write_value(1); 841 r.tasks_stoprx().write_value(1);
802 while r.events_rxto().read() == 0 {} 842 while r.events_rxto().read() == 0 {}
803 843
804 let s = U::buffered_state(); 844 let s = self.buffered_state;
805 unsafe { s.rx_buf.deinit() } 845 unsafe { s.rx_buf.deinit() }
806 846
807 let s = U::state(); 847 let s = self.state;
808 drop_tx_rx(r, s); 848 drop_tx_rx(r, s);
809 } 849 }
810} 850}
@@ -818,43 +858,44 @@ mod _embedded_io {
818 } 858 }
819 } 859 }
820 860
821 impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::ErrorType for BufferedUarte<'d, U, T> { 861 impl<'d> embedded_io_async::ErrorType for BufferedUarte<'d> {
822 type Error = Error; 862 type Error = Error;
823 } 863 }
824 864
825 impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::ErrorType for BufferedUarteRx<'d, U, T> { 865 impl<'d> embedded_io_async::ErrorType for BufferedUarteRx<'d> {
826 type Error = Error; 866 type Error = Error;
827 } 867 }
828 868
829 impl<'d, U: UarteInstance> embedded_io_async::ErrorType for BufferedUarteTx<'d, U> { 869 impl<'d> embedded_io_async::ErrorType for BufferedUarteTx<'d> {
830 type Error = Error; 870 type Error = Error;
831 } 871 }
832 872
833 impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::Read for BufferedUarte<'d, U, T> { 873 impl<'d> embedded_io_async::Read for BufferedUarte<'d> {
834 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { 874 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
835 self.read(buf).await 875 self.read(buf).await
836 } 876 }
837 } 877 }
838 878
839 impl<'d: 'd, U: UarteInstance, T: TimerInstance> embedded_io_async::Read for BufferedUarteRx<'d, U, T> { 879 impl<'d> embedded_io_async::Read for BufferedUarteRx<'d> {
840 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { 880 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
841 self.read(buf).await 881 self.read(buf).await
842 } 882 }
843 } 883 }
844 884
845 impl<'d, U: UarteInstance, T: TimerInstance + 'd> embedded_io_async::ReadReady for BufferedUarte<'d, U, T> { 885 impl<'d> embedded_io_async::ReadReady for BufferedUarte<'d> {
846 fn read_ready(&mut self) -> Result<bool, Self::Error> { 886 fn read_ready(&mut self) -> Result<bool, Self::Error> {
847 BufferedUarteRx::<'d, U, T>::read_ready() 887 self.rx.read_ready()
848 } 888 }
849 } 889 }
850 890
851 impl<'d, U: UarteInstance, T: TimerInstance + 'd> embedded_io_async::ReadReady for BufferedUarteRx<'d, U, T> { 891 impl<'d> embedded_io_async::ReadReady for BufferedUarteRx<'d> {
852 fn read_ready(&mut self) -> Result<bool, Self::Error> { 892 fn read_ready(&mut self) -> Result<bool, Self::Error> {
853 Self::read_ready() 893 let state = self.buffered_state;
894 Ok(!state.rx_buf.is_empty())
854 } 895 }
855 } 896 }
856 897
857 impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::BufRead for BufferedUarte<'d, U, T> { 898 impl<'d> embedded_io_async::BufRead for BufferedUarte<'d> {
858 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { 899 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
859 self.fill_buf().await 900 self.fill_buf().await
860 } 901 }
@@ -864,7 +905,7 @@ mod _embedded_io {
864 } 905 }
865 } 906 }
866 907
867 impl<'d: 'd, U: UarteInstance, T: TimerInstance> embedded_io_async::BufRead for BufferedUarteRx<'d, U, T> { 908 impl<'d> embedded_io_async::BufRead for BufferedUarteRx<'d> {
868 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> { 909 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
869 self.fill_buf().await 910 self.fill_buf().await
870 } 911 }
@@ -874,7 +915,7 @@ mod _embedded_io {
874 } 915 }
875 } 916 }
876 917
877 impl<'d, U: UarteInstance, T: TimerInstance> embedded_io_async::Write for BufferedUarte<'d, U, T> { 918 impl<'d> embedded_io_async::Write for BufferedUarte<'d> {
878 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 919 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
879 self.write(buf).await 920 self.write(buf).await
880 } 921 }
@@ -884,7 +925,7 @@ mod _embedded_io {
884 } 925 }
885 } 926 }
886 927
887 impl<'d: 'd, U: UarteInstance> embedded_io_async::Write for BufferedUarteTx<'d, U> { 928 impl<'d> embedded_io_async::Write for BufferedUarteTx<'d> {
888 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 929 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
889 self.write(buf).await 930 self.write(buf).await
890 } 931 }
diff --git a/embassy-nrf/src/chips/nrf51.rs b/embassy-nrf/src/chips/nrf51.rs
index fd13ae5c4..3976e8ff0 100644
--- a/embassy-nrf/src/chips/nrf51.rs
+++ b/embassy-nrf/src/chips/nrf51.rs
@@ -8,6 +8,7 @@ pub const FLASH_SIZE: usize = 128 * 1024;
8embassy_hal_internal::peripherals! { 8embassy_hal_internal::peripherals! {
9 // RTC 9 // RTC
10 RTC0, 10 RTC0,
11 #[cfg(not(feature = "time-driver-rtc1"))]
11 RTC1, 12 RTC1,
12 13
13 // WDT 14 // WDT
@@ -110,6 +111,10 @@ impl_timer!(TIMER2, TIMER2, TIMER2);
110 111
111impl_rng!(RNG, RNG, RNG); 112impl_rng!(RNG, RNG, RNG);
112 113
114impl_rtc!(RTC0, RTC0, RTC0);
115#[cfg(not(feature = "time-driver-rtc1"))]
116impl_rtc!(RTC1, RTC1, RTC1);
117
113impl_pin!(P0_00, 0, 0); 118impl_pin!(P0_00, 0, 0);
114impl_pin!(P0_01, 0, 1); 119impl_pin!(P0_01, 0, 1);
115impl_pin!(P0_02, 0, 2); 120impl_pin!(P0_02, 0, 2);
diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs
index 7e72df8fc..63ba6999a 100644
--- a/embassy-nrf/src/chips/nrf52805.rs
+++ b/embassy-nrf/src/chips/nrf52805.rs
@@ -12,6 +12,7 @@ pub const APPROTECT_MIN_BUILD_CODE: u8 = b'B';
12embassy_hal_internal::peripherals! { 12embassy_hal_internal::peripherals! {
13 // RTC 13 // RTC
14 RTC0, 14 RTC0,
15 #[cfg(not(feature="time-driver-rtc1"))]
15 RTC1, 16 RTC1,
16 17
17 // WDT 18 // WDT
@@ -156,6 +157,10 @@ impl_timer!(TIMER0, TIMER0, TIMER0);
156impl_timer!(TIMER1, TIMER1, TIMER1); 157impl_timer!(TIMER1, TIMER1, TIMER1);
157impl_timer!(TIMER2, TIMER2, TIMER2); 158impl_timer!(TIMER2, TIMER2, TIMER2);
158 159
160impl_rtc!(RTC0, RTC0, RTC0);
161#[cfg(not(feature = "time-driver-rtc1"))]
162impl_rtc!(RTC1, RTC1, RTC1);
163
159impl_pin!(P0_00, 0, 0); 164impl_pin!(P0_00, 0, 0);
160impl_pin!(P0_01, 0, 1); 165impl_pin!(P0_01, 0, 1);
161impl_pin!(P0_02, 0, 2); 166impl_pin!(P0_02, 0, 2);
@@ -234,12 +239,12 @@ embassy_hal_internal::interrupt_mod!(
234 TIMER0, 239 TIMER0,
235 TIMER1, 240 TIMER1,
236 TIMER2, 241 TIMER2,
237 RTC0,
238 TEMP, 242 TEMP,
239 RNG, 243 RNG,
240 ECB, 244 ECB,
241 AAR_CCM, 245 AAR_CCM,
242 WDT, 246 WDT,
247 RTC0,
243 RTC1, 248 RTC1,
244 QDEC, 249 QDEC,
245 EGU0_SWI0, 250 EGU0_SWI0,
diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs
index e388e44e8..7f744f9fb 100644
--- a/embassy-nrf/src/chips/nrf52810.rs
+++ b/embassy-nrf/src/chips/nrf52810.rs
@@ -12,6 +12,7 @@ pub const APPROTECT_MIN_BUILD_CODE: u8 = b'E';
12embassy_hal_internal::peripherals! { 12embassy_hal_internal::peripherals! {
13 // RTC 13 // RTC
14 RTC0, 14 RTC0,
15 #[cfg(not(feature="time-driver-rtc1"))]
15 RTC1, 16 RTC1,
16 17
17 // WDT 18 // WDT
@@ -166,6 +167,10 @@ impl_timer!(TIMER0, TIMER0, TIMER0);
166impl_timer!(TIMER1, TIMER1, TIMER1); 167impl_timer!(TIMER1, TIMER1, TIMER1);
167impl_timer!(TIMER2, TIMER2, TIMER2); 168impl_timer!(TIMER2, TIMER2, TIMER2);
168 169
170impl_rtc!(RTC0, RTC0, RTC0);
171#[cfg(not(feature = "time-driver-rtc1"))]
172impl_rtc!(RTC1, RTC1, RTC1);
173
169impl_pin!(P0_00, 0, 0); 174impl_pin!(P0_00, 0, 0);
170impl_pin!(P0_01, 0, 1); 175impl_pin!(P0_01, 0, 1);
171impl_pin!(P0_02, 0, 2); 176impl_pin!(P0_02, 0, 2);
diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs
index 96b8df30b..908167e31 100644
--- a/embassy-nrf/src/chips/nrf52811.rs
+++ b/embassy-nrf/src/chips/nrf52811.rs
@@ -12,6 +12,7 @@ pub const APPROTECT_MIN_BUILD_CODE: u8 = b'B';
12embassy_hal_internal::peripherals! { 12embassy_hal_internal::peripherals! {
13 // RTC 13 // RTC
14 RTC0, 14 RTC0,
15 #[cfg(not(feature="time-driver-rtc1"))]
15 RTC1, 16 RTC1,
16 17
17 // WDT 18 // WDT
@@ -168,6 +169,10 @@ impl_timer!(TIMER0, TIMER0, TIMER0);
168impl_timer!(TIMER1, TIMER1, TIMER1); 169impl_timer!(TIMER1, TIMER1, TIMER1);
169impl_timer!(TIMER2, TIMER2, TIMER2); 170impl_timer!(TIMER2, TIMER2, TIMER2);
170 171
172impl_rtc!(RTC0, RTC0, RTC0);
173#[cfg(not(feature = "time-driver-rtc1"))]
174impl_rtc!(RTC1, RTC1, RTC1);
175
171impl_pin!(P0_00, 0, 0); 176impl_pin!(P0_00, 0, 0);
172impl_pin!(P0_01, 0, 1); 177impl_pin!(P0_01, 0, 1);
173impl_pin!(P0_02, 0, 2); 178impl_pin!(P0_02, 0, 2);
diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs
index ad461b153..22360575b 100644
--- a/embassy-nrf/src/chips/nrf52820.rs
+++ b/embassy-nrf/src/chips/nrf52820.rs
@@ -15,6 +15,7 @@ embassy_hal_internal::peripherals! {
15 15
16 // RTC 16 // RTC
17 RTC0, 17 RTC0,
18 #[cfg(not(feature="time-driver-rtc1"))]
18 RTC1, 19 RTC1,
19 20
20 // WDT 21 // WDT
@@ -164,6 +165,10 @@ impl_timer!(TIMER1, TIMER1, TIMER1);
164impl_timer!(TIMER2, TIMER2, TIMER2); 165impl_timer!(TIMER2, TIMER2, TIMER2);
165impl_timer!(TIMER3, TIMER3, TIMER3, extended); 166impl_timer!(TIMER3, TIMER3, TIMER3, extended);
166 167
168impl_rtc!(RTC0, RTC0, RTC0);
169#[cfg(not(feature = "time-driver-rtc1"))]
170impl_rtc!(RTC1, RTC1, RTC1);
171
167impl_qdec!(QDEC, QDEC, QDEC); 172impl_qdec!(QDEC, QDEC, QDEC);
168 173
169impl_rng!(RNG, RNG, RNG); 174impl_rng!(RNG, RNG, RNG);
diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs
index cf2abf23a..1598df3fe 100644
--- a/embassy-nrf/src/chips/nrf52832.rs
+++ b/embassy-nrf/src/chips/nrf52832.rs
@@ -16,6 +16,7 @@ pub const APPROTECT_MIN_BUILD_CODE: u8 = b'G';
16embassy_hal_internal::peripherals! { 16embassy_hal_internal::peripherals! {
17 // RTC 17 // RTC
18 RTC0, 18 RTC0,
19 #[cfg(not(feature="time-driver-rtc1"))]
19 RTC1, 20 RTC1,
20 RTC2, 21 RTC2,
21 22
@@ -182,6 +183,11 @@ impl_twim!(TWISPI1, TWIM1, TWISPI1);
182impl_twis!(TWISPI0, TWIS0, TWISPI0); 183impl_twis!(TWISPI0, TWIS0, TWISPI0);
183impl_twis!(TWISPI1, TWIS1, TWISPI1); 184impl_twis!(TWISPI1, TWIS1, TWISPI1);
184 185
186impl_rtc!(RTC0, RTC0, RTC0);
187#[cfg(not(feature = "time-driver-rtc1"))]
188impl_rtc!(RTC1, RTC1, RTC1);
189impl_rtc!(RTC2, RTC2, RTC2);
190
185impl_pwm!(PWM0, PWM0, PWM0); 191impl_pwm!(PWM0, PWM0, PWM0);
186impl_pwm!(PWM1, PWM1, PWM1); 192impl_pwm!(PWM1, PWM1, PWM1);
187impl_pwm!(PWM2, PWM2, PWM2); 193impl_pwm!(PWM2, PWM2, PWM2);
diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs
index e46eb1d2b..6931fb064 100644
--- a/embassy-nrf/src/chips/nrf52833.rs
+++ b/embassy-nrf/src/chips/nrf52833.rs
@@ -15,6 +15,7 @@ embassy_hal_internal::peripherals! {
15 15
16 // RTC 16 // RTC
17 RTC0, 17 RTC0,
18 #[cfg(not(feature = "time-driver-rtc1"))]
18 RTC1, 19 RTC1,
19 RTC2, 20 RTC2,
20 21
@@ -223,6 +224,11 @@ impl_timer!(TIMER2, TIMER2, TIMER2);
223impl_timer!(TIMER3, TIMER3, TIMER3, extended); 224impl_timer!(TIMER3, TIMER3, TIMER3, extended);
224impl_timer!(TIMER4, TIMER4, TIMER4, extended); 225impl_timer!(TIMER4, TIMER4, TIMER4, extended);
225 226
227impl_rtc!(RTC0, RTC0, RTC0);
228#[cfg(not(feature = "time-driver-rtc1"))]
229impl_rtc!(RTC1, RTC1, RTC1);
230impl_rtc!(RTC2, RTC2, RTC2);
231
226impl_pin!(P0_00, 0, 0); 232impl_pin!(P0_00, 0, 0);
227impl_pin!(P0_01, 0, 1); 233impl_pin!(P0_01, 0, 1);
228impl_pin!(P0_02, 0, 2); 234impl_pin!(P0_02, 0, 2);
diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs
index 88747843d..5fa521aae 100644
--- a/embassy-nrf/src/chips/nrf52840.rs
+++ b/embassy-nrf/src/chips/nrf52840.rs
@@ -15,6 +15,7 @@ embassy_hal_internal::peripherals! {
15 15
16 // RTC 16 // RTC
17 RTC0, 17 RTC0,
18 #[cfg(not(feature = "time-driver-rtc1"))]
18 RTC1, 19 RTC1,
19 RTC2, 20 RTC2,
20 21
@@ -220,6 +221,11 @@ impl_timer!(TIMER2, TIMER2, TIMER2);
220impl_timer!(TIMER3, TIMER3, TIMER3, extended); 221impl_timer!(TIMER3, TIMER3, TIMER3, extended);
221impl_timer!(TIMER4, TIMER4, TIMER4, extended); 222impl_timer!(TIMER4, TIMER4, TIMER4, extended);
222 223
224impl_rtc!(RTC0, RTC0, RTC0);
225#[cfg(not(feature = "time-driver-rtc1"))]
226impl_rtc!(RTC1, RTC1, RTC1);
227impl_rtc!(RTC2, RTC2, RTC2);
228
223impl_qspi!(QSPI, QSPI, QSPI); 229impl_qspi!(QSPI, QSPI, QSPI);
224 230
225impl_pdm!(PDM, PDM, PDM); 231impl_pdm!(PDM, PDM, PDM);
diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs
index c0290b7a4..730c9842d 100644
--- a/embassy-nrf/src/chips/nrf5340_app.rs
+++ b/embassy-nrf/src/chips/nrf5340_app.rs
@@ -168,6 +168,7 @@ embassy_hal_internal::peripherals! {
168 168
169 // RTC 169 // RTC
170 RTC0, 170 RTC0,
171 #[cfg(not(feature = "time-driver-rtc1"))]
171 RTC1, 172 RTC1,
172 173
173 // WDT 174 // WDT
@@ -369,6 +370,10 @@ impl_timer!(TIMER0, TIMER0, TIMER0);
369impl_timer!(TIMER1, TIMER1, TIMER1); 370impl_timer!(TIMER1, TIMER1, TIMER1);
370impl_timer!(TIMER2, TIMER2, TIMER2); 371impl_timer!(TIMER2, TIMER2, TIMER2);
371 372
373impl_rtc!(RTC0, RTC0, RTC0);
374#[cfg(not(feature = "time-driver-rtc1"))]
375impl_rtc!(RTC1, RTC1, RTC1);
376
372impl_qspi!(QSPI, QSPI, QSPI); 377impl_qspi!(QSPI, QSPI, QSPI);
373 378
374impl_pdm!(PDM0, PDM0, PDM0); 379impl_pdm!(PDM0, PDM0, PDM0);
diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs
index d4c3e5353..413afc5c5 100644
--- a/embassy-nrf/src/chips/nrf5340_net.rs
+++ b/embassy-nrf/src/chips/nrf5340_net.rs
@@ -59,6 +59,7 @@ pub const FLASH_SIZE: usize = 256 * 1024;
59embassy_hal_internal::peripherals! { 59embassy_hal_internal::peripherals! {
60 // RTC 60 // RTC
61 RTC0, 61 RTC0,
62 #[cfg(not(feature = "time-driver-rtc1"))]
62 RTC1, 63 RTC1,
63 64
64 // WDT 65 // WDT
@@ -218,6 +219,10 @@ impl_timer!(TIMER0, TIMER0, TIMER0);
218impl_timer!(TIMER1, TIMER1, TIMER1); 219impl_timer!(TIMER1, TIMER1, TIMER1);
219impl_timer!(TIMER2, TIMER2, TIMER2); 220impl_timer!(TIMER2, TIMER2, TIMER2);
220 221
222impl_rtc!(RTC0, RTC0, RTC0);
223#[cfg(not(feature = "time-driver-rtc1"))]
224impl_rtc!(RTC1, RTC1, RTC1);
225
221impl_rng!(RNG, RNG, RNG); 226impl_rng!(RNG, RNG, RNG);
222 227
223impl_pin!(P0_00, 0, 0); 228impl_pin!(P0_00, 0, 0);
diff --git a/embassy-nrf/src/chips/nrf9120.rs b/embassy-nrf/src/chips/nrf9120.rs
index e8ddbf86f..5aee19d97 100644
--- a/embassy-nrf/src/chips/nrf9120.rs
+++ b/embassy-nrf/src/chips/nrf9120.rs
@@ -131,6 +131,7 @@ pub const FLASH_SIZE: usize = 1024 * 1024;
131embassy_hal_internal::peripherals! { 131embassy_hal_internal::peripherals! {
132 // RTC 132 // RTC
133 RTC0, 133 RTC0,
134 #[cfg(not(feature = "time-driver-rtc1"))]
134 RTC1, 135 RTC1,
135 136
136 // WDT 137 // WDT
@@ -276,6 +277,10 @@ impl_timer!(TIMER0, TIMER0, TIMER0);
276impl_timer!(TIMER1, TIMER1, TIMER1); 277impl_timer!(TIMER1, TIMER1, TIMER1);
277impl_timer!(TIMER2, TIMER2, TIMER2); 278impl_timer!(TIMER2, TIMER2, TIMER2);
278 279
280impl_rtc!(RTC0, RTC0, RTC0);
281#[cfg(not(feature = "time-driver-rtc1"))]
282impl_rtc!(RTC1, RTC1, RTC1);
283
279impl_pin!(P0_00, 0, 0); 284impl_pin!(P0_00, 0, 0);
280impl_pin!(P0_01, 0, 1); 285impl_pin!(P0_01, 0, 1);
281impl_pin!(P0_02, 0, 2); 286impl_pin!(P0_02, 0, 2);
diff --git a/embassy-nrf/src/chips/nrf9160.rs b/embassy-nrf/src/chips/nrf9160.rs
index 5d04a72e5..64aec217c 100644
--- a/embassy-nrf/src/chips/nrf9160.rs
+++ b/embassy-nrf/src/chips/nrf9160.rs
@@ -131,6 +131,7 @@ pub const FLASH_SIZE: usize = 1024 * 1024;
131embassy_hal_internal::peripherals! { 131embassy_hal_internal::peripherals! {
132 // RTC 132 // RTC
133 RTC0, 133 RTC0,
134 #[cfg(not(feature = "time-driver-rtc1"))]
134 RTC1, 135 RTC1,
135 136
136 // WDT 137 // WDT
@@ -276,6 +277,10 @@ impl_timer!(TIMER0, TIMER0, TIMER0);
276impl_timer!(TIMER1, TIMER1, TIMER1); 277impl_timer!(TIMER1, TIMER1, TIMER1);
277impl_timer!(TIMER2, TIMER2, TIMER2); 278impl_timer!(TIMER2, TIMER2, TIMER2);
278 279
280impl_rtc!(RTC0, RTC0, RTC0);
281#[cfg(not(feature = "time-driver-rtc1"))]
282impl_rtc!(RTC1, RTC1, RTC1);
283
279impl_pin!(P0_00, 0, 0); 284impl_pin!(P0_00, 0, 0);
280impl_pin!(P0_01, 0, 1); 285impl_pin!(P0_01, 0, 1);
281impl_pin!(P0_02, 0, 2); 286impl_pin!(P0_02, 0, 2);
diff --git a/embassy-nrf/src/egu.rs b/embassy-nrf/src/egu.rs
index 028396c7c..f7372fca1 100644
--- a/embassy-nrf/src/egu.rs
+++ b/embassy-nrf/src/egu.rs
@@ -13,21 +13,26 @@ use crate::ppi::{Event, Task};
13use crate::{interrupt, pac, Peri}; 13use crate::{interrupt, pac, Peri};
14 14
15/// An instance of the EGU. 15/// An instance of the EGU.
16pub struct Egu<'d, T: Instance> { 16pub struct Egu<'d> {
17 _p: Peri<'d, T>, 17 r: pac::egu::Egu,
18 _phantom: PhantomData<&'d ()>,
18} 19}
19 20
20impl<'d, T: Instance> Egu<'d, T> { 21impl<'d> Egu<'d> {
21 /// Create a new EGU instance. 22 /// Create a new EGU instance.
22 pub fn new(_p: Peri<'d, T>) -> Self { 23 pub fn new<T: Instance>(_p: Peri<'d, T>) -> Self {
23 Self { _p } 24 Self {
25 r: T::regs(),
26 _phantom: PhantomData,
27 }
24 } 28 }
25 29
26 /// Get a handle to a trigger for the EGU. 30 /// Get a handle to a trigger for the EGU.
27 pub fn trigger(&mut self, number: TriggerNumber) -> Trigger<'d, T> { 31 pub fn trigger(&mut self, number: TriggerNumber) -> Trigger<'d> {
28 Trigger { 32 Trigger {
29 number, 33 number,
30 _p: PhantomData, 34 r: self.r,
35 _phantom: PhantomData,
31 } 36 }
32 } 37 }
33} 38}
@@ -57,36 +62,37 @@ macro_rules! impl_egu {
57} 62}
58 63
59/// Represents a trigger within the EGU. 64/// Represents a trigger within the EGU.
60pub struct Trigger<'d, T: Instance> { 65pub struct Trigger<'d> {
61 number: TriggerNumber, 66 number: TriggerNumber,
62 _p: PhantomData<&'d T>, 67 r: pac::egu::Egu,
68 _phantom: PhantomData<&'d ()>,
63} 69}
64 70
65impl<'d, T: Instance> Trigger<'d, T> { 71impl<'d> Trigger<'d> {
66 /// Get task for this trigger to use with PPI. 72 /// Get task for this trigger to use with PPI.
67 pub fn task(&self) -> Task<'d> { 73 pub fn task(&self) -> Task<'d> {
68 let nr = self.number as usize; 74 let nr = self.number as usize;
69 let regs = T::regs(); 75 Task::from_reg(self.r.tasks_trigger(nr))
70 Task::from_reg(regs.tasks_trigger(nr))
71 } 76 }
72 77
73 /// Get event for this trigger to use with PPI. 78 /// Get event for this trigger to use with PPI.
74 pub fn event(&self) -> Event<'d> { 79 pub fn event(&self) -> Event<'d> {
75 let nr = self.number as usize; 80 let nr = self.number as usize;
76 let regs = T::regs(); 81 Event::from_reg(self.r.events_triggered(nr))
77 Event::from_reg(regs.events_triggered(nr))
78 } 82 }
79 83
80 /// Enable interrupts for this trigger 84 /// Enable interrupts for this trigger
81 pub fn enable_interrupt(&mut self) { 85 pub fn enable_interrupt(&mut self) {
82 let regs = T::regs(); 86 self.r
83 regs.intenset().modify(|w| w.set_triggered(self.number as usize, true)); 87 .intenset()
88 .modify(|w| w.set_triggered(self.number as usize, true));
84 } 89 }
85 90
86 /// Enable interrupts for this trigger 91 /// Enable interrupts for this trigger
87 pub fn disable_interrupt(&mut self) { 92 pub fn disable_interrupt(&mut self) {
88 let regs = T::regs(); 93 self.r
89 regs.intenset().modify(|w| w.set_triggered(self.number as usize, false)); 94 .intenset()
95 .modify(|w| w.set_triggered(self.number as usize, false));
90 } 96 }
91} 97}
92 98
diff --git a/embassy-nrf/src/embassy_net_802154_driver.rs b/embassy-nrf/src/embassy_net_802154_driver.rs
index 8662be787..b3fc5df2c 100644
--- a/embassy-nrf/src/embassy_net_802154_driver.rs
+++ b/embassy-nrf/src/embassy_net_802154_driver.rs
@@ -32,12 +32,12 @@ impl<const N_RX: usize, const N_TX: usize> State<N_RX, N_TX> {
32/// Background runner for the driver. 32/// Background runner for the driver.
33/// 33///
34/// You must call `.run()` in a background task for the driver to operate. 34/// You must call `.run()` in a background task for the driver to operate.
35pub struct Runner<'d, T: nrf::radio::Instance> { 35pub struct Runner<'d> {
36 radio: nrf::radio::ieee802154::Radio<'d, T>, 36 radio: nrf::radio::ieee802154::Radio<'d>,
37 ch: ch::Runner<'d, MTU>, 37 ch: ch::Runner<'d, MTU>,
38} 38}
39 39
40impl<'d, T: nrf::radio::Instance> Runner<'d, T> { 40impl<'d> Runner<'d> {
41 /// Drives the radio. Needs to run to use the driver. 41 /// Drives the radio. Needs to run to use the driver.
42 pub async fn run(mut self) -> ! { 42 pub async fn run(mut self) -> ! {
43 let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split(); 43 let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split();
@@ -84,7 +84,7 @@ pub async fn new<'a, const N_RX: usize, const N_TX: usize, T: nrf::radio::Instan
84 radio: nrf::Peri<'a, T>, 84 radio: nrf::Peri<'a, T>,
85 irq: Irq, 85 irq: Irq,
86 state: &'a mut State<N_RX, N_TX>, 86 state: &'a mut State<N_RX, N_TX>,
87) -> Result<(Device<'a>, Runner<'a, T>), ()> 87) -> Result<(Device<'a>, Runner<'a>), ()>
88where 88where
89 Irq: interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'a, 89 Irq: interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'a,
90{ 90{
diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs
index 65f2d99f7..ab5e7ed4b 100644
--- a/embassy-nrf/src/gpio.rs
+++ b/embassy-nrf/src/gpio.rs
@@ -75,6 +75,15 @@ impl<'d> Input<'d> {
75 } 75 }
76} 76}
77 77
78impl Input<'static> {
79 /// Persist the pin's configuration for the rest of the program's lifetime. This method should
80 /// be preferred over [`core::mem::forget()`] because the `'static` bound prevents accidental
81 /// reuse of the underlying peripheral.
82 pub fn persist(self) {
83 self.pin.persist()
84 }
85}
86
78/// Digital input or output level. 87/// Digital input or output level.
79#[derive(Clone, Copy, Debug, Eq, PartialEq)] 88#[derive(Clone, Copy, Debug, Eq, PartialEq)]
80#[cfg_attr(feature = "defmt", derive(defmt::Format))] 89#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -208,7 +217,7 @@ pub struct Output<'d> {
208} 217}
209 218
210impl<'d> Output<'d> { 219impl<'d> Output<'d> {
211 /// Create GPIO output driver for a [Pin] with the provided [Level] and [OutputDriver] configuration. 220 /// Create GPIO output driver for a [Pin] with the provided [Level] and [OutputDrive] configuration.
212 #[inline] 221 #[inline]
213 pub fn new(pin: Peri<'d, impl Pin>, initial_output: Level, drive: OutputDrive) -> Self { 222 pub fn new(pin: Peri<'d, impl Pin>, initial_output: Level, drive: OutputDrive) -> Self {
214 let mut pin = Flex::new(pin); 223 let mut pin = Flex::new(pin);
@@ -264,6 +273,15 @@ impl<'d> Output<'d> {
264 } 273 }
265} 274}
266 275
276impl Output<'static> {
277 /// Persist the pin's configuration for the rest of the program's lifetime. This method should
278 /// be preferred over [`core::mem::forget()`] because the `'static` bound prevents accidental
279 /// reuse of the underlying peripheral.
280 pub fn persist(self) {
281 self.pin.persist()
282 }
283}
284
267pub(crate) fn convert_drive(w: &mut pac::gpio::regs::PinCnf, drive: OutputDrive) { 285pub(crate) fn convert_drive(w: &mut pac::gpio::regs::PinCnf, drive: OutputDrive) {
268 #[cfg(not(feature = "_nrf54l"))] 286 #[cfg(not(feature = "_nrf54l"))]
269 { 287 {
@@ -447,6 +465,15 @@ impl<'d> Flex<'d> {
447 } 465 }
448} 466}
449 467
468impl Flex<'static> {
469 /// Persist the pin's configuration for the rest of the program's lifetime. This method should
470 /// be preferred over [`core::mem::forget()`] because the `'static` bound prevents accidental
471 /// reuse of the underlying peripheral.
472 pub fn persist(self) {
473 core::mem::forget(self);
474 }
475}
476
450impl<'d> Drop for Flex<'d> { 477impl<'d> Drop for Flex<'d> {
451 fn drop(&mut self) { 478 fn drop(&mut self) {
452 self.set_as_disconnected(); 479 self.set_as_disconnected();
@@ -754,7 +781,7 @@ impl<'d> embedded_hal_1::digital::ErrorType for Flex<'d> {
754 type Error = Infallible; 781 type Error = Infallible;
755} 782}
756 783
757/// Implement [`InputPin`] for [`Flex`]; 784/// Implement [embedded_hal_1::digital::InputPin] for [`Flex`];
758/// 785///
759/// If the pin is not in input mode the result is unspecified. 786/// If the pin is not in input mode the result is unspecified.
760impl<'d> embedded_hal_1::digital::InputPin for Flex<'d> { 787impl<'d> embedded_hal_1::digital::InputPin for Flex<'d> {
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs
index d169b49f9..43e43f0bf 100644
--- a/embassy-nrf/src/gpiote.rs
+++ b/embassy-nrf/src/gpiote.rs
@@ -193,6 +193,15 @@ pub struct InputChannel<'d> {
193 pin: Input<'d>, 193 pin: Input<'d>,
194} 194}
195 195
196impl InputChannel<'static> {
197 /// Persist the channel's configuration for the rest of the program's lifetime. This method
198 /// should be preferred over [`core::mem::forget()`] because the `'static` bound prevents
199 /// accidental reuse of the underlying peripheral.
200 pub fn persist(self) {
201 core::mem::forget(self);
202 }
203}
204
196impl<'d> Drop for InputChannel<'d> { 205impl<'d> Drop for InputChannel<'d> {
197 fn drop(&mut self) { 206 fn drop(&mut self) {
198 let g = regs(); 207 let g = regs();
@@ -263,6 +272,15 @@ pub struct OutputChannel<'d> {
263 _pin: Output<'d>, 272 _pin: Output<'d>,
264} 273}
265 274
275impl OutputChannel<'static> {
276 /// Persist the channel's configuration for the rest of the program's lifetime. This method
277 /// should be preferred over [`core::mem::forget()`] because the `'static` bound prevents
278 /// accidental reuse of the underlying peripheral.
279 pub fn persist(self) {
280 core::mem::forget(self);
281 }
282}
283
266impl<'d> Drop for OutputChannel<'d> { 284impl<'d> Drop for OutputChannel<'d> {
267 fn drop(&mut self) { 285 fn drop(&mut self) {
268 let g = regs(); 286 let g = regs();
diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs
index a7dde8cd7..1bfa18491 100644
--- a/embassy-nrf/src/i2s.rs
+++ b/embassy-nrf/src/i2s.rs
@@ -252,7 +252,7 @@ impl ApproxSampleRate {
252/// 252///
253/// Those are non standard sample rates that can be configured without error. 253/// Those are non standard sample rates that can be configured without error.
254/// 254///
255/// For custom master clock configuration, please refer to [Mode]. 255/// For custom master clock configuration, please refer to [vals::Mode].
256#[derive(Clone, Copy)] 256#[derive(Clone, Copy)]
257pub enum ExactSampleRate { 257pub enum ExactSampleRate {
258 /// 8000 Hz 258 /// 8000 Hz
@@ -381,7 +381,7 @@ pub struct InterruptHandler<T: Instance> {
381 381
382impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { 382impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
383 unsafe fn on_interrupt() { 383 unsafe fn on_interrupt() {
384 let device = Device::<T>::new(); 384 let device = Device::new(T::regs());
385 let s = T::state(); 385 let s = T::state();
386 386
387 if device.is_tx_ptr_updated() { 387 if device.is_tx_ptr_updated() {
@@ -405,8 +405,9 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
405} 405}
406 406
407/// I2S driver. 407/// I2S driver.
408pub struct I2S<'d, T: Instance> { 408pub struct I2S<'d> {
409 i2s: Peri<'d, T>, 409 r: pac::i2s::I2s,
410 state: &'static State,
410 mck: Option<Peri<'d, AnyPin>>, 411 mck: Option<Peri<'d, AnyPin>>,
411 sck: Peri<'d, AnyPin>, 412 sck: Peri<'d, AnyPin>,
412 lrck: Peri<'d, AnyPin>, 413 lrck: Peri<'d, AnyPin>,
@@ -416,10 +417,10 @@ pub struct I2S<'d, T: Instance> {
416 config: Config, 417 config: Config,
417} 418}
418 419
419impl<'d, T: Instance> I2S<'d, T> { 420impl<'d> I2S<'d> {
420 /// Create a new I2S in master mode 421 /// Create a new I2S in master mode
421 pub fn new_master( 422 pub fn new_master<T: Instance>(
422 i2s: Peri<'d, T>, 423 _i2s: Peri<'d, T>,
423 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 424 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
424 mck: Peri<'d, impl GpioPin>, 425 mck: Peri<'d, impl GpioPin>,
425 sck: Peri<'d, impl GpioPin>, 426 sck: Peri<'d, impl GpioPin>,
@@ -427,8 +428,12 @@ impl<'d, T: Instance> I2S<'d, T> {
427 master_clock: MasterClock, 428 master_clock: MasterClock,
428 config: Config, 429 config: Config,
429 ) -> Self { 430 ) -> Self {
431 T::Interrupt::unpend();
432 unsafe { T::Interrupt::enable() };
433
430 Self { 434 Self {
431 i2s, 435 r: T::regs(),
436 state: T::state(),
432 mck: Some(mck.into()), 437 mck: Some(mck.into()),
433 sck: sck.into(), 438 sck: sck.into(),
434 lrck: lrck.into(), 439 lrck: lrck.into(),
@@ -440,15 +445,19 @@ impl<'d, T: Instance> I2S<'d, T> {
440 } 445 }
441 446
442 /// Create a new I2S in slave mode 447 /// Create a new I2S in slave mode
443 pub fn new_slave( 448 pub fn new_slave<T: Instance>(
444 i2s: Peri<'d, T>, 449 _i2s: Peri<'d, T>,
445 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 450 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
446 sck: Peri<'d, impl GpioPin>, 451 sck: Peri<'d, impl GpioPin>,
447 lrck: Peri<'d, impl GpioPin>, 452 lrck: Peri<'d, impl GpioPin>,
448 config: Config, 453 config: Config,
449 ) -> Self { 454 ) -> Self {
455 T::Interrupt::unpend();
456 unsafe { T::Interrupt::enable() };
457
450 Self { 458 Self {
451 i2s, 459 r: T::regs(),
460 state: T::state(),
452 mck: None, 461 mck: None,
453 sck: sck.into(), 462 sck: sck.into(),
454 lrck: lrck.into(), 463 lrck: lrck.into(),
@@ -464,10 +473,13 @@ impl<'d, T: Instance> I2S<'d, T> {
464 mut self, 473 mut self,
465 sdout: Peri<'d, impl GpioPin>, 474 sdout: Peri<'d, impl GpioPin>,
466 buffers: MultiBuffering<S, NB, NS>, 475 buffers: MultiBuffering<S, NB, NS>,
467 ) -> OutputStream<'d, T, S, NB, NS> { 476 ) -> OutputStream<'d, S, NB, NS> {
468 self.sdout = Some(sdout.into()); 477 self.sdout = Some(sdout.into());
478 let p = self.build();
469 OutputStream { 479 OutputStream {
470 _p: self.build(), 480 r: p.0,
481 state: p.1,
482 _phantom: PhantomData,
471 buffers, 483 buffers,
472 } 484 }
473 } 485 }
@@ -477,11 +489,14 @@ impl<'d, T: Instance> I2S<'d, T> {
477 mut self, 489 mut self,
478 sdin: Peri<'d, impl GpioPin>, 490 sdin: Peri<'d, impl GpioPin>,
479 buffers: MultiBuffering<S, NB, NS>, 491 buffers: MultiBuffering<S, NB, NS>,
480 ) -> InputStream<'d, T, S, NB, NS> { 492 ) -> InputStream<'d, S, NB, NS> {
481 self.sdin = Some(sdin.into()); 493 self.sdin = Some(sdin.into());
494 let p = self.build();
482 InputStream { 495 InputStream {
483 _p: self.build(), 496 r: p.0,
497 state: p.1,
484 buffers, 498 buffers,
499 _phantom: PhantomData,
485 } 500 }
486 } 501 }
487 502
@@ -492,30 +507,33 @@ impl<'d, T: Instance> I2S<'d, T> {
492 sdout: Peri<'d, impl GpioPin>, 507 sdout: Peri<'d, impl GpioPin>,
493 buffers_out: MultiBuffering<S, NB, NS>, 508 buffers_out: MultiBuffering<S, NB, NS>,
494 buffers_in: MultiBuffering<S, NB, NS>, 509 buffers_in: MultiBuffering<S, NB, NS>,
495 ) -> FullDuplexStream<'d, T, S, NB, NS> { 510 ) -> FullDuplexStream<'d, S, NB, NS> {
496 self.sdout = Some(sdout.into()); 511 self.sdout = Some(sdout.into());
497 self.sdin = Some(sdin.into()); 512 self.sdin = Some(sdin.into());
513 let p = self.build();
498 514
499 FullDuplexStream { 515 FullDuplexStream {
500 _p: self.build(), 516 r: p.0,
517 state: p.1,
518 _phantom: PhantomData,
501 buffers_out, 519 buffers_out,
502 buffers_in, 520 buffers_in,
503 } 521 }
504 } 522 }
505 523
506 fn build(self) -> Peri<'d, T> { 524 fn build(self) -> (pac::i2s::I2s, &'static State) {
507 self.apply_config(); 525 self.apply_config();
508 self.select_pins(); 526 self.select_pins();
509 self.setup_interrupt(); 527 self.setup_interrupt();
510 528
511 let device = Device::<T>::new(); 529 let device = Device::new(self.r);
512 device.enable(); 530 device.enable();
513 531
514 self.i2s 532 (self.r, self.state)
515 } 533 }
516 534
517 fn apply_config(&self) { 535 fn apply_config(&self) {
518 let c = T::regs().config(); 536 let c = self.r.config();
519 match &self.master_clock { 537 match &self.master_clock {
520 Some(MasterClock { freq, ratio }) => { 538 Some(MasterClock { freq, ratio }) => {
521 c.mode().write(|w| w.set_mode(vals::Mode::MASTER)); 539 c.mode().write(|w| w.set_mode(vals::Mode::MASTER));
@@ -535,7 +553,7 @@ impl<'d, T: Instance> I2S<'d, T> {
535 } 553 }
536 554
537 fn select_pins(&self) { 555 fn select_pins(&self) {
538 let psel = T::regs().psel(); 556 let psel = self.r.psel();
539 psel.mck().write_value(self.mck.psel_bits()); 557 psel.mck().write_value(self.mck.psel_bits());
540 psel.sck().write_value(self.sck.psel_bits()); 558 psel.sck().write_value(self.sck.psel_bits());
541 psel.lrck().write_value(self.lrck.psel_bits()); 559 psel.lrck().write_value(self.lrck.psel_bits());
@@ -544,10 +562,9 @@ impl<'d, T: Instance> I2S<'d, T> {
544 } 562 }
545 563
546 fn setup_interrupt(&self) { 564 fn setup_interrupt(&self) {
547 T::Interrupt::unpend(); 565 // Interrupt is already set up in constructor
548 unsafe { T::Interrupt::enable() };
549 566
550 let device = Device::<T>::new(); 567 let device = Device::new(self.r);
551 device.disable_tx_ptr_interrupt(); 568 device.disable_tx_ptr_interrupt();
552 device.disable_rx_ptr_interrupt(); 569 device.disable_rx_ptr_interrupt();
553 device.disable_stopped_interrupt(); 570 device.disable_stopped_interrupt();
@@ -561,16 +578,16 @@ impl<'d, T: Instance> I2S<'d, T> {
561 device.enable_stopped_interrupt(); 578 device.enable_stopped_interrupt();
562 } 579 }
563 580
564 async fn stop() { 581 async fn stop(r: pac::i2s::I2s, state: &State) {
565 compiler_fence(Ordering::SeqCst); 582 compiler_fence(Ordering::SeqCst);
566 583
567 let device = Device::<T>::new(); 584 let device = Device::new(r);
568 device.stop(); 585 device.stop();
569 586
570 T::state().started.store(false, Ordering::Relaxed); 587 state.started.store(false, Ordering::Relaxed);
571 588
572 poll_fn(|cx| { 589 poll_fn(|cx| {
573 T::state().stop_waker.register(cx.waker()); 590 state.stop_waker.register(cx.waker());
574 591
575 if device.is_stopped() { 592 if device.is_stopped() {
576 trace!("STOP: Ready"); 593 trace!("STOP: Ready");
@@ -586,7 +603,7 @@ impl<'d, T: Instance> I2S<'d, T> {
586 device.disable(); 603 device.disable();
587 } 604 }
588 605
589 async fn send_from_ram<S>(buffer_ptr: *const [S]) -> Result<(), Error> 606 async fn send_from_ram<S>(r: pac::i2s::I2s, state: &State, buffer_ptr: *const [S]) -> Result<(), Error>
590 where 607 where
591 S: Sample, 608 S: Sample,
592 { 609 {
@@ -596,22 +613,22 @@ impl<'d, T: Instance> I2S<'d, T> {
596 613
597 compiler_fence(Ordering::SeqCst); 614 compiler_fence(Ordering::SeqCst);
598 615
599 let device = Device::<T>::new(); 616 let device = Device::new(r);
600 617
601 device.update_tx(buffer_ptr)?; 618 device.update_tx(buffer_ptr)?;
602 619
603 Self::wait_tx_ptr_update().await; 620 Self::wait_tx_ptr_update(r, state).await;
604 621
605 compiler_fence(Ordering::SeqCst); 622 compiler_fence(Ordering::SeqCst);
606 623
607 Ok(()) 624 Ok(())
608 } 625 }
609 626
610 async fn wait_tx_ptr_update() { 627 async fn wait_tx_ptr_update(r: pac::i2s::I2s, state: &State) {
611 let drop = OnDrop::new(move || { 628 let drop = OnDrop::new(move || {
612 trace!("TX DROP: Stopping"); 629 trace!("TX DROP: Stopping");
613 630
614 let device = Device::<T>::new(); 631 let device = Device::new(r);
615 device.disable_tx_ptr_interrupt(); 632 device.disable_tx_ptr_interrupt();
616 device.reset_tx_ptr_event(); 633 device.reset_tx_ptr_event();
617 device.disable_tx(); 634 device.disable_tx();
@@ -623,9 +640,9 @@ impl<'d, T: Instance> I2S<'d, T> {
623 }); 640 });
624 641
625 poll_fn(|cx| { 642 poll_fn(|cx| {
626 T::state().tx_waker.register(cx.waker()); 643 state.tx_waker.register(cx.waker());
627 644
628 let device = Device::<T>::new(); 645 let device = Device::new(r);
629 if device.is_tx_ptr_updated() { 646 if device.is_tx_ptr_updated() {
630 trace!("TX POLL: Ready"); 647 trace!("TX POLL: Ready");
631 device.reset_tx_ptr_event(); 648 device.reset_tx_ptr_event();
@@ -641,7 +658,7 @@ impl<'d, T: Instance> I2S<'d, T> {
641 drop.defuse(); 658 drop.defuse();
642 } 659 }
643 660
644 async fn receive_from_ram<S>(buffer_ptr: *mut [S]) -> Result<(), Error> 661 async fn receive_from_ram<S>(r: pac::i2s::I2s, state: &State, buffer_ptr: *mut [S]) -> Result<(), Error>
645 where 662 where
646 S: Sample, 663 S: Sample,
647 { 664 {
@@ -652,22 +669,22 @@ impl<'d, T: Instance> I2S<'d, T> {
652 669
653 compiler_fence(Ordering::SeqCst); 670 compiler_fence(Ordering::SeqCst);
654 671
655 let device = Device::<T>::new(); 672 let device = Device::new(r);
656 673
657 device.update_rx(buffer_ptr)?; 674 device.update_rx(buffer_ptr)?;
658 675
659 Self::wait_rx_ptr_update().await; 676 Self::wait_rx_ptr_update(r, state).await;
660 677
661 compiler_fence(Ordering::SeqCst); 678 compiler_fence(Ordering::SeqCst);
662 679
663 Ok(()) 680 Ok(())
664 } 681 }
665 682
666 async fn wait_rx_ptr_update() { 683 async fn wait_rx_ptr_update(r: pac::i2s::I2s, state: &State) {
667 let drop = OnDrop::new(move || { 684 let drop = OnDrop::new(move || {
668 trace!("RX DROP: Stopping"); 685 trace!("RX DROP: Stopping");
669 686
670 let device = Device::<T>::new(); 687 let device = Device::new(r);
671 device.disable_rx_ptr_interrupt(); 688 device.disable_rx_ptr_interrupt();
672 device.reset_rx_ptr_event(); 689 device.reset_rx_ptr_event();
673 device.disable_rx(); 690 device.disable_rx();
@@ -679,9 +696,9 @@ impl<'d, T: Instance> I2S<'d, T> {
679 }); 696 });
680 697
681 poll_fn(|cx| { 698 poll_fn(|cx| {
682 T::state().rx_waker.register(cx.waker()); 699 state.rx_waker.register(cx.waker());
683 700
684 let device = Device::<T>::new(); 701 let device = Device::new(r);
685 if device.is_rx_ptr_updated() { 702 if device.is_rx_ptr_updated() {
686 trace!("RX POLL: Ready"); 703 trace!("RX POLL: Ready");
687 device.reset_rx_ptr_event(); 704 device.reset_rx_ptr_event();
@@ -699,12 +716,14 @@ impl<'d, T: Instance> I2S<'d, T> {
699} 716}
700 717
701/// I2S output 718/// I2S output
702pub struct OutputStream<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> { 719pub struct OutputStream<'d, S: Sample, const NB: usize, const NS: usize> {
703 _p: Peri<'d, T>, 720 r: pac::i2s::I2s,
721 state: &'static State,
704 buffers: MultiBuffering<S, NB, NS>, 722 buffers: MultiBuffering<S, NB, NS>,
723 _phantom: PhantomData<&'d ()>,
705} 724}
706 725
707impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> OutputStream<'d, T, S, NB, NS> { 726impl<'d, S: Sample, const NB: usize, const NS: usize> OutputStream<'d, S, NB, NS> {
708 /// Get a mutable reference to the current buffer. 727 /// Get a mutable reference to the current buffer.
709 pub fn buffer(&mut self) -> &mut [S] { 728 pub fn buffer(&mut self) -> &mut [S] {
710 self.buffers.get_mut() 729 self.buffers.get_mut()
@@ -715,10 +734,9 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> OutputStream<
715 where 734 where
716 S: Sample, 735 S: Sample,
717 { 736 {
718 let device = Device::<T>::new(); 737 let device = Device::new(self.r);
719 738
720 let s = T::state(); 739 if self.state.started.load(Ordering::Relaxed) {
721 if s.started.load(Ordering::Relaxed) {
722 self.stop().await; 740 self.stop().await;
723 } 741 }
724 742
@@ -727,11 +745,11 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> OutputStream<
727 745
728 device.update_tx(self.buffers.switch())?; 746 device.update_tx(self.buffers.switch())?;
729 747
730 s.started.store(true, Ordering::Relaxed); 748 self.state.started.store(true, Ordering::Relaxed);
731 749
732 device.start(); 750 device.start();
733 751
734 I2S::<T>::wait_tx_ptr_update().await; 752 I2S::wait_tx_ptr_update(self.r, self.state).await;
735 753
736 Ok(()) 754 Ok(())
737 } 755 }
@@ -739,7 +757,7 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> OutputStream<
739 /// Stops the I2S transfer and waits until it has stopped. 757 /// Stops the I2S transfer and waits until it has stopped.
740 #[inline(always)] 758 #[inline(always)]
741 pub async fn stop(&self) { 759 pub async fn stop(&self) {
742 I2S::<T>::stop().await 760 I2S::stop(self.r, self.state).await
743 } 761 }
744 762
745 /// Sends the current buffer for transmission in the DMA. 763 /// Sends the current buffer for transmission in the DMA.
@@ -748,17 +766,19 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> OutputStream<
748 where 766 where
749 S: Sample, 767 S: Sample,
750 { 768 {
751 I2S::<T>::send_from_ram(self.buffers.switch()).await 769 I2S::send_from_ram(self.r, self.state, self.buffers.switch()).await
752 } 770 }
753} 771}
754 772
755/// I2S input 773/// I2S input
756pub struct InputStream<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> { 774pub struct InputStream<'d, S: Sample, const NB: usize, const NS: usize> {
757 _p: Peri<'d, T>, 775 r: pac::i2s::I2s,
776 state: &'static State,
758 buffers: MultiBuffering<S, NB, NS>, 777 buffers: MultiBuffering<S, NB, NS>,
778 _phantom: PhantomData<&'d ()>,
759} 779}
760 780
761impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> InputStream<'d, T, S, NB, NS> { 781impl<'d, S: Sample, const NB: usize, const NS: usize> InputStream<'d, S, NB, NS> {
762 /// Get a mutable reference to the current buffer. 782 /// Get a mutable reference to the current buffer.
763 pub fn buffer(&mut self) -> &mut [S] { 783 pub fn buffer(&mut self) -> &mut [S] {
764 self.buffers.get_mut() 784 self.buffers.get_mut()
@@ -769,10 +789,9 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> InputStream<'
769 where 789 where
770 S: Sample, 790 S: Sample,
771 { 791 {
772 let device = Device::<T>::new(); 792 let device = Device::new(self.r);
773 793
774 let s = T::state(); 794 if self.state.started.load(Ordering::Relaxed) {
775 if s.started.load(Ordering::Relaxed) {
776 self.stop().await; 795 self.stop().await;
777 } 796 }
778 797
@@ -781,11 +800,11 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> InputStream<'
781 800
782 device.update_rx(self.buffers.switch())?; 801 device.update_rx(self.buffers.switch())?;
783 802
784 s.started.store(true, Ordering::Relaxed); 803 self.state.started.store(true, Ordering::Relaxed);
785 804
786 device.start(); 805 device.start();
787 806
788 I2S::<T>::wait_rx_ptr_update().await; 807 I2S::wait_rx_ptr_update(self.r, self.state).await;
789 808
790 Ok(()) 809 Ok(())
791 } 810 }
@@ -793,7 +812,7 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> InputStream<'
793 /// Stops the I2S transfer and waits until it has stopped. 812 /// Stops the I2S transfer and waits until it has stopped.
794 #[inline(always)] 813 #[inline(always)]
795 pub async fn stop(&self) { 814 pub async fn stop(&self) {
796 I2S::<T>::stop().await 815 I2S::stop(self.r, self.state).await
797 } 816 }
798 817
799 /// Sets the current buffer for reception from the DMA. 818 /// Sets the current buffer for reception from the DMA.
@@ -803,18 +822,20 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> InputStream<'
803 where 822 where
804 S: Sample, 823 S: Sample,
805 { 824 {
806 I2S::<T>::receive_from_ram(self.buffers.switch_mut()).await 825 I2S::receive_from_ram(self.r, self.state, self.buffers.switch_mut()).await
807 } 826 }
808} 827}
809 828
810/// I2S full duplex stream (input & output) 829/// I2S full duplex stream (input & output)
811pub struct FullDuplexStream<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> { 830pub struct FullDuplexStream<'d, S: Sample, const NB: usize, const NS: usize> {
812 _p: Peri<'d, T>, 831 r: pac::i2s::I2s,
832 state: &'static State,
813 buffers_out: MultiBuffering<S, NB, NS>, 833 buffers_out: MultiBuffering<S, NB, NS>,
814 buffers_in: MultiBuffering<S, NB, NS>, 834 buffers_in: MultiBuffering<S, NB, NS>,
835 _phantom: PhantomData<&'d ()>,
815} 836}
816 837
817impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> FullDuplexStream<'d, T, S, NB, NS> { 838impl<'d, S: Sample, const NB: usize, const NS: usize> FullDuplexStream<'d, S, NB, NS> {
818 /// Get the current output and input buffers. 839 /// Get the current output and input buffers.
819 pub fn buffers(&mut self) -> (&mut [S], &[S]) { 840 pub fn buffers(&mut self) -> (&mut [S], &[S]) {
820 (self.buffers_out.get_mut(), self.buffers_in.get()) 841 (self.buffers_out.get_mut(), self.buffers_in.get())
@@ -825,10 +846,9 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> FullDuplexStr
825 where 846 where
826 S: Sample, 847 S: Sample,
827 { 848 {
828 let device = Device::<T>::new(); 849 let device = Device::new(self.r);
829 850
830 let s = T::state(); 851 if self.state.started.load(Ordering::Relaxed) {
831 if s.started.load(Ordering::Relaxed) {
832 self.stop().await; 852 self.stop().await;
833 } 853 }
834 854
@@ -839,12 +859,12 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> FullDuplexStr
839 device.update_tx(self.buffers_out.switch())?; 859 device.update_tx(self.buffers_out.switch())?;
840 device.update_rx(self.buffers_in.switch_mut())?; 860 device.update_rx(self.buffers_in.switch_mut())?;
841 861
842 s.started.store(true, Ordering::Relaxed); 862 self.state.started.store(true, Ordering::Relaxed);
843 863
844 device.start(); 864 device.start();
845 865
846 I2S::<T>::wait_tx_ptr_update().await; 866 I2S::wait_tx_ptr_update(self.r, self.state).await;
847 I2S::<T>::wait_rx_ptr_update().await; 867 I2S::wait_rx_ptr_update(self.r, self.state).await;
848 868
849 Ok(()) 869 Ok(())
850 } 870 }
@@ -852,7 +872,7 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> FullDuplexStr
852 /// Stops the I2S transfer and waits until it has stopped. 872 /// Stops the I2S transfer and waits until it has stopped.
853 #[inline(always)] 873 #[inline(always)]
854 pub async fn stop(&self) { 874 pub async fn stop(&self) {
855 I2S::<T>::stop().await 875 I2S::stop(self.r, self.state).await
856 } 876 }
857 877
858 /// Sets the current buffers for output and input for transmission/reception from the DMA. 878 /// Sets the current buffers for output and input for transmission/reception from the DMA.
@@ -861,18 +881,18 @@ impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> FullDuplexStr
861 where 881 where
862 S: Sample, 882 S: Sample,
863 { 883 {
864 I2S::<T>::send_from_ram(self.buffers_out.switch()).await?; 884 I2S::send_from_ram(self.r, self.state, self.buffers_out.switch()).await?;
865 I2S::<T>::receive_from_ram(self.buffers_in.switch_mut()).await?; 885 I2S::receive_from_ram(self.r, self.state, self.buffers_in.switch_mut()).await?;
866 Ok(()) 886 Ok(())
867 } 887 }
868} 888}
869 889
870/// Helper encapsulating common I2S device operations. 890/// Helper encapsulating common I2S device operations.
871struct Device<T>(pac::i2s::I2s, PhantomData<T>); 891struct Device(pac::i2s::I2s);
872 892
873impl<T: Instance> Device<T> { 893impl Device {
874 fn new() -> Self { 894 fn new(r: pac::i2s::I2s) -> Self {
875 Self(T::regs(), PhantomData) 895 Self(r)
876 } 896 }
877 897
878 #[inline(always)] 898 #[inline(always)]
diff --git a/embassy-nrf/src/ipc.rs b/embassy-nrf/src/ipc.rs
index a8a08c911..a40c36c99 100644
--- a/embassy-nrf/src/ipc.rs
+++ b/embassy-nrf/src/ipc.rs
@@ -134,97 +134,99 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
134 134
135/// IPC driver 135/// IPC driver
136#[non_exhaustive] 136#[non_exhaustive]
137pub struct Ipc<'d, T: Instance> { 137pub struct Ipc<'d> {
138 /// Event 0 138 /// Event 0
139 pub event0: Event<'d, T>, 139 pub event0: Event<'d>,
140 /// Event 1 140 /// Event 1
141 pub event1: Event<'d, T>, 141 pub event1: Event<'d>,
142 /// Event 2 142 /// Event 2
143 pub event2: Event<'d, T>, 143 pub event2: Event<'d>,
144 /// Event 3 144 /// Event 3
145 pub event3: Event<'d, T>, 145 pub event3: Event<'d>,
146 /// Event 4 146 /// Event 4
147 pub event4: Event<'d, T>, 147 pub event4: Event<'d>,
148 /// Event 5 148 /// Event 5
149 pub event5: Event<'d, T>, 149 pub event5: Event<'d>,
150 /// Event 6 150 /// Event 6
151 pub event6: Event<'d, T>, 151 pub event6: Event<'d>,
152 /// Event 7 152 /// Event 7
153 pub event7: Event<'d, T>, 153 pub event7: Event<'d>,
154 /// Event 8 154 /// Event 8
155 pub event8: Event<'d, T>, 155 pub event8: Event<'d>,
156 /// Event 9 156 /// Event 9
157 pub event9: Event<'d, T>, 157 pub event9: Event<'d>,
158 /// Event 10 158 /// Event 10
159 pub event10: Event<'d, T>, 159 pub event10: Event<'d>,
160 /// Event 11 160 /// Event 11
161 pub event11: Event<'d, T>, 161 pub event11: Event<'d>,
162 /// Event 12 162 /// Event 12
163 pub event12: Event<'d, T>, 163 pub event12: Event<'d>,
164 /// Event 13 164 /// Event 13
165 pub event13: Event<'d, T>, 165 pub event13: Event<'d>,
166 /// Event 14 166 /// Event 14
167 pub event14: Event<'d, T>, 167 pub event14: Event<'d>,
168 /// Event 15 168 /// Event 15
169 pub event15: Event<'d, T>, 169 pub event15: Event<'d>,
170} 170}
171 171
172impl<'d, T: Instance> Ipc<'d, T> { 172impl<'d> Ipc<'d> {
173 /// Create a new IPC driver. 173 /// Create a new IPC driver.
174 pub fn new( 174 pub fn new<T: Instance>(
175 _p: Peri<'d, T>, 175 _p: Peri<'d, T>,
176 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 176 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
177 ) -> Self { 177 ) -> Self {
178 T::Interrupt::unpend(); 178 T::Interrupt::unpend();
179 unsafe { T::Interrupt::enable() }; 179 unsafe { T::Interrupt::enable() };
180 180
181 let _phantom = PhantomData; 181 let r = T::regs();
182 let state = T::state();
182 #[rustfmt::skip] 183 #[rustfmt::skip]
183 let r = Self { // attributes on expressions are experimental 184 let result = Self { // attributes on expressions are experimental
184 event0: Event { number: EventNumber::Event0, _phantom }, 185 event0: Event { number: EventNumber::Event0, r, state, _phantom: PhantomData },
185 event1: Event { number: EventNumber::Event1, _phantom }, 186 event1: Event { number: EventNumber::Event1, r, state, _phantom: PhantomData },
186 event2: Event { number: EventNumber::Event2, _phantom }, 187 event2: Event { number: EventNumber::Event2, r, state, _phantom: PhantomData },
187 event3: Event { number: EventNumber::Event3, _phantom }, 188 event3: Event { number: EventNumber::Event3, r, state, _phantom: PhantomData },
188 event4: Event { number: EventNumber::Event4, _phantom }, 189 event4: Event { number: EventNumber::Event4, r, state, _phantom: PhantomData },
189 event5: Event { number: EventNumber::Event5, _phantom }, 190 event5: Event { number: EventNumber::Event5, r, state, _phantom: PhantomData },
190 event6: Event { number: EventNumber::Event6, _phantom }, 191 event6: Event { number: EventNumber::Event6, r, state, _phantom: PhantomData },
191 event7: Event { number: EventNumber::Event7, _phantom }, 192 event7: Event { number: EventNumber::Event7, r, state, _phantom: PhantomData },
192 event8: Event { number: EventNumber::Event8, _phantom }, 193 event8: Event { number: EventNumber::Event8, r, state, _phantom: PhantomData },
193 event9: Event { number: EventNumber::Event9, _phantom }, 194 event9: Event { number: EventNumber::Event9, r, state, _phantom: PhantomData },
194 event10: Event { number: EventNumber::Event10, _phantom }, 195 event10: Event { number: EventNumber::Event10, r, state, _phantom: PhantomData },
195 event11: Event { number: EventNumber::Event11, _phantom }, 196 event11: Event { number: EventNumber::Event11, r, state, _phantom: PhantomData },
196 event12: Event { number: EventNumber::Event12, _phantom }, 197 event12: Event { number: EventNumber::Event12, r, state, _phantom: PhantomData },
197 event13: Event { number: EventNumber::Event13, _phantom }, 198 event13: Event { number: EventNumber::Event13, r, state, _phantom: PhantomData },
198 event14: Event { number: EventNumber::Event14, _phantom }, 199 event14: Event { number: EventNumber::Event14, r, state, _phantom: PhantomData },
199 event15: Event { number: EventNumber::Event15, _phantom }, 200 event15: Event { number: EventNumber::Event15, r, state, _phantom: PhantomData },
200 }; 201 };
201 r 202 result
202 } 203 }
203} 204}
204 205
205/// IPC event 206/// IPC event
206pub struct Event<'d, T: Instance> { 207pub struct Event<'d> {
207 number: EventNumber, 208 number: EventNumber,
208 _phantom: PhantomData<&'d T>, 209 r: pac::ipc::Ipc,
210 state: &'static State,
211 _phantom: PhantomData<&'d ()>,
209} 212}
210 213
211impl<'d, T: Instance> Event<'d, T> { 214impl<'d> Event<'d> {
212 /// Trigger the event. 215 /// Trigger the event.
213 pub fn trigger(&self) { 216 pub fn trigger(&self) {
214 let nr = self.number; 217 let nr = self.number;
215 T::regs().tasks_send(nr as usize).write_value(1); 218 self.r.tasks_send(nr as usize).write_value(1);
216 } 219 }
217 220
218 /// Wait for the event to be triggered. 221 /// Wait for the event to be triggered.
219 pub async fn wait(&mut self) { 222 pub async fn wait(&mut self) {
220 let regs = T::regs();
221 let nr = self.number as usize; 223 let nr = self.number as usize;
222 regs.intenset().write(|w| w.0 = 1 << nr); 224 self.r.intenset().write(|w| w.0 = 1 << nr);
223 poll_fn(|cx| { 225 poll_fn(|cx| {
224 T::state().wakers[nr].register(cx.waker()); 226 self.state.wakers[nr].register(cx.waker());
225 227
226 if regs.events_receive(nr).read() == 1 { 228 if self.r.events_receive(nr).read() == 1 {
227 regs.events_receive(nr).write_value(0x00); 229 self.r.events_receive(nr).write_value(0x00);
228 Poll::Ready(()) 230 Poll::Ready(())
229 } else { 231 } else {
230 Poll::Pending 232 Poll::Pending
@@ -239,16 +241,17 @@ impl<'d, T: Instance> Event<'d, T> {
239 } 241 }
240 242
241 /// Create a handle that can trigger the event. 243 /// Create a handle that can trigger the event.
242 pub fn trigger_handle(&self) -> EventTrigger<'d, T> { 244 pub fn trigger_handle(&self) -> EventTrigger<'d> {
243 EventTrigger { 245 EventTrigger {
244 number: self.number, 246 number: self.number,
247 r: self.r,
245 _phantom: PhantomData, 248 _phantom: PhantomData,
246 } 249 }
247 } 250 }
248 251
249 /// Configure the channels the event will broadcast to 252 /// Configure the channels the event will broadcast to
250 pub fn configure_trigger<I: IntoIterator<Item = IpcChannel>>(&mut self, channels: I) { 253 pub fn configure_trigger<I: IntoIterator<Item = IpcChannel>>(&mut self, channels: I) {
251 T::regs().send_cnf(self.number as usize).write(|w| { 254 self.r.send_cnf(self.number as usize).write(|w| {
252 for channel in channels { 255 for channel in channels {
253 w.0 |= channel.mask(); 256 w.0 |= channel.mask();
254 } 257 }
@@ -257,7 +260,7 @@ impl<'d, T: Instance> Event<'d, T> {
257 260
258 /// Configure the channels the event will listen on 261 /// Configure the channels the event will listen on
259 pub fn configure_wait<I: IntoIterator<Item = IpcChannel>>(&mut self, channels: I) { 262 pub fn configure_wait<I: IntoIterator<Item = IpcChannel>>(&mut self, channels: I) {
260 T::regs().receive_cnf(self.number as usize).write(|w| { 263 self.r.receive_cnf(self.number as usize).write(|w| {
261 for channel in channels { 264 for channel in channels {
262 w.0 |= channel.mask(); 265 w.0 |= channel.mask();
263 } 266 }
@@ -267,22 +270,25 @@ impl<'d, T: Instance> Event<'d, T> {
267 /// Get the task for the IPC event to use with PPI. 270 /// Get the task for the IPC event to use with PPI.
268 pub fn task(&self) -> ppi::Task<'d> { 271 pub fn task(&self) -> ppi::Task<'d> {
269 let nr = self.number as usize; 272 let nr = self.number as usize;
270 let regs = T::regs(); 273 ppi::Task::from_reg(self.r.tasks_send(nr))
271 ppi::Task::from_reg(regs.tasks_send(nr))
272 } 274 }
273 275
274 /// Get the event for the IPC event to use with PPI. 276 /// Get the event for the IPC event to use with PPI.
275 pub fn event(&self) -> ppi::Event<'d> { 277 pub fn event(&self) -> ppi::Event<'d> {
276 let nr = self.number as usize; 278 let nr = self.number as usize;
277 let regs = T::regs(); 279 ppi::Event::from_reg(self.r.events_receive(nr))
278 ppi::Event::from_reg(regs.events_receive(nr))
279 } 280 }
280 281
281 /// Reborrow into a "child" Event. 282 /// Reborrow into a "child" Event.
282 /// 283 ///
283 /// `self` will stay borrowed until the child Event is dropped. 284 /// `self` will stay borrowed until the child Event is dropped.
284 pub fn reborrow(&mut self) -> Event<'_, T> { 285 pub fn reborrow(&mut self) -> Event<'_> {
285 Self { ..*self } 286 Event {
287 number: self.number,
288 r: self.r,
289 state: self.state,
290 _phantom: PhantomData,
291 }
286 } 292 }
287 293
288 /// Steal an IPC event by number. 294 /// Steal an IPC event by number.
@@ -290,9 +296,11 @@ impl<'d, T: Instance> Event<'d, T> {
290 /// # Safety 296 /// # Safety
291 /// 297 ///
292 /// The event number must not be in use by another [`Event`]. 298 /// The event number must not be in use by another [`Event`].
293 pub unsafe fn steal(number: EventNumber) -> Self { 299 pub unsafe fn steal<T: Instance>(number: EventNumber) -> Self {
294 Self { 300 Self {
295 number, 301 number,
302 r: T::regs(),
303 state: T::state(),
296 _phantom: PhantomData, 304 _phantom: PhantomData,
297 } 305 }
298 } 306 }
@@ -301,17 +309,17 @@ impl<'d, T: Instance> Event<'d, T> {
301/// A handle that can trigger an IPC event. 309/// A handle that can trigger an IPC event.
302/// 310///
303/// This `struct` is returned by [`Event::trigger_handle`]. 311/// This `struct` is returned by [`Event::trigger_handle`].
304#[derive(Debug, Copy, Clone)] 312pub struct EventTrigger<'d> {
305pub struct EventTrigger<'d, T: Instance> {
306 number: EventNumber, 313 number: EventNumber,
307 _phantom: PhantomData<&'d T>, 314 r: pac::ipc::Ipc,
315 _phantom: PhantomData<&'d ()>,
308} 316}
309 317
310impl<T: Instance> EventTrigger<'_, T> { 318impl EventTrigger<'_> {
311 /// Trigger the event. 319 /// Trigger the event.
312 pub fn trigger(&self) { 320 pub fn trigger(&self) {
313 let nr = self.number; 321 let nr = self.number;
314 T::regs().tasks_send(nr as usize).write_value(1); 322 self.r.tasks_send(nr as usize).write_value(1);
315 } 323 }
316 324
317 /// Returns the [`EventNumber`] of the event. 325 /// Returns the [`EventNumber`] of the event.
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index 897e660b8..7c26a6184 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -155,6 +155,8 @@ pub mod reset;
155#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))] 155#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))]
156pub mod rng; 156pub mod rng;
157#[cfg(not(feature = "_nrf54l"))] // TODO 157#[cfg(not(feature = "_nrf54l"))] // TODO
158pub mod rtc;
159#[cfg(not(feature = "_nrf54l"))] // TODO
158#[cfg(not(any(feature = "_nrf51", feature = "nrf52820", feature = "_nrf5340-net")))] 160#[cfg(not(any(feature = "_nrf51", feature = "nrf52820", feature = "_nrf5340-net")))]
159pub mod saadc; 161pub mod saadc;
160#[cfg(not(feature = "_nrf54l"))] // TODO 162#[cfg(not(feature = "_nrf54l"))] // TODO
@@ -205,7 +207,7 @@ mod chip;
205/// Macro to bind interrupts to handlers. 207/// Macro to bind interrupts to handlers.
206/// 208///
207/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`) 209/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
208/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to 210/// and implements the right [crate::interrupt::typelevel::Binding]s for it. You can pass this struct to drivers to
209/// prove at compile-time that the right interrupts have been bound. 211/// prove at compile-time that the right interrupts have been bound.
210/// 212///
211/// Example of how to bind one interrupt: 213/// Example of how to bind one interrupt:
diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs
index c2a4ba65f..b6ee52850 100644
--- a/embassy-nrf/src/pdm.rs
+++ b/embassy-nrf/src/pdm.rs
@@ -53,8 +53,10 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
53} 53}
54 54
55/// PDM microphone interface 55/// PDM microphone interface
56pub struct Pdm<'d, T: Instance> { 56pub struct Pdm<'d> {
57 _peri: Peri<'d, T>, 57 r: pac::pdm::Pdm,
58 state: &'static State,
59 _phantom: PhantomData<&'d ()>,
58} 60}
59 61
60/// PDM error 62/// PDM error
@@ -86,9 +88,9 @@ pub enum SamplerState {
86 Stopped, 88 Stopped,
87} 89}
88 90
89impl<'d, T: Instance> Pdm<'d, T> { 91impl<'d> Pdm<'d> {
90 /// Create PDM driver 92 /// Create PDM driver
91 pub fn new( 93 pub fn new<T: Instance>(
92 pdm: Peri<'d, T>, 94 pdm: Peri<'d, T>,
93 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 95 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
94 clk: Peri<'d, impl GpioPin>, 96 clk: Peri<'d, impl GpioPin>,
@@ -98,7 +100,7 @@ impl<'d, T: Instance> Pdm<'d, T> {
98 Self::new_inner(pdm, clk.into(), din.into(), config) 100 Self::new_inner(pdm, clk.into(), din.into(), config)
99 } 101 }
100 102
101 fn new_inner(pdm: Peri<'d, T>, clk: Peri<'d, AnyPin>, din: Peri<'d, AnyPin>, config: Config) -> Self { 103 fn new_inner<T: Instance>(_pdm: Peri<'d, T>, clk: Peri<'d, AnyPin>, din: Peri<'d, AnyPin>, config: Config) -> Self {
102 let r = T::regs(); 104 let r = T::regs();
103 105
104 // setup gpio pins 106 // setup gpio pins
@@ -133,7 +135,11 @@ impl<'d, T: Instance> Pdm<'d, T> {
133 135
134 r.enable().write(|w| w.set_enable(true)); 136 r.enable().write(|w| w.set_enable(true));
135 137
136 Self { _peri: pdm } 138 Self {
139 r: T::regs(),
140 state: T::state(),
141 _phantom: PhantomData,
142 }
137 } 143 }
138 144
139 fn _set_gain(r: pac::pdm::Pdm, gain_left: I7F1, gain_right: I7F1) { 145 fn _set_gain(r: pac::pdm::Pdm, gain_left: I7F1, gain_right: I7F1) {
@@ -147,26 +153,26 @@ impl<'d, T: Instance> Pdm<'d, T> {
147 153
148 /// Adjust the gain of the PDM microphone on the fly 154 /// Adjust the gain of the PDM microphone on the fly
149 pub fn set_gain(&mut self, gain_left: I7F1, gain_right: I7F1) { 155 pub fn set_gain(&mut self, gain_left: I7F1, gain_right: I7F1) {
150 Self::_set_gain(T::regs(), gain_left, gain_right) 156 Self::_set_gain(self.r, gain_left, gain_right)
151 } 157 }
152 158
153 /// Start sampling microphone data into a dummy buffer. 159 /// Start sampling microphone data into a dummy buffer.
154 /// Useful to start the microphone and keep it active between recording samples. 160 /// Useful to start the microphone and keep it active between recording samples.
155 pub async fn start(&mut self) { 161 pub async fn start(&mut self) {
156 let r = T::regs();
157
158 // start dummy sampling because microphone needs some setup time 162 // start dummy sampling because microphone needs some setup time
159 r.sample().ptr().write_value(DUMMY_BUFFER.as_ptr() as u32); 163 self.r.sample().ptr().write_value(DUMMY_BUFFER.as_ptr() as u32);
160 r.sample().maxcnt().write(|w| w.set_buffsize(DUMMY_BUFFER.len() as _)); 164 self.r
165 .sample()
166 .maxcnt()
167 .write(|w| w.set_buffsize(DUMMY_BUFFER.len() as _));
161 168
162 r.tasks_start().write_value(1); 169 self.r.tasks_start().write_value(1);
163 } 170 }
164 171
165 /// Stop sampling microphone data inta a dummy buffer 172 /// Stop sampling microphone data inta a dummy buffer
166 pub async fn stop(&mut self) { 173 pub async fn stop(&mut self) {
167 let r = T::regs(); 174 self.r.tasks_stop().write_value(1);
168 r.tasks_stop().write_value(1); 175 self.r.events_started().write_value(0);
169 r.events_started().write_value(0);
170 } 176 }
171 177
172 /// Sample data into the given buffer 178 /// Sample data into the given buffer
@@ -178,12 +184,11 @@ impl<'d, T: Instance> Pdm<'d, T> {
178 return Err(Error::BufferTooLong); 184 return Err(Error::BufferTooLong);
179 } 185 }
180 186
181 let r = T::regs(); 187 if self.r.events_started().read() == 0 {
182
183 if r.events_started().read() == 0 {
184 return Err(Error::NotRunning); 188 return Err(Error::NotRunning);
185 } 189 }
186 190
191 let r = self.r;
187 let drop = OnDrop::new(move || { 192 let drop = OnDrop::new(move || {
188 r.intenclr().write(|w| w.set_end(true)); 193 r.intenclr().write(|w| w.set_end(true));
189 r.events_stopped().write_value(0); 194 r.events_stopped().write_value(0);
@@ -198,34 +203,37 @@ impl<'d, T: Instance> Pdm<'d, T> {
198 // setup user buffer 203 // setup user buffer
199 let ptr = buffer.as_ptr(); 204 let ptr = buffer.as_ptr();
200 let len = buffer.len(); 205 let len = buffer.len();
201 r.sample().ptr().write_value(ptr as u32); 206 self.r.sample().ptr().write_value(ptr as u32);
202 r.sample().maxcnt().write(|w| w.set_buffsize(len as _)); 207 self.r.sample().maxcnt().write(|w| w.set_buffsize(len as _));
203 208
204 // wait till the current sample is finished and the user buffer sample is started 209 // wait till the current sample is finished and the user buffer sample is started
205 Self::wait_for_sample().await; 210 self.wait_for_sample().await;
206 211
207 // reset the buffer back to the dummy buffer 212 // reset the buffer back to the dummy buffer
208 r.sample().ptr().write_value(DUMMY_BUFFER.as_ptr() as u32); 213 self.r.sample().ptr().write_value(DUMMY_BUFFER.as_ptr() as u32);
209 r.sample().maxcnt().write(|w| w.set_buffsize(DUMMY_BUFFER.len() as _)); 214 self.r
215 .sample()
216 .maxcnt()
217 .write(|w| w.set_buffsize(DUMMY_BUFFER.len() as _));
210 218
211 // wait till the user buffer is sampled 219 // wait till the user buffer is sampled
212 Self::wait_for_sample().await; 220 self.wait_for_sample().await;
213 221
214 drop.defuse(); 222 drop.defuse();
215 223
216 Ok(()) 224 Ok(())
217 } 225 }
218 226
219 async fn wait_for_sample() { 227 async fn wait_for_sample(&mut self) {
220 let r = T::regs(); 228 self.r.events_end().write_value(0);
221 229 self.r.intenset().write(|w| w.set_end(true));
222 r.events_end().write_value(0);
223 r.intenset().write(|w| w.set_end(true));
224 230
225 compiler_fence(Ordering::SeqCst); 231 compiler_fence(Ordering::SeqCst);
226 232
233 let state = self.state;
234 let r = self.r;
227 poll_fn(|cx| { 235 poll_fn(|cx| {
228 T::state().waker.register(cx.waker()); 236 state.waker.register(cx.waker());
229 if r.events_end().read() != 0 { 237 if r.events_end().read() != 0 {
230 return Poll::Ready(()); 238 return Poll::Ready(());
231 } 239 }
@@ -255,20 +263,18 @@ impl<'d, T: Instance> Pdm<'d, T> {
255 where 263 where
256 S: FnMut(&[i16; N]) -> SamplerState, 264 S: FnMut(&[i16; N]) -> SamplerState,
257 { 265 {
258 let r = T::regs(); 266 if self.r.events_started().read() != 0 {
259
260 if r.events_started().read() != 0 {
261 return Err(Error::AlreadyRunning); 267 return Err(Error::AlreadyRunning);
262 } 268 }
263 269
264 r.sample().ptr().write_value(bufs[0].as_mut_ptr() as u32); 270 self.r.sample().ptr().write_value(bufs[0].as_mut_ptr() as u32);
265 r.sample().maxcnt().write(|w| w.set_buffsize(N as _)); 271 self.r.sample().maxcnt().write(|w| w.set_buffsize(N as _));
266 272
267 // Reset and enable the events 273 // Reset and enable the events
268 r.events_end().write_value(0); 274 self.r.events_end().write_value(0);
269 r.events_started().write_value(0); 275 self.r.events_started().write_value(0);
270 r.events_stopped().write_value(0); 276 self.r.events_stopped().write_value(0);
271 r.intenset().write(|w| { 277 self.r.intenset().write(|w| {
272 w.set_end(true); 278 w.set_end(true);
273 w.set_started(true); 279 w.set_started(true);
274 w.set_stopped(true); 280 w.set_stopped(true);
@@ -278,23 +284,24 @@ impl<'d, T: Instance> Pdm<'d, T> {
278 // wouldn't happen anyway 284 // wouldn't happen anyway
279 compiler_fence(Ordering::SeqCst); 285 compiler_fence(Ordering::SeqCst);
280 286
281 r.tasks_start().write_value(1); 287 self.r.tasks_start().write_value(1);
282 288
283 let mut current_buffer = 0; 289 let mut current_buffer = 0;
284 290
285 let mut done = false; 291 let mut done = false;
286 292
287 let drop = OnDrop::new(|| { 293 let r = self.r;
294 let drop = OnDrop::new(move || {
288 r.tasks_stop().write_value(1); 295 r.tasks_stop().write_value(1);
289 // N.B. It would be better if this were async, but Drop only support sync code 296 // N.B. It would be better if this were async, but Drop only support sync code
290 while r.events_stopped().read() != 0 {} 297 while r.events_stopped().read() != 0 {}
291 }); 298 });
292 299
300 let state = self.state;
301 let r = self.r;
293 // Wait for events and complete when the sampler indicates it has had enough 302 // Wait for events and complete when the sampler indicates it has had enough
294 poll_fn(|cx| { 303 poll_fn(|cx| {
295 let r = T::regs(); 304 state.waker.register(cx.waker());
296
297 T::state().waker.register(cx.waker());
298 305
299 if r.events_end().read() != 0 { 306 if r.events_end().read() != 0 {
300 compiler_fence(Ordering::SeqCst); 307 compiler_fence(Ordering::SeqCst);
@@ -411,16 +418,14 @@ impl From<Edge> for vals::Edge {
411 } 418 }
412} 419}
413 420
414impl<'d, T: Instance> Drop for Pdm<'d, T> { 421impl<'d> Drop for Pdm<'d> {
415 fn drop(&mut self) { 422 fn drop(&mut self) {
416 let r = T::regs(); 423 self.r.tasks_stop().write_value(1);
417
418 r.tasks_stop().write_value(1);
419 424
420 r.enable().write(|w| w.set_enable(false)); 425 self.r.enable().write(|w| w.set_enable(false));
421 426
422 r.psel().din().write_value(DISCONNECTED); 427 self.r.psel().din().write_value(DISCONNECTED);
423 r.psel().clk().write_value(DISCONNECTED); 428 self.r.psel().clk().write_value(DISCONNECTED);
424 } 429 }
425} 430}
426 431
diff --git a/embassy-nrf/src/ppi/dppi.rs b/embassy-nrf/src/ppi/dppi.rs
index 686f66987..078d2fd1c 100644
--- a/embassy-nrf/src/ppi/dppi.rs
+++ b/embassy-nrf/src/ppi/dppi.rs
@@ -59,6 +59,15 @@ impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Ppi<'d,
59 } 59 }
60} 60}
61 61
62impl<C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Ppi<'static, C, EVENT_COUNT, TASK_COUNT> {
63 /// Persist the channel's configuration for the rest of the program's lifetime. This method
64 /// should be preferred over [`core::mem::forget()`] because the `'static` bound prevents
65 /// accidental reuse of the underlying peripheral.
66 pub fn persist(self) {
67 core::mem::forget(self);
68 }
69}
70
62impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Drop for Ppi<'d, C, EVENT_COUNT, TASK_COUNT> { 71impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Drop for Ppi<'d, C, EVENT_COUNT, TASK_COUNT> {
63 fn drop(&mut self) { 72 fn drop(&mut self) {
64 self.disable(); 73 self.disable();
diff --git a/embassy-nrf/src/ppi/mod.rs b/embassy-nrf/src/ppi/mod.rs
index 531777205..2bcf72e9c 100644
--- a/embassy-nrf/src/ppi/mod.rs
+++ b/embassy-nrf/src/ppi/mod.rs
@@ -108,6 +108,14 @@ impl<'d, G: Group> PpiGroup<'d, G> {
108 Task::from_reg(regs().tasks_chg(n).dis()) 108 Task::from_reg(regs().tasks_chg(n).dis())
109 } 109 }
110} 110}
111impl<G: Group> PpiGroup<'static, G> {
112 /// Persist this group's configuration for the rest of the program's lifetime. This method
113 /// should be preferred over [`core::mem::forget()`] because the `'static` bound prevents
114 /// accidental reuse of the underlying peripheral.
115 pub fn persist(self) {
116 core::mem::forget(self);
117 }
118}
111 119
112impl<'d, G: Group> Drop for PpiGroup<'d, G> { 120impl<'d, G: Group> Drop for PpiGroup<'d, G> {
113 fn drop(&mut self) { 121 fn drop(&mut self) {
diff --git a/embassy-nrf/src/ppi/ppi.rs b/embassy-nrf/src/ppi/ppi.rs
index e04dacbc0..531c25444 100644
--- a/embassy-nrf/src/ppi/ppi.rs
+++ b/embassy-nrf/src/ppi/ppi.rs
@@ -68,6 +68,15 @@ impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Ppi<'d,
68 } 68 }
69} 69}
70 70
71impl<C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Ppi<'static, C, EVENT_COUNT, TASK_COUNT> {
72 /// Persist the channel's configuration for the rest of the program's lifetime. This method
73 /// should be preferred over [`core::mem::forget()`] because the `'static` bound prevents
74 /// accidental reuse of the underlying peripheral.
75 pub fn persist(self) {
76 core::mem::forget(self);
77 }
78}
79
71impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Drop for Ppi<'d, C, EVENT_COUNT, TASK_COUNT> { 80impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Drop for Ppi<'d, C, EVENT_COUNT, TASK_COUNT> {
72 fn drop(&mut self) { 81 fn drop(&mut self) {
73 self.disable(); 82 self.disable();
diff --git a/embassy-nrf/src/pwm.rs b/embassy-nrf/src/pwm.rs
index d6b40b5c0..d67cb546b 100644
--- a/embassy-nrf/src/pwm.rs
+++ b/embassy-nrf/src/pwm.rs
@@ -15,8 +15,8 @@ use crate::{interrupt, pac};
15 15
16/// SimplePwm is the traditional pwm interface you're probably used to, allowing 16/// SimplePwm is the traditional pwm interface you're probably used to, allowing
17/// to simply set a duty cycle across up to four channels. 17/// to simply set a duty cycle across up to four channels.
18pub struct SimplePwm<'d, T: Instance> { 18pub struct SimplePwm<'d> {
19 _peri: Peri<'d, T>, 19 r: pac::pwm::Pwm,
20 duty: [u16; 4], 20 duty: [u16; 4],
21 ch0: Option<Peri<'d, AnyPin>>, 21 ch0: Option<Peri<'d, AnyPin>>,
22 ch1: Option<Peri<'d, AnyPin>>, 22 ch1: Option<Peri<'d, AnyPin>>,
@@ -26,8 +26,8 @@ pub struct SimplePwm<'d, T: Instance> {
26 26
27/// SequencePwm allows you to offload the updating of a sequence of duty cycles 27/// SequencePwm allows you to offload the updating of a sequence of duty cycles
28/// to up to four channels, as well as repeat that sequence n times. 28/// to up to four channels, as well as repeat that sequence n times.
29pub struct SequencePwm<'d, T: Instance> { 29pub struct SequencePwm<'d> {
30 _peri: Peri<'d, T>, 30 r: pac::pwm::Pwm,
31 ch0: Option<Peri<'d, AnyPin>>, 31 ch0: Option<Peri<'d, AnyPin>>,
32 ch1: Option<Peri<'d, AnyPin>>, 32 ch1: Option<Peri<'d, AnyPin>>,
33 ch2: Option<Peri<'d, AnyPin>>, 33 ch2: Option<Peri<'d, AnyPin>>,
@@ -51,16 +51,16 @@ const MAX_SEQUENCE_LEN: usize = 32767;
51/// The used pwm clock frequency 51/// The used pwm clock frequency
52pub const PWM_CLK_HZ: u32 = 16_000_000; 52pub const PWM_CLK_HZ: u32 = 16_000_000;
53 53
54impl<'d, T: Instance> SequencePwm<'d, T> { 54impl<'d> SequencePwm<'d> {
55 /// Create a new 1-channel PWM 55 /// Create a new 1-channel PWM
56 #[allow(unused_unsafe)] 56 #[allow(unused_unsafe)]
57 pub fn new_1ch(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, config: Config) -> Result<Self, Error> { 57 pub fn new_1ch<T: Instance>(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, config: Config) -> Result<Self, Error> {
58 Self::new_inner(pwm, Some(ch0.into()), None, None, None, config) 58 Self::new_inner(pwm, Some(ch0.into()), None, None, None, config)
59 } 59 }
60 60
61 /// Create a new 2-channel PWM 61 /// Create a new 2-channel PWM
62 #[allow(unused_unsafe)] 62 #[allow(unused_unsafe)]
63 pub fn new_2ch( 63 pub fn new_2ch<T: Instance>(
64 pwm: Peri<'d, T>, 64 pwm: Peri<'d, T>,
65 ch0: Peri<'d, impl GpioPin>, 65 ch0: Peri<'d, impl GpioPin>,
66 ch1: Peri<'d, impl GpioPin>, 66 ch1: Peri<'d, impl GpioPin>,
@@ -71,7 +71,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
71 71
72 /// Create a new 3-channel PWM 72 /// Create a new 3-channel PWM
73 #[allow(unused_unsafe)] 73 #[allow(unused_unsafe)]
74 pub fn new_3ch( 74 pub fn new_3ch<T: Instance>(
75 pwm: Peri<'d, T>, 75 pwm: Peri<'d, T>,
76 ch0: Peri<'d, impl GpioPin>, 76 ch0: Peri<'d, impl GpioPin>,
77 ch1: Peri<'d, impl GpioPin>, 77 ch1: Peri<'d, impl GpioPin>,
@@ -83,7 +83,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
83 83
84 /// Create a new 4-channel PWM 84 /// Create a new 4-channel PWM
85 #[allow(unused_unsafe)] 85 #[allow(unused_unsafe)]
86 pub fn new_4ch( 86 pub fn new_4ch<T: Instance>(
87 pwm: Peri<'d, T>, 87 pwm: Peri<'d, T>,
88 ch0: Peri<'d, impl GpioPin>, 88 ch0: Peri<'d, impl GpioPin>,
89 ch1: Peri<'d, impl GpioPin>, 89 ch1: Peri<'d, impl GpioPin>,
@@ -101,7 +101,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
101 ) 101 )
102 } 102 }
103 103
104 fn new_inner( 104 fn new_inner<T: Instance>(
105 _pwm: Peri<'d, T>, 105 _pwm: Peri<'d, T>,
106 ch0: Option<Peri<'d, AnyPin>>, 106 ch0: Option<Peri<'d, AnyPin>>,
107 ch1: Option<Peri<'d, AnyPin>>, 107 ch1: Option<Peri<'d, AnyPin>>,
@@ -174,7 +174,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
174 r.countertop().write(|w| w.set_countertop(config.max_duty)); 174 r.countertop().write(|w| w.set_countertop(config.max_duty));
175 175
176 Ok(Self { 176 Ok(Self {
177 _peri: _pwm, 177 r: T::regs(),
178 ch0, 178 ch0,
179 ch1, 179 ch1,
180 ch2, 180 ch2,
@@ -185,57 +185,43 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
185 /// Returns reference to `Stopped` event endpoint for PPI. 185 /// Returns reference to `Stopped` event endpoint for PPI.
186 #[inline(always)] 186 #[inline(always)]
187 pub fn event_stopped(&self) -> Event<'d> { 187 pub fn event_stopped(&self) -> Event<'d> {
188 let r = T::regs(); 188 Event::from_reg(self.r.events_stopped())
189
190 Event::from_reg(r.events_stopped())
191 } 189 }
192 190
193 /// Returns reference to `LoopsDone` event endpoint for PPI. 191 /// Returns reference to `LoopsDone` event endpoint for PPI.
194 #[inline(always)] 192 #[inline(always)]
195 pub fn event_loops_done(&self) -> Event<'d> { 193 pub fn event_loops_done(&self) -> Event<'d> {
196 let r = T::regs(); 194 Event::from_reg(self.r.events_loopsdone())
197
198 Event::from_reg(r.events_loopsdone())
199 } 195 }
200 196
201 /// Returns reference to `PwmPeriodEnd` event endpoint for PPI. 197 /// Returns reference to `PwmPeriodEnd` event endpoint for PPI.
202 #[inline(always)] 198 #[inline(always)]
203 pub fn event_pwm_period_end(&self) -> Event<'d> { 199 pub fn event_pwm_period_end(&self) -> Event<'d> {
204 let r = T::regs(); 200 Event::from_reg(self.r.events_pwmperiodend())
205
206 Event::from_reg(r.events_pwmperiodend())
207 } 201 }
208 202
209 /// Returns reference to `Seq0 End` event endpoint for PPI. 203 /// Returns reference to `Seq0 End` event endpoint for PPI.
210 #[inline(always)] 204 #[inline(always)]
211 pub fn event_seq_end(&self) -> Event<'d> { 205 pub fn event_seq_end(&self) -> Event<'d> {
212 let r = T::regs(); 206 Event::from_reg(self.r.events_seqend(0))
213
214 Event::from_reg(r.events_seqend(0))
215 } 207 }
216 208
217 /// Returns reference to `Seq1 End` event endpoint for PPI. 209 /// Returns reference to `Seq1 End` event endpoint for PPI.
218 #[inline(always)] 210 #[inline(always)]
219 pub fn event_seq1_end(&self) -> Event<'d> { 211 pub fn event_seq1_end(&self) -> Event<'d> {
220 let r = T::regs(); 212 Event::from_reg(self.r.events_seqend(1))
221
222 Event::from_reg(r.events_seqend(1))
223 } 213 }
224 214
225 /// Returns reference to `Seq0 Started` event endpoint for PPI. 215 /// Returns reference to `Seq0 Started` event endpoint for PPI.
226 #[inline(always)] 216 #[inline(always)]
227 pub fn event_seq0_started(&self) -> Event<'d> { 217 pub fn event_seq0_started(&self) -> Event<'d> {
228 let r = T::regs(); 218 Event::from_reg(self.r.events_seqstarted(0))
229
230 Event::from_reg(r.events_seqstarted(0))
231 } 219 }
232 220
233 /// Returns reference to `Seq1 Started` event endpoint for PPI. 221 /// Returns reference to `Seq1 Started` event endpoint for PPI.
234 #[inline(always)] 222 #[inline(always)]
235 pub fn event_seq1_started(&self) -> Event<'d> { 223 pub fn event_seq1_started(&self) -> Event<'d> {
236 let r = T::regs(); 224 Event::from_reg(self.r.events_seqstarted(1))
237
238 Event::from_reg(r.events_seqstarted(1))
239 } 225 }
240 226
241 /// Returns reference to `Seq0 Start` task endpoint for PPI. 227 /// Returns reference to `Seq0 Start` task endpoint for PPI.
@@ -244,9 +230,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
244 /// Interacting with the sequence while it runs puts it in an unknown state 230 /// Interacting with the sequence while it runs puts it in an unknown state
245 #[inline(always)] 231 #[inline(always)]
246 pub unsafe fn task_start_seq0(&self) -> Task<'d> { 232 pub unsafe fn task_start_seq0(&self) -> Task<'d> {
247 let r = T::regs(); 233 Task::from_reg(self.r.tasks_seqstart(0))
248
249 Task::from_reg(r.tasks_seqstart(0))
250 } 234 }
251 235
252 /// Returns reference to `Seq1 Started` task endpoint for PPI. 236 /// Returns reference to `Seq1 Started` task endpoint for PPI.
@@ -255,9 +239,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
255 /// Interacting with the sequence while it runs puts it in an unknown state 239 /// Interacting with the sequence while it runs puts it in an unknown state
256 #[inline(always)] 240 #[inline(always)]
257 pub unsafe fn task_start_seq1(&self) -> Task<'d> { 241 pub unsafe fn task_start_seq1(&self) -> Task<'d> {
258 let r = T::regs(); 242 Task::from_reg(self.r.tasks_seqstart(1))
259
260 Task::from_reg(r.tasks_seqstart(1))
261 } 243 }
262 244
263 /// Returns reference to `NextStep` task endpoint for PPI. 245 /// Returns reference to `NextStep` task endpoint for PPI.
@@ -266,9 +248,7 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
266 /// Interacting with the sequence while it runs puts it in an unknown state 248 /// Interacting with the sequence while it runs puts it in an unknown state
267 #[inline(always)] 249 #[inline(always)]
268 pub unsafe fn task_next_step(&self) -> Task<'d> { 250 pub unsafe fn task_next_step(&self) -> Task<'d> {
269 let r = T::regs(); 251 Task::from_reg(self.r.tasks_nextstep())
270
271 Task::from_reg(r.tasks_nextstep())
272 } 252 }
273 253
274 /// Returns reference to `Stop` task endpoint for PPI. 254 /// Returns reference to `Stop` task endpoint for PPI.
@@ -277,36 +257,34 @@ impl<'d, T: Instance> SequencePwm<'d, T> {
277 /// Interacting with the sequence while it runs puts it in an unknown state 257 /// Interacting with the sequence while it runs puts it in an unknown state
278 #[inline(always)] 258 #[inline(always)]
279 pub unsafe fn task_stop(&self) -> Task<'d> { 259 pub unsafe fn task_stop(&self) -> Task<'d> {
280 let r = T::regs(); 260 Task::from_reg(self.r.tasks_stop())
281
282 Task::from_reg(r.tasks_stop())
283 } 261 }
284} 262}
285 263
286impl<'a, T: Instance> Drop for SequencePwm<'a, T> { 264impl<'a> Drop for SequencePwm<'a> {
287 fn drop(&mut self) { 265 fn drop(&mut self) {
288 let r = T::regs();
289
290 if let Some(pin) = &self.ch0 { 266 if let Some(pin) = &self.ch0 {
291 pin.set_low(); 267 pin.set_low();
292 pin.conf().write(|_| ()); 268 pin.conf().write(|_| ());
293 r.psel().out(0).write_value(DISCONNECTED); 269 self.r.psel().out(0).write_value(DISCONNECTED);
294 } 270 }
295 if let Some(pin) = &self.ch1 { 271 if let Some(pin) = &self.ch1 {
296 pin.set_low(); 272 pin.set_low();
297 pin.conf().write(|_| ()); 273 pin.conf().write(|_| ());
298 r.psel().out(1).write_value(DISCONNECTED); 274 self.r.psel().out(1).write_value(DISCONNECTED);
299 } 275 }
300 if let Some(pin) = &self.ch2 { 276 if let Some(pin) = &self.ch2 {
301 pin.set_low(); 277 pin.set_low();
302 pin.conf().write(|_| ()); 278 pin.conf().write(|_| ());
303 r.psel().out(2).write_value(DISCONNECTED); 279 self.r.psel().out(2).write_value(DISCONNECTED);
304 } 280 }
305 if let Some(pin) = &self.ch3 { 281 if let Some(pin) = &self.ch3 {
306 pin.set_low(); 282 pin.set_low();
307 pin.conf().write(|_| ()); 283 pin.conf().write(|_| ());
308 r.psel().out(3).write_value(DISCONNECTED); 284 self.r.psel().out(3).write_value(DISCONNECTED);
309 } 285 }
286
287 self.r.enable().write(|w| w.set_enable(false));
310 } 288 }
311} 289}
312 290
@@ -384,13 +362,13 @@ impl<'s> Sequence<'s> {
384/// A single sequence that can be started and stopped. 362/// A single sequence that can be started and stopped.
385/// Takes one sequence along with its configuration. 363/// Takes one sequence along with its configuration.
386#[non_exhaustive] 364#[non_exhaustive]
387pub struct SingleSequencer<'d, 's, T: Instance> { 365pub struct SingleSequencer<'d, 's> {
388 sequencer: Sequencer<'d, 's, T>, 366 sequencer: Sequencer<'d, 's>,
389} 367}
390 368
391impl<'d, 's, T: Instance> SingleSequencer<'d, 's, T> { 369impl<'d, 's> SingleSequencer<'d, 's> {
392 /// Create a new sequencer 370 /// Create a new sequencer
393 pub fn new(pwm: &'s mut SequencePwm<'d, T>, words: &'s [u16], config: SequenceConfig) -> Self { 371 pub fn new(pwm: &'s mut SequencePwm<'d>, words: &'s [u16], config: SequenceConfig) -> Self {
394 Self { 372 Self {
395 sequencer: Sequencer::new(pwm, Sequence::new(words, config), None), 373 sequencer: Sequencer::new(pwm, Sequence::new(words, config), None),
396 } 374 }
@@ -423,16 +401,16 @@ impl<'d, 's, T: Instance> SingleSequencer<'d, 's, T> {
423/// In the case where no second sequence is provided then the first sequence 401/// In the case where no second sequence is provided then the first sequence
424/// is used. 402/// is used.
425#[non_exhaustive] 403#[non_exhaustive]
426pub struct Sequencer<'d, 's, T: Instance> { 404pub struct Sequencer<'d, 's> {
427 _pwm: &'s mut SequencePwm<'d, T>, 405 _pwm: &'s mut SequencePwm<'d>,
428 sequence0: Sequence<'s>, 406 sequence0: Sequence<'s>,
429 sequence1: Option<Sequence<'s>>, 407 sequence1: Option<Sequence<'s>>,
430} 408}
431 409
432impl<'d, 's, T: Instance> Sequencer<'d, 's, T> { 410impl<'d, 's> Sequencer<'d, 's> {
433 /// Create a new double sequence. In the absence of sequence 1, sequence 0 411 /// Create a new double sequence. In the absence of sequence 1, sequence 0
434 /// will be used twice in the one loop. 412 /// will be used twice in the one loop.
435 pub fn new(pwm: &'s mut SequencePwm<'d, T>, sequence0: Sequence<'s>, sequence1: Option<Sequence<'s>>) -> Self { 413 pub fn new(pwm: &'s mut SequencePwm<'d>, sequence0: Sequence<'s>, sequence1: Option<Sequence<'s>>) -> Self {
436 Sequencer { 414 Sequencer {
437 _pwm: pwm, 415 _pwm: pwm,
438 sequence0, 416 sequence0,
@@ -459,7 +437,7 @@ impl<'d, 's, T: Instance> Sequencer<'d, 's, T> {
459 437
460 self.stop(); 438 self.stop();
461 439
462 let r = T::regs(); 440 let r = self._pwm.r;
463 441
464 r.seq(0).refresh().write(|w| w.0 = sequence0.config.refresh); 442 r.seq(0).refresh().write(|w| w.0 = sequence0.config.refresh);
465 r.seq(0).enddelay().write(|w| w.0 = sequence0.config.end_delay); 443 r.seq(0).enddelay().write(|w| w.0 = sequence0.config.end_delay);
@@ -499,7 +477,7 @@ impl<'d, 's, T: Instance> Sequencer<'d, 's, T> {
499 /// `start` so that they may be further mutated. 477 /// `start` so that they may be further mutated.
500 #[inline(always)] 478 #[inline(always)]
501 pub fn stop(&self) { 479 pub fn stop(&self) {
502 let r = T::regs(); 480 let r = self._pwm.r;
503 481
504 r.shorts().write(|_| ()); 482 r.shorts().write(|_| ());
505 483
@@ -510,7 +488,7 @@ impl<'d, 's, T: Instance> Sequencer<'d, 's, T> {
510 } 488 }
511} 489}
512 490
513impl<'d, 's, T: Instance> Drop for Sequencer<'d, 's, T> { 491impl<'d, 's> Drop for Sequencer<'d, 's> {
514 fn drop(&mut self) { 492 fn drop(&mut self) {
515 self.stop(); 493 self.stop();
516 } 494 }
@@ -589,22 +567,22 @@ pub enum CounterMode {
589 UpAndDown, 567 UpAndDown,
590} 568}
591 569
592impl<'d, T: Instance> SimplePwm<'d, T> { 570impl<'d> SimplePwm<'d> {
593 /// Create a new 1-channel PWM 571 /// Create a new 1-channel PWM
594 #[allow(unused_unsafe)] 572 #[allow(unused_unsafe)]
595 pub fn new_1ch(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>) -> Self { 573 pub fn new_1ch<T: Instance>(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>) -> Self {
596 unsafe { Self::new_inner(pwm, Some(ch0.into()), None, None, None) } 574 unsafe { Self::new_inner(pwm, Some(ch0.into()), None, None, None) }
597 } 575 }
598 576
599 /// Create a new 2-channel PWM 577 /// Create a new 2-channel PWM
600 #[allow(unused_unsafe)] 578 #[allow(unused_unsafe)]
601 pub fn new_2ch(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, ch1: Peri<'d, impl GpioPin>) -> Self { 579 pub fn new_2ch<T: Instance>(pwm: Peri<'d, T>, ch0: Peri<'d, impl GpioPin>, ch1: Peri<'d, impl GpioPin>) -> Self {
602 Self::new_inner(pwm, Some(ch0.into()), Some(ch1.into()), None, None) 580 Self::new_inner(pwm, Some(ch0.into()), Some(ch1.into()), None, None)
603 } 581 }
604 582
605 /// Create a new 3-channel PWM 583 /// Create a new 3-channel PWM
606 #[allow(unused_unsafe)] 584 #[allow(unused_unsafe)]
607 pub fn new_3ch( 585 pub fn new_3ch<T: Instance>(
608 pwm: Peri<'d, T>, 586 pwm: Peri<'d, T>,
609 ch0: Peri<'d, impl GpioPin>, 587 ch0: Peri<'d, impl GpioPin>,
610 ch1: Peri<'d, impl GpioPin>, 588 ch1: Peri<'d, impl GpioPin>,
@@ -615,7 +593,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> {
615 593
616 /// Create a new 4-channel PWM 594 /// Create a new 4-channel PWM
617 #[allow(unused_unsafe)] 595 #[allow(unused_unsafe)]
618 pub fn new_4ch( 596 pub fn new_4ch<T: Instance>(
619 pwm: Peri<'d, T>, 597 pwm: Peri<'d, T>,
620 ch0: Peri<'d, impl GpioPin>, 598 ch0: Peri<'d, impl GpioPin>,
621 ch1: Peri<'d, impl GpioPin>, 599 ch1: Peri<'d, impl GpioPin>,
@@ -633,7 +611,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> {
633 } 611 }
634 } 612 }
635 613
636 fn new_inner( 614 fn new_inner<T: Instance>(
637 _pwm: Peri<'d, T>, 615 _pwm: Peri<'d, T>,
638 ch0: Option<Peri<'d, AnyPin>>, 616 ch0: Option<Peri<'d, AnyPin>>,
639 ch1: Option<Peri<'d, AnyPin>>, 617 ch1: Option<Peri<'d, AnyPin>>,
@@ -656,7 +634,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> {
656 } 634 }
657 635
658 let pwm = Self { 636 let pwm = Self {
659 _peri: _pwm, 637 r: T::regs(),
660 ch0, 638 ch0,
661 ch1, 639 ch1,
662 ch2, 640 ch2,
@@ -691,22 +669,19 @@ impl<'d, T: Instance> SimplePwm<'d, T> {
691 /// Returns the enable state of the pwm counter 669 /// Returns the enable state of the pwm counter
692 #[inline(always)] 670 #[inline(always)]
693 pub fn is_enabled(&self) -> bool { 671 pub fn is_enabled(&self) -> bool {
694 let r = T::regs(); 672 self.r.enable().read().enable()
695 r.enable().read().enable()
696 } 673 }
697 674
698 /// Enables the PWM generator. 675 /// Enables the PWM generator.
699 #[inline(always)] 676 #[inline(always)]
700 pub fn enable(&self) { 677 pub fn enable(&self) {
701 let r = T::regs(); 678 self.r.enable().write(|w| w.set_enable(true));
702 r.enable().write(|w| w.set_enable(true));
703 } 679 }
704 680
705 /// Disables the PWM generator. Does NOT clear the last duty cycle from the pin. 681 /// Disables the PWM generator. Does NOT clear the last duty cycle from the pin.
706 #[inline(always)] 682 #[inline(always)]
707 pub fn disable(&self) { 683 pub fn disable(&self) {
708 let r = T::regs(); 684 self.r.enable().write(|w| w.set_enable(false));
709 r.enable().write(|w| w.set_enable(false));
710 } 685 }
711 686
712 /// Returns the current duty of the channel 687 /// Returns the current duty of the channel
@@ -716,32 +691,30 @@ impl<'d, T: Instance> SimplePwm<'d, T> {
716 691
717 /// Sets duty cycle (15 bit) for a PWM channel. 692 /// Sets duty cycle (15 bit) for a PWM channel.
718 pub fn set_duty(&mut self, channel: usize, duty: u16) { 693 pub fn set_duty(&mut self, channel: usize, duty: u16) {
719 let r = T::regs();
720
721 self.duty[channel] = duty & 0x7FFF; 694 self.duty[channel] = duty & 0x7FFF;
722 695
723 // reload ptr in case self was moved 696 // reload ptr in case self was moved
724 r.seq(0).ptr().write_value((self.duty).as_ptr() as u32); 697 self.r.seq(0).ptr().write_value((self.duty).as_ptr() as u32);
725 698
726 // defensive before seqstart 699 // defensive before seqstart
727 compiler_fence(Ordering::SeqCst); 700 compiler_fence(Ordering::SeqCst);
728 701
729 r.events_seqend(0).write_value(0); 702 self.r.events_seqend(0).write_value(0);
730 703
731 // tasks_seqstart() doesn't exist in all svds so write its bit instead 704 // tasks_seqstart() doesn't exist in all svds so write its bit instead
732 r.tasks_seqstart(0).write_value(1); 705 self.r.tasks_seqstart(0).write_value(1);
733 706
734 // defensive wait until waveform is loaded after seqstart so set_duty 707 // defensive wait until waveform is loaded after seqstart so set_duty
735 // can't be called again while dma is still reading 708 // can't be called again while dma is still reading
736 if self.is_enabled() { 709 if self.is_enabled() {
737 while r.events_seqend(0).read() == 0 {} 710 while self.r.events_seqend(0).read() == 0 {}
738 } 711 }
739 } 712 }
740 713
741 /// Sets the PWM clock prescaler. 714 /// Sets the PWM clock prescaler.
742 #[inline(always)] 715 #[inline(always)]
743 pub fn set_prescaler(&self, div: Prescaler) { 716 pub fn set_prescaler(&self, div: Prescaler) {
744 T::regs() 717 self.r
745 .prescaler() 718 .prescaler()
746 .write(|w| w.set_prescaler(vals::Prescaler::from_bits(div as u8))); 719 .write(|w| w.set_prescaler(vals::Prescaler::from_bits(div as u8)));
747 } 720 }
@@ -749,7 +722,7 @@ impl<'d, T: Instance> SimplePwm<'d, T> {
749 /// Gets the PWM clock prescaler. 722 /// Gets the PWM clock prescaler.
750 #[inline(always)] 723 #[inline(always)]
751 pub fn prescaler(&self) -> Prescaler { 724 pub fn prescaler(&self) -> Prescaler {
752 match T::regs().prescaler().read().prescaler().to_bits() { 725 match self.r.prescaler().read().prescaler().to_bits() {
753 0 => Prescaler::Div1, 726 0 => Prescaler::Div1,
754 1 => Prescaler::Div2, 727 1 => Prescaler::Div2,
755 2 => Prescaler::Div4, 728 2 => Prescaler::Div4,
@@ -765,13 +738,13 @@ impl<'d, T: Instance> SimplePwm<'d, T> {
765 /// Sets the maximum duty cycle value. 738 /// Sets the maximum duty cycle value.
766 #[inline(always)] 739 #[inline(always)]
767 pub fn set_max_duty(&self, duty: u16) { 740 pub fn set_max_duty(&self, duty: u16) {
768 T::regs().countertop().write(|w| w.set_countertop(duty.min(32767u16))); 741 self.r.countertop().write(|w| w.set_countertop(duty.min(32767u16)));
769 } 742 }
770 743
771 /// Returns the maximum duty cycle value. 744 /// Returns the maximum duty cycle value.
772 #[inline(always)] 745 #[inline(always)]
773 pub fn max_duty(&self) -> u16 { 746 pub fn max_duty(&self) -> u16 {
774 T::regs().countertop().read().countertop() 747 self.r.countertop().read().countertop()
775 } 748 }
776 749
777 /// Sets the PWM output frequency. 750 /// Sets the PWM output frequency.
@@ -823,9 +796,9 @@ impl<'d, T: Instance> SimplePwm<'d, T> {
823 } 796 }
824} 797}
825 798
826impl<'a, T: Instance> Drop for SimplePwm<'a, T> { 799impl<'a> Drop for SimplePwm<'a> {
827 fn drop(&mut self) { 800 fn drop(&mut self) {
828 let r = T::regs(); 801 let r = &self.r;
829 802
830 self.disable(); 803 self.disable();
831 804
diff --git a/embassy-nrf/src/qdec.rs b/embassy-nrf/src/qdec.rs
index 69bfab0bb..0ebd7afb8 100644
--- a/embassy-nrf/src/qdec.rs
+++ b/embassy-nrf/src/qdec.rs
@@ -16,8 +16,10 @@ use crate::pac::qdec::vals;
16use crate::{interrupt, pac}; 16use crate::{interrupt, pac};
17 17
18/// Quadrature decoder driver. 18/// Quadrature decoder driver.
19pub struct Qdec<'d, T: Instance> { 19pub struct Qdec<'d> {
20 _p: Peri<'d, T>, 20 r: pac::qdec::Qdec,
21 state: &'static State,
22 _phantom: PhantomData<&'d ()>,
21} 23}
22 24
23/// QDEC config 25/// QDEC config
@@ -59,9 +61,9 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
59 } 61 }
60} 62}
61 63
62impl<'d, T: Instance> Qdec<'d, T> { 64impl<'d> Qdec<'d> {
63 /// Create a new QDEC. 65 /// Create a new QDEC.
64 pub fn new( 66 pub fn new<T: Instance>(
65 qdec: Peri<'d, T>, 67 qdec: Peri<'d, T>,
66 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 68 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
67 a: Peri<'d, impl GpioPin>, 69 a: Peri<'d, impl GpioPin>,
@@ -72,7 +74,7 @@ impl<'d, T: Instance> Qdec<'d, T> {
72 } 74 }
73 75
74 /// Create a new QDEC, with a pin for LED output. 76 /// Create a new QDEC, with a pin for LED output.
75 pub fn new_with_led( 77 pub fn new_with_led<T: Instance>(
76 qdec: Peri<'d, T>, 78 qdec: Peri<'d, T>,
77 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 79 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
78 a: Peri<'d, impl GpioPin>, 80 a: Peri<'d, impl GpioPin>,
@@ -83,8 +85,8 @@ impl<'d, T: Instance> Qdec<'d, T> {
83 Self::new_inner(qdec, a.into(), b.into(), Some(led.into()), config) 85 Self::new_inner(qdec, a.into(), b.into(), Some(led.into()), config)
84 } 86 }
85 87
86 fn new_inner( 88 fn new_inner<T: Instance>(
87 p: Peri<'d, T>, 89 _p: Peri<'d, T>,
88 a: Peri<'d, AnyPin>, 90 a: Peri<'d, AnyPin>,
89 b: Peri<'d, AnyPin>, 91 b: Peri<'d, AnyPin>,
90 led: Option<Peri<'d, AnyPin>>, 92 led: Option<Peri<'d, AnyPin>>,
@@ -147,7 +149,11 @@ impl<'d, T: Instance> Qdec<'d, T> {
147 // Start sampling 149 // Start sampling
148 r.tasks_start().write_value(1); 150 r.tasks_start().write_value(1);
149 151
150 Self { _p: p } 152 Self {
153 r: T::regs(),
154 state: T::state(),
155 _phantom: PhantomData,
156 }
151 } 157 }
152 158
153 /// Perform an asynchronous read of the decoder. 159 /// Perform an asynchronous read of the decoder.
@@ -173,17 +179,18 @@ impl<'d, T: Instance> Qdec<'d, T> {
173 /// # }; 179 /// # };
174 /// ``` 180 /// ```
175 pub async fn read(&mut self) -> i16 { 181 pub async fn read(&mut self) -> i16 {
176 let t = T::regs(); 182 self.r.intenset().write(|w| w.set_reportrdy(true));
177 t.intenset().write(|w| w.set_reportrdy(true)); 183 self.r.tasks_readclracc().write_value(1);
178 t.tasks_readclracc().write_value(1);
179 184
180 poll_fn(|cx| { 185 let state = self.state;
181 T::state().waker.register(cx.waker()); 186 let r = self.r;
182 if t.events_reportrdy().read() == 0 { 187 poll_fn(move |cx| {
188 state.waker.register(cx.waker());
189 if r.events_reportrdy().read() == 0 {
183 Poll::Pending 190 Poll::Pending
184 } else { 191 } else {
185 t.events_reportrdy().write_value(0); 192 r.events_reportrdy().write_value(0);
186 let acc = t.accread().read(); 193 let acc = r.accread().read();
187 Poll::Ready(acc as i16) 194 Poll::Ready(acc as i16)
188 } 195 }
189 }) 196 })
diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs
index e6e829f6e..6f4524716 100755
--- a/embassy-nrf/src/qspi.rs
+++ b/embassy-nrf/src/qspi.rs
@@ -138,16 +138,18 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
138} 138}
139 139
140/// QSPI flash driver. 140/// QSPI flash driver.
141pub struct Qspi<'d, T: Instance> { 141pub struct Qspi<'d> {
142 _peri: Peri<'d, T>, 142 r: pac::qspi::Qspi,
143 state: &'static State,
143 dpm_enabled: bool, 144 dpm_enabled: bool,
144 capacity: u32, 145 capacity: u32,
146 _phantom: PhantomData<&'d ()>,
145} 147}
146 148
147impl<'d, T: Instance> Qspi<'d, T> { 149impl<'d> Qspi<'d> {
148 /// Create a new QSPI driver. 150 /// Create a new QSPI driver.
149 pub fn new( 151 pub fn new<T: Instance>(
150 qspi: Peri<'d, T>, 152 _qspi: Peri<'d, T>,
151 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 153 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
152 sck: Peri<'d, impl GpioPin>, 154 sck: Peri<'d, impl GpioPin>,
153 csn: Peri<'d, impl GpioPin>, 155 csn: Peri<'d, impl GpioPin>,
@@ -214,9 +216,11 @@ impl<'d, T: Instance> Qspi<'d, T> {
214 r.enable().write(|w| w.set_enable(true)); 216 r.enable().write(|w| w.set_enable(true));
215 217
216 let res = Self { 218 let res = Self {
217 _peri: qspi, 219 r: T::regs(),
220 state: T::state(),
218 dpm_enabled: config.deep_power_down.is_some(), 221 dpm_enabled: config.deep_power_down.is_some(),
219 capacity: config.capacity, 222 capacity: config.capacity,
223 _phantom: PhantomData,
220 }; 224 };
221 225
222 r.events_ready().write_value(0); 226 r.events_ready().write_value(0);
@@ -274,14 +278,13 @@ impl<'d, T: Instance> Qspi<'d, T> {
274 } 278 }
275 } 279 }
276 280
277 let r = T::regs(); 281 self.r.cinstrdat0().write(|w| w.0 = dat0);
278 r.cinstrdat0().write(|w| w.0 = dat0); 282 self.r.cinstrdat1().write(|w| w.0 = dat1);
279 r.cinstrdat1().write(|w| w.0 = dat1);
280 283
281 r.events_ready().write_value(0); 284 self.r.events_ready().write_value(0);
282 r.intenset().write(|w| w.set_ready(true)); 285 self.r.intenset().write(|w| w.set_ready(true));
283 286
284 r.cinstrconf().write(|w| { 287 self.r.cinstrconf().write(|w| {
285 w.set_opcode(opcode); 288 w.set_opcode(opcode);
286 w.set_length(vals::Length::from_bits(len + 1)); 289 w.set_length(vals::Length::from_bits(len + 1));
287 w.set_lio2(true); 290 w.set_lio2(true);
@@ -295,10 +298,8 @@ impl<'d, T: Instance> Qspi<'d, T> {
295 } 298 }
296 299
297 fn custom_instruction_finish(&mut self, resp: &mut [u8]) -> Result<(), Error> { 300 fn custom_instruction_finish(&mut self, resp: &mut [u8]) -> Result<(), Error> {
298 let r = T::regs(); 301 let dat0 = self.r.cinstrdat0().read().0;
299 302 let dat1 = self.r.cinstrdat1().read().0;
300 let dat0 = r.cinstrdat0().read().0;
301 let dat1 = r.cinstrdat1().read().0;
302 for i in 0..4 { 303 for i in 0..4 {
303 if i < resp.len() { 304 if i < resp.len() {
304 resp[i] = (dat0 >> (i * 8)) as u8; 305 resp[i] = (dat0 >> (i * 8)) as u8;
@@ -313,9 +314,9 @@ impl<'d, T: Instance> Qspi<'d, T> {
313 } 314 }
314 315
315 fn wait_ready(&mut self) -> impl Future<Output = ()> { 316 fn wait_ready(&mut self) -> impl Future<Output = ()> {
317 let r = self.r;
318 let s = self.state;
316 poll_fn(move |cx| { 319 poll_fn(move |cx| {
317 let r = T::regs();
318 let s = T::state();
319 s.waker.register(cx.waker()); 320 s.waker.register(cx.waker());
320 if r.events_ready().read() != 0 { 321 if r.events_ready().read() != 0 {
321 return Poll::Ready(()); 322 return Poll::Ready(());
@@ -326,7 +327,7 @@ impl<'d, T: Instance> Qspi<'d, T> {
326 327
327 fn blocking_wait_ready() { 328 fn blocking_wait_ready() {
328 loop { 329 loop {
329 let r = T::regs(); 330 let r = pac::QSPI;
330 if r.events_ready().read() != 0 { 331 if r.events_ready().read() != 0 {
331 break; 332 break;
332 } 333 }
@@ -339,15 +340,13 @@ impl<'d, T: Instance> Qspi<'d, T> {
339 assert_eq!(data.len() as u32 % 4, 0); 340 assert_eq!(data.len() as u32 % 4, 0);
340 assert_eq!(address % 4, 0); 341 assert_eq!(address % 4, 0);
341 342
342 let r = T::regs(); 343 self.r.read().src().write_value(address);
343 344 self.r.read().dst().write_value(data.as_ptr() as u32);
344 r.read().src().write_value(address); 345 self.r.read().cnt().write(|w| w.set_cnt(data.len() as u32));
345 r.read().dst().write_value(data.as_ptr() as u32);
346 r.read().cnt().write(|w| w.set_cnt(data.len() as u32));
347 346
348 r.events_ready().write_value(0); 347 self.r.events_ready().write_value(0);
349 r.intenset().write(|w| w.set_ready(true)); 348 self.r.intenset().write(|w| w.set_ready(true));
350 r.tasks_readstart().write_value(1); 349 self.r.tasks_readstart().write_value(1);
351 350
352 Ok(()) 351 Ok(())
353 } 352 }
@@ -358,14 +357,13 @@ impl<'d, T: Instance> Qspi<'d, T> {
358 assert_eq!(data.len() as u32 % 4, 0); 357 assert_eq!(data.len() as u32 % 4, 0);
359 assert_eq!(address % 4, 0); 358 assert_eq!(address % 4, 0);
360 359
361 let r = T::regs(); 360 self.r.write().src().write_value(data.as_ptr() as u32);
362 r.write().src().write_value(data.as_ptr() as u32); 361 self.r.write().dst().write_value(address);
363 r.write().dst().write_value(address); 362 self.r.write().cnt().write(|w| w.set_cnt(data.len() as u32));
364 r.write().cnt().write(|w| w.set_cnt(data.len() as u32));
365 363
366 r.events_ready().write_value(0); 364 self.r.events_ready().write_value(0);
367 r.intenset().write(|w| w.set_ready(true)); 365 self.r.intenset().write(|w| w.set_ready(true));
368 r.tasks_writestart().write_value(1); 366 self.r.tasks_writestart().write_value(1);
369 367
370 Ok(()) 368 Ok(())
371 } 369 }
@@ -374,13 +372,12 @@ impl<'d, T: Instance> Qspi<'d, T> {
374 // TODO: Return these as errors instead. 372 // TODO: Return these as errors instead.
375 assert_eq!(address % 4096, 0); 373 assert_eq!(address % 4096, 0);
376 374
377 let r = T::regs(); 375 self.r.erase().ptr().write_value(address);
378 r.erase().ptr().write_value(address); 376 self.r.erase().len().write(|w| w.set_len(vals::Len::_4KB));
379 r.erase().len().write(|w| w.set_len(vals::Len::_4KB));
380 377
381 r.events_ready().write_value(0); 378 self.r.events_ready().write_value(0);
382 r.intenset().write(|w| w.set_ready(true)); 379 self.r.intenset().write(|w| w.set_ready(true));
383 r.tasks_erasestart().write_value(1); 380 self.r.tasks_erasestart().write_value(1);
384 381
385 Ok(()) 382 Ok(())
386 } 383 }
@@ -520,19 +517,17 @@ impl<'d, T: Instance> Qspi<'d, T> {
520 } 517 }
521} 518}
522 519
523impl<'d, T: Instance> Drop for Qspi<'d, T> { 520impl<'d> Drop for Qspi<'d> {
524 fn drop(&mut self) { 521 fn drop(&mut self) {
525 let r = T::regs();
526
527 if self.dpm_enabled { 522 if self.dpm_enabled {
528 trace!("qspi: doing deep powerdown..."); 523 trace!("qspi: doing deep powerdown...");
529 524
530 r.ifconfig1().modify(|w| w.set_dpmen(true)); 525 self.r.ifconfig1().modify(|w| w.set_dpmen(true));
531 526
532 // Wait for DPM enter. 527 // Wait for DPM enter.
533 // Unfortunately we must spin. There's no way to do this interrupt-driven. 528 // Unfortunately we must spin. There's no way to do this interrupt-driven.
534 // The READY event does NOT fire on DPM enter (but it does fire on DPM exit :shrug:) 529 // The READY event does NOT fire on DPM enter (but it does fire on DPM exit :shrug:)
535 while !r.status().read().dpm() {} 530 while !self.r.status().read().dpm() {}
536 531
537 // Wait MORE for DPM enter. 532 // Wait MORE for DPM enter.
538 // I have absolutely no idea why, but the wait above is not enough :'( 533 // I have absolutely no idea why, but the wait above is not enough :'(
@@ -541,29 +536,29 @@ impl<'d, T: Instance> Drop for Qspi<'d, T> {
541 } 536 }
542 537
543 // it seems events_ready is not generated in response to deactivate. nrfx doesn't wait for it. 538 // it seems events_ready is not generated in response to deactivate. nrfx doesn't wait for it.
544 r.tasks_deactivate().write_value(1); 539 self.r.tasks_deactivate().write_value(1);
545 540
546 // Workaround https://docs.nordicsemi.com/bundle/errata_nRF52840_Rev3/page/ERR/nRF52840/Rev3/latest/anomaly_840_122.html 541 // Workaround https://docs.nordicsemi.com/bundle/errata_nRF52840_Rev3/page/ERR/nRF52840/Rev3/latest/anomaly_840_122.html
547 // Note that the doc has 2 register writes, but the first one is really the write to tasks_deactivate, 542 // Note that the doc has 2 register writes, but the first one is really the write to tasks_deactivate,
548 // so we only do the second one here. 543 // so we only do the second one here.
549 unsafe { ptr::write_volatile(0x40029054 as *mut u32, 1) } 544 unsafe { ptr::write_volatile(0x40029054 as *mut u32, 1) }
550 545
551 r.enable().write(|w| w.set_enable(false)); 546 self.r.enable().write(|w| w.set_enable(false));
552 547
553 // Note: we do NOT deconfigure CSN here. If DPM is in use and we disconnect CSN, 548 // Note: we do NOT deconfigure CSN here. If DPM is in use and we disconnect CSN,
554 // leaving it floating, the flash chip might read it as zero which would cause it to 549 // leaving it floating, the flash chip might read it as zero which would cause it to
555 // spuriously exit DPM. 550 // spuriously exit DPM.
556 gpio::deconfigure_pin(r.psel().sck().read()); 551 gpio::deconfigure_pin(self.r.psel().sck().read());
557 gpio::deconfigure_pin(r.psel().io0().read()); 552 gpio::deconfigure_pin(self.r.psel().io0().read());
558 gpio::deconfigure_pin(r.psel().io1().read()); 553 gpio::deconfigure_pin(self.r.psel().io1().read());
559 gpio::deconfigure_pin(r.psel().io2().read()); 554 gpio::deconfigure_pin(self.r.psel().io2().read());
560 gpio::deconfigure_pin(r.psel().io3().read()); 555 gpio::deconfigure_pin(self.r.psel().io3().read());
561 556
562 trace!("qspi: dropped"); 557 trace!("qspi: dropped");
563 } 558 }
564} 559}
565 560
566impl<'d, T: Instance> ErrorType for Qspi<'d, T> { 561impl<'d> ErrorType for Qspi<'d> {
567 type Error = Error; 562 type Error = Error;
568} 563}
569 564
@@ -573,7 +568,7 @@ impl NorFlashError for Error {
573 } 568 }
574} 569}
575 570
576impl<'d, T: Instance> ReadNorFlash for Qspi<'d, T> { 571impl<'d> ReadNorFlash for Qspi<'d> {
577 const READ_SIZE: usize = 4; 572 const READ_SIZE: usize = 4;
578 573
579 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> { 574 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
@@ -586,7 +581,7 @@ impl<'d, T: Instance> ReadNorFlash for Qspi<'d, T> {
586 } 581 }
587} 582}
588 583
589impl<'d, T: Instance> NorFlash for Qspi<'d, T> { 584impl<'d> NorFlash for Qspi<'d> {
590 const WRITE_SIZE: usize = 4; 585 const WRITE_SIZE: usize = 4;
591 const ERASE_SIZE: usize = 4096; 586 const ERASE_SIZE: usize = 4096;
592 587
@@ -604,14 +599,14 @@ impl<'d, T: Instance> NorFlash for Qspi<'d, T> {
604} 599}
605 600
606#[cfg(feature = "qspi-multiwrite-flash")] 601#[cfg(feature = "qspi-multiwrite-flash")]
607impl<'d, T: Instance> embedded_storage::nor_flash::MultiwriteNorFlash for Qspi<'d, T> {} 602impl<'d> embedded_storage::nor_flash::MultiwriteNorFlash for Qspi<'d> {}
608 603
609mod _eh1 { 604mod _eh1 {
610 use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash}; 605 use embedded_storage_async::nor_flash::{NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash};
611 606
612 use super::*; 607 use super::*;
613 608
614 impl<'d, T: Instance> AsyncNorFlash for Qspi<'d, T> { 609 impl<'d> AsyncNorFlash for Qspi<'d> {
615 const WRITE_SIZE: usize = <Self as NorFlash>::WRITE_SIZE; 610 const WRITE_SIZE: usize = <Self as NorFlash>::WRITE_SIZE;
616 const ERASE_SIZE: usize = <Self as NorFlash>::ERASE_SIZE; 611 const ERASE_SIZE: usize = <Self as NorFlash>::ERASE_SIZE;
617 612
@@ -627,7 +622,7 @@ mod _eh1 {
627 } 622 }
628 } 623 }
629 624
630 impl<'d, T: Instance> AsyncReadNorFlash for Qspi<'d, T> { 625 impl<'d> AsyncReadNorFlash for Qspi<'d> {
631 const READ_SIZE: usize = 4; 626 const READ_SIZE: usize = 4;
632 async fn read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Self::Error> { 627 async fn read(&mut self, address: u32, data: &mut [u8]) -> Result<(), Self::Error> {
633 self.read(address, data).await 628 self.read(address, data).await
@@ -639,7 +634,7 @@ mod _eh1 {
639 } 634 }
640 635
641 #[cfg(feature = "qspi-multiwrite-flash")] 636 #[cfg(feature = "qspi-multiwrite-flash")]
642 impl<'d, T: Instance> embedded_storage_async::nor_flash::MultiwriteNorFlash for Qspi<'d, T> {} 637 impl<'d> embedded_storage_async::nor_flash::MultiwriteNorFlash for Qspi<'d> {}
643} 638}
644 639
645/// Peripheral static state 640/// Peripheral static state
diff --git a/embassy-nrf/src/radio/ieee802154.rs b/embassy-nrf/src/radio/ieee802154.rs
index 7f4f8f462..62af03a5a 100644
--- a/embassy-nrf/src/radio/ieee802154.rs
+++ b/embassy-nrf/src/radio/ieee802154.rs
@@ -1,15 +1,17 @@
1//! IEEE 802.15.4 radio driver 1//! IEEE 802.15.4 radio driver
2 2
3use core::marker::PhantomData;
3use core::sync::atomic::{compiler_fence, Ordering}; 4use core::sync::atomic::{compiler_fence, Ordering};
4use core::task::Poll; 5use core::task::Poll;
5 6
6use embassy_hal_internal::drop::OnDrop; 7use embassy_hal_internal::drop::OnDrop;
7 8
8use super::{Error, Instance, InterruptHandler, TxPower}; 9use super::{Error, InterruptHandler, TxPower};
9use crate::interrupt::typelevel::Interrupt; 10use crate::interrupt::typelevel::Interrupt;
10use crate::interrupt::{self}; 11use crate::interrupt::{self};
11use crate::pac::radio::vals; 12use crate::pac::radio::vals;
12pub use crate::pac::radio::vals::State as RadioState; 13pub use crate::pac::radio::vals::State as RadioState;
14use crate::radio::Instance;
13use crate::Peri; 15use crate::Peri;
14 16
15/// Default (IEEE compliant) Start of Frame Delimiter 17/// Default (IEEE compliant) Start of Frame Delimiter
@@ -32,18 +34,20 @@ pub enum Cca {
32} 34}
33 35
34/// IEEE 802.15.4 radio driver. 36/// IEEE 802.15.4 radio driver.
35pub struct Radio<'d, T: Instance> { 37pub struct Radio<'d> {
36 _p: Peri<'d, T>, 38 r: crate::pac::radio::Radio,
39 state: &'static crate::radio::State,
37 needs_enable: bool, 40 needs_enable: bool,
41 phantom: PhantomData<&'d ()>,
38} 42}
39 43
40impl<'d, T: Instance> Radio<'d, T> { 44impl<'d> Radio<'d> {
41 /// Create a new IEEE 802.15.4 radio driver. 45 /// Create a new IEEE 802.15.4 radio driver.
42 pub fn new( 46 pub fn new<T: Instance>(
43 radio: Peri<'d, T>, 47 _radio: Peri<'d, T>,
44 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 48 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
45 ) -> Self { 49 ) -> Self {
46 let r = T::regs(); 50 let r = crate::pac::RADIO;
47 51
48 // Disable and enable to reset peripheral 52 // Disable and enable to reset peripheral
49 r.power().write(|w| w.set_power(false)); 53 r.power().write(|w| w.set_power(false));
@@ -89,12 +93,14 @@ impl<'d, T: Instance> Radio<'d, T> {
89 }); 93 });
90 94
91 // Enable NVIC interrupt 95 // Enable NVIC interrupt
92 T::Interrupt::unpend(); 96 crate::interrupt::typelevel::RADIO::unpend();
93 unsafe { T::Interrupt::enable() }; 97 unsafe { crate::interrupt::typelevel::RADIO::enable() };
94 98
95 let mut radio = Self { 99 let mut radio = Self {
96 _p: radio, 100 r: crate::pac::RADIO,
101 state: T::state(),
97 needs_enable: false, 102 needs_enable: false,
103 phantom: PhantomData,
98 }; 104 };
99 105
100 radio.set_sfd(DEFAULT_SFD); 106 radio.set_sfd(DEFAULT_SFD);
@@ -107,7 +113,7 @@ impl<'d, T: Instance> Radio<'d, T> {
107 113
108 /// Changes the radio channel 114 /// Changes the radio channel
109 pub fn set_channel(&mut self, channel: u8) { 115 pub fn set_channel(&mut self, channel: u8) {
110 let r = T::regs(); 116 let r = self.r;
111 if channel < 11 || channel > 26 { 117 if channel < 11 || channel > 26 {
112 panic!("Bad 802.15.4 channel"); 118 panic!("Bad 802.15.4 channel");
113 } 119 }
@@ -121,7 +127,7 @@ impl<'d, T: Instance> Radio<'d, T> {
121 127
122 /// Changes the Clear Channel Assessment method 128 /// Changes the Clear Channel Assessment method
123 pub fn set_cca(&mut self, cca: Cca) { 129 pub fn set_cca(&mut self, cca: Cca) {
124 let r = T::regs(); 130 let r = self.r;
125 self.needs_enable = true; 131 self.needs_enable = true;
126 match cca { 132 match cca {
127 Cca::CarrierSense => r.ccactrl().write(|w| w.set_ccamode(vals::Ccamode::CARRIER_MODE)), 133 Cca::CarrierSense => r.ccactrl().write(|w| w.set_ccamode(vals::Ccamode::CARRIER_MODE)),
@@ -138,19 +144,19 @@ impl<'d, T: Instance> Radio<'d, T> {
138 144
139 /// Changes the Start of Frame Delimiter (SFD) 145 /// Changes the Start of Frame Delimiter (SFD)
140 pub fn set_sfd(&mut self, sfd: u8) { 146 pub fn set_sfd(&mut self, sfd: u8) {
141 let r = T::regs(); 147 let r = self.r;
142 r.sfd().write(|w| w.set_sfd(sfd)); 148 r.sfd().write(|w| w.set_sfd(sfd));
143 } 149 }
144 150
145 /// Clear interrupts 151 /// Clear interrupts
146 pub fn clear_all_interrupts(&mut self) { 152 pub fn clear_all_interrupts(&mut self) {
147 let r = T::regs(); 153 let r = self.r;
148 r.intenclr().write(|w| w.0 = 0xffff_ffff); 154 r.intenclr().write(|w| w.0 = 0xffff_ffff);
149 } 155 }
150 156
151 /// Changes the radio transmission power 157 /// Changes the radio transmission power
152 pub fn set_transmission_power(&mut self, power: i8) { 158 pub fn set_transmission_power(&mut self, power: i8) {
153 let r = T::regs(); 159 let r = self.r;
154 self.needs_enable = true; 160 self.needs_enable = true;
155 161
156 let tx_power: TxPower = match power { 162 let tx_power: TxPower = match power {
@@ -201,12 +207,12 @@ impl<'d, T: Instance> Radio<'d, T> {
201 207
202 /// Get the current radio state 208 /// Get the current radio state
203 fn state(&self) -> RadioState { 209 fn state(&self) -> RadioState {
204 T::regs().state().read().state() 210 self.r.state().read().state()
205 } 211 }
206 212
207 /// Moves the radio from any state to the DISABLED state 213 /// Moves the radio from any state to the DISABLED state
208 fn disable(&mut self) { 214 fn disable(&mut self) {
209 let r = T::regs(); 215 let r = self.r;
210 // See figure 110 in nRF52840-PS 216 // See figure 110 in nRF52840-PS
211 loop { 217 loop {
212 match self.state() { 218 match self.state() {
@@ -238,15 +244,15 @@ impl<'d, T: Instance> Radio<'d, T> {
238 } 244 }
239 245
240 fn set_buffer(&mut self, buffer: &[u8]) { 246 fn set_buffer(&mut self, buffer: &[u8]) {
241 let r = T::regs(); 247 let r = self.r;
242 r.packetptr().write_value(buffer.as_ptr() as u32); 248 r.packetptr().write_value(buffer.as_ptr() as u32);
243 } 249 }
244 250
245 /// Moves the radio to the RXIDLE state 251 /// Moves the radio to the RXIDLE state
246 fn receive_prepare(&mut self) { 252 fn receive_prepare(&mut self) {
247 // clear related events 253 // clear related events
248 T::regs().events_ccabusy().write_value(0); 254 self.r.events_ccabusy().write_value(0);
249 T::regs().events_phyend().write_value(0); 255 self.r.events_phyend().write_value(0);
250 // NOTE to avoid errata 204 (see rev1 v1.4) we do TX_IDLE -> DISABLED -> RXIDLE 256 // NOTE to avoid errata 204 (see rev1 v1.4) we do TX_IDLE -> DISABLED -> RXIDLE
251 let disable = match self.state() { 257 let disable = match self.state() {
252 RadioState::DISABLED => false, 258 RadioState::DISABLED => false,
@@ -263,7 +269,7 @@ impl<'d, T: Instance> Radio<'d, T> {
263 fn receive_start(&mut self, packet: &mut Packet) { 269 fn receive_start(&mut self, packet: &mut Packet) {
264 // NOTE we do NOT check the address of `packet` because the mutable reference ensures it's 270 // NOTE we do NOT check the address of `packet` because the mutable reference ensures it's
265 // allocated in RAM 271 // allocated in RAM
266 let r = T::regs(); 272 let r = self.r;
267 273
268 self.receive_prepare(); 274 self.receive_prepare();
269 275
@@ -290,7 +296,7 @@ impl<'d, T: Instance> Radio<'d, T> {
290 296
291 /// Cancel receiving packet 297 /// Cancel receiving packet
292 fn receive_cancel() { 298 fn receive_cancel() {
293 let r = T::regs(); 299 let r = crate::pac::RADIO;
294 r.shorts().write(|_| {}); 300 r.shorts().write(|_| {});
295 r.tasks_stop().write_value(1); 301 r.tasks_stop().write_value(1);
296 loop { 302 loop {
@@ -309,8 +315,8 @@ impl<'d, T: Instance> Radio<'d, T> {
309 /// validated by the hardware; otherwise it returns the `Err` variant. In either case, `packet` 315 /// validated by the hardware; otherwise it returns the `Err` variant. In either case, `packet`
310 /// will be updated with the received packet's data 316 /// will be updated with the received packet's data
311 pub async fn receive(&mut self, packet: &mut Packet) -> Result<(), Error> { 317 pub async fn receive(&mut self, packet: &mut Packet) -> Result<(), Error> {
312 let s = T::state(); 318 let s = self.state;
313 let r = T::regs(); 319 let r = self.r;
314 320
315 // Start the read 321 // Start the read
316 self.receive_start(packet); 322 self.receive_start(packet);
@@ -356,8 +362,8 @@ impl<'d, T: Instance> Radio<'d, T> {
356 // NOTE we do NOT check the address of `packet` because the mutable reference ensures it's 362 // NOTE we do NOT check the address of `packet` because the mutable reference ensures it's
357 // allocated in RAM 363 // allocated in RAM
358 pub async fn try_send(&mut self, packet: &mut Packet) -> Result<(), Error> { 364 pub async fn try_send(&mut self, packet: &mut Packet) -> Result<(), Error> {
359 let s = T::state(); 365 let s = self.state;
360 let r = T::regs(); 366 let r = self.r;
361 367
362 // enable radio to perform cca 368 // enable radio to perform cca
363 self.receive_prepare(); 369 self.receive_prepare();
diff --git a/embassy-nrf/src/rng.rs b/embassy-nrf/src/rng.rs
index 9d3130e6e..8070c1afe 100644
--- a/embassy-nrf/src/rng.rs
+++ b/embassy-nrf/src/rng.rs
@@ -56,21 +56,23 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
56/// A wrapper around an nRF RNG peripheral. 56/// A wrapper around an nRF RNG peripheral.
57/// 57///
58/// It has a non-blocking API, and a blocking api through `rand`. 58/// It has a non-blocking API, and a blocking api through `rand`.
59pub struct Rng<'d, T: Instance, M: Mode> { 59pub struct Rng<'d, M: Mode> {
60 _peri: Peri<'d, T>, 60 r: pac::rng::Rng,
61 _phantom: PhantomData<M>, 61 state: &'static State,
62 _phantom: PhantomData<(&'d (), M)>,
62} 63}
63 64
64impl<'d, T: Instance> Rng<'d, T, Blocking> { 65impl<'d> Rng<'d, Blocking> {
65 /// Creates a new RNG driver from the `RNG` peripheral and interrupt. 66 /// Creates a new RNG driver from the `RNG` peripheral and interrupt.
66 /// 67 ///
67 /// SAFETY: The future returned from `fill_bytes` must not have its lifetime end without running its destructor, 68 /// SAFETY: The future returned from `fill_bytes` must not have its lifetime end without running its destructor,
68 /// e.g. using `mem::forget`. 69 /// e.g. using `mem::forget`.
69 /// 70 ///
70 /// The synchronous API is safe. 71 /// The synchronous API is safe.
71 pub fn new_blocking(rng: Peri<'d, T>) -> Self { 72 pub fn new_blocking<T: Instance>(_rng: Peri<'d, T>) -> Self {
72 let this = Self { 73 let this = Self {
73 _peri: rng, 74 r: T::regs(),
75 state: T::state(),
74 _phantom: PhantomData, 76 _phantom: PhantomData,
75 }; 77 };
76 78
@@ -80,19 +82,20 @@ impl<'d, T: Instance> Rng<'d, T, Blocking> {
80 } 82 }
81} 83}
82 84
83impl<'d, T: Instance> Rng<'d, T, Async> { 85impl<'d> Rng<'d, Async> {
84 /// Creates a new RNG driver from the `RNG` peripheral and interrupt. 86 /// Creates a new RNG driver from the `RNG` peripheral and interrupt.
85 /// 87 ///
86 /// SAFETY: The future returned from `fill_bytes` must not have its lifetime end without running its destructor, 88 /// SAFETY: The future returned from `fill_bytes` must not have its lifetime end without running its destructor,
87 /// e.g. using `mem::forget`. 89 /// e.g. using `mem::forget`.
88 /// 90 ///
89 /// The synchronous API is safe. 91 /// The synchronous API is safe.
90 pub fn new( 92 pub fn new<T: Instance>(
91 rng: Peri<'d, T>, 93 _rng: Peri<'d, T>,
92 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 94 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
93 ) -> Self { 95 ) -> Self {
94 let this = Self { 96 let this = Self {
95 _peri: rng, 97 r: T::regs(),
98 state: T::state(),
96 _phantom: PhantomData, 99 _phantom: PhantomData,
97 }; 100 };
98 101
@@ -106,11 +109,11 @@ impl<'d, T: Instance> Rng<'d, T, Async> {
106 } 109 }
107 110
108 fn enable_irq(&self) { 111 fn enable_irq(&self) {
109 T::regs().intenset().write(|w| w.set_valrdy(true)); 112 self.r.intenset().write(|w| w.set_valrdy(true));
110 } 113 }
111 114
112 fn disable_irq(&self) { 115 fn disable_irq(&self) {
113 T::regs().intenclr().write(|w| w.set_valrdy(true)); 116 self.r.intenclr().write(|w| w.set_valrdy(true));
114 } 117 }
115 118
116 /// Fill the buffer with random bytes. 119 /// Fill the buffer with random bytes.
@@ -120,10 +123,11 @@ impl<'d, T: Instance> Rng<'d, T, Async> {
120 } 123 }
121 124
122 let range = dest.as_mut_ptr_range(); 125 let range = dest.as_mut_ptr_range();
126 let state = self.state;
123 // Even if we've preempted the interrupt, it can't preempt us again, 127 // Even if we've preempted the interrupt, it can't preempt us again,
124 // so we don't need to worry about the order we write these in. 128 // so we don't need to worry about the order we write these in.
125 critical_section::with(|cs| { 129 critical_section::with(|cs| {
126 let mut state = T::state().borrow_mut(cs); 130 let mut state = state.borrow_mut(cs);
127 state.ptr = range.start; 131 state.ptr = range.start;
128 state.end = range.end; 132 state.end = range.end;
129 }); 133 });
@@ -136,7 +140,7 @@ impl<'d, T: Instance> Rng<'d, T, Async> {
136 self.disable_irq(); 140 self.disable_irq();
137 141
138 critical_section::with(|cs| { 142 critical_section::with(|cs| {
139 let mut state = T::state().borrow_mut(cs); 143 let mut state = state.borrow_mut(cs);
140 state.ptr = ptr::null_mut(); 144 state.ptr = ptr::null_mut();
141 state.end = ptr::null_mut(); 145 state.end = ptr::null_mut();
142 }); 146 });
@@ -144,7 +148,7 @@ impl<'d, T: Instance> Rng<'d, T, Async> {
144 148
145 poll_fn(|cx| { 149 poll_fn(|cx| {
146 critical_section::with(|cs| { 150 critical_section::with(|cs| {
147 let mut s = T::state().borrow_mut(cs); 151 let mut s = state.borrow_mut(cs);
148 s.waker.register(cx.waker()); 152 s.waker.register(cx.waker());
149 if s.ptr == s.end { 153 if s.ptr == s.end {
150 // We're done. 154 // We're done.
@@ -161,13 +165,13 @@ impl<'d, T: Instance> Rng<'d, T, Async> {
161 } 165 }
162} 166}
163 167
164impl<'d, T: Instance, M: Mode> Rng<'d, T, M> { 168impl<'d, M: Mode> Rng<'d, M> {
165 fn stop(&self) { 169 fn stop(&self) {
166 T::regs().tasks_stop().write_value(1) 170 self.r.tasks_stop().write_value(1)
167 } 171 }
168 172
169 fn start(&self) { 173 fn start(&self) {
170 T::regs().tasks_start().write_value(1) 174 self.r.tasks_start().write_value(1)
171 } 175 }
172 176
173 /// Enable or disable the RNG's bias correction. 177 /// Enable or disable the RNG's bias correction.
@@ -177,7 +181,7 @@ impl<'d, T: Instance, M: Mode> Rng<'d, T, M> {
177 /// 181 ///
178 /// Defaults to disabled. 182 /// Defaults to disabled.
179 pub fn set_bias_correction(&self, enable: bool) { 183 pub fn set_bias_correction(&self, enable: bool) {
180 T::regs().config().write(|w| w.set_dercen(enable)) 184 self.r.config().write(|w| w.set_dercen(enable))
181 } 185 }
182 186
183 /// Fill the buffer with random bytes, blocking version. 187 /// Fill the buffer with random bytes, blocking version.
@@ -185,7 +189,7 @@ impl<'d, T: Instance, M: Mode> Rng<'d, T, M> {
185 self.start(); 189 self.start();
186 190
187 for byte in dest.iter_mut() { 191 for byte in dest.iter_mut() {
188 let regs = T::regs(); 192 let regs = self.r;
189 while regs.events_valrdy().read() == 0 {} 193 while regs.events_valrdy().read() == 0 {}
190 regs.events_valrdy().write_value(0); 194 regs.events_valrdy().write_value(0);
191 *byte = regs.value().read().value(); 195 *byte = regs.value().read().value();
@@ -210,18 +214,18 @@ impl<'d, T: Instance, M: Mode> Rng<'d, T, M> {
210 } 214 }
211} 215}
212 216
213impl<'d, T: Instance, M: Mode> Drop for Rng<'d, T, M> { 217impl<'d, M: Mode> Drop for Rng<'d, M> {
214 fn drop(&mut self) { 218 fn drop(&mut self) {
215 self.stop(); 219 self.stop();
216 critical_section::with(|cs| { 220 critical_section::with(|cs| {
217 let mut state = T::state().borrow_mut(cs); 221 let mut state = self.state.borrow_mut(cs);
218 state.ptr = ptr::null_mut(); 222 state.ptr = ptr::null_mut();
219 state.end = ptr::null_mut(); 223 state.end = ptr::null_mut();
220 }); 224 });
221 } 225 }
222} 226}
223 227
224impl<'d, T: Instance, M: Mode> rand_core_06::RngCore for Rng<'d, T, M> { 228impl<'d, M: Mode> rand_core_06::RngCore for Rng<'d, M> {
225 fn fill_bytes(&mut self, dest: &mut [u8]) { 229 fn fill_bytes(&mut self, dest: &mut [u8]) {
226 self.blocking_fill_bytes(dest); 230 self.blocking_fill_bytes(dest);
227 } 231 }
@@ -237,9 +241,9 @@ impl<'d, T: Instance, M: Mode> rand_core_06::RngCore for Rng<'d, T, M> {
237 } 241 }
238} 242}
239 243
240impl<'d, T: Instance, M: Mode> rand_core_06::CryptoRng for Rng<'d, T, M> {} 244impl<'d, M: Mode> rand_core_06::CryptoRng for Rng<'d, M> {}
241 245
242impl<'d, T: Instance, M: Mode> rand_core_09::RngCore for Rng<'d, T, M> { 246impl<'d, M: Mode> rand_core_09::RngCore for Rng<'d, M> {
243 fn fill_bytes(&mut self, dest: &mut [u8]) { 247 fn fill_bytes(&mut self, dest: &mut [u8]) {
244 self.blocking_fill_bytes(dest); 248 self.blocking_fill_bytes(dest);
245 } 249 }
@@ -251,7 +255,7 @@ impl<'d, T: Instance, M: Mode> rand_core_09::RngCore for Rng<'d, T, M> {
251 } 255 }
252} 256}
253 257
254impl<'d, T: Instance, M: Mode> rand_core_09::CryptoRng for Rng<'d, T, M> {} 258impl<'d, M: Mode> rand_core_09::CryptoRng for Rng<'d, M> {}
255 259
256/// Peripheral static state 260/// Peripheral static state
257pub(crate) struct State { 261pub(crate) struct State {
diff --git a/embassy-nrf/src/rtc.rs b/embassy-nrf/src/rtc.rs
new file mode 100644
index 000000000..652de511b
--- /dev/null
+++ b/embassy-nrf/src/rtc.rs
@@ -0,0 +1,274 @@
1//! Low-level RTC driver.
2
3#![macro_use]
4
5use core::marker::PhantomData;
6
7use embassy_hal_internal::interrupt::InterruptExt;
8use embassy_hal_internal::{Peri, PeripheralType};
9
10use crate::interrupt::typelevel::Interrupt as _;
11use crate::{interrupt, pac};
12
13/// Prescaler has an invalid value which exceeds 12 bits.
14#[derive(Debug, PartialEq, Eq)]
15#[cfg_attr(feature = "defmt", derive(defmt::Format))]
16pub struct PrescalerOutOfRangeError(u32);
17
18/// Compare value has an invalid value which exceeds 24 bits.
19#[derive(Debug, PartialEq, Eq)]
20#[cfg_attr(feature = "defmt", derive(defmt::Format))]
21pub struct CompareOutOfRangeError(u32);
22
23/// Interrupts/Events that can be generated by the RTCn peripheral.
24#[derive(Debug, Copy, Clone, PartialEq, Eq)]
25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26pub enum Interrupt {
27 /// Tick interrupt.
28 Tick,
29 /// Overflow interrupt.
30 Overflow,
31 /// Compare 0 interrupt.
32 Compare0,
33 /// Compare 1 interrupt.
34 Compare1,
35 /// Compare 2 interrupt.
36 Compare2,
37 /// Compare 3 interrupt. Only implemented for RTC1 and RTC2.
38 Compare3,
39}
40
41/// Compare registers available on the RTCn.
42#[derive(Debug, Copy, Clone)]
43#[cfg_attr(feature = "defmt", derive(defmt::Format))]
44pub enum CompareChannel {
45 /// Channel 0
46 _0,
47 /// Channel 1
48 _1,
49 /// Channel 2
50 _2,
51 /// Channel 3. Only implemented for RTC1 and RTC2.
52 _3,
53}
54
55pub(crate) trait SealedInstance {
56 fn regs() -> pac::rtc::Rtc;
57}
58
59/// Basic RTC instance.
60#[allow(private_bounds)]
61pub trait Instance: SealedInstance + PeripheralType + 'static + Send {
62 /// Interrupt for this peripheral.
63 type Interrupt: crate::interrupt::typelevel::Interrupt;
64
65 /// Unsafely create a peripheral instance.
66 ///
67 /// # Safety
68 ///
69 /// Potentially allows to create multiple instances of the driver for the same peripheral
70 /// which can lead to undefined behavior.
71 unsafe fn steal() -> Peri<'static, Self>;
72}
73
74macro_rules! impl_rtc {
75 ($type:ident, $pac_type:ident, $irq:ident) => {
76 impl crate::rtc::SealedInstance for peripherals::$type {
77 #[inline]
78 fn regs() -> pac::rtc::Rtc {
79 unsafe { pac::rtc::Rtc::from_ptr(pac::$pac_type.as_ptr()) }
80 }
81 }
82
83 impl crate::rtc::Instance for peripherals::$type {
84 type Interrupt = crate::interrupt::typelevel::$irq;
85
86 unsafe fn steal() -> embassy_hal_internal::Peri<'static, Self> {
87 unsafe { peripherals::$type::steal() }
88 }
89 }
90 };
91}
92
93/// nRF RTC driver.
94pub struct Rtc<'d> {
95 r: pac::rtc::Rtc,
96 irq: interrupt::Interrupt,
97 _phantom: PhantomData<&'d ()>,
98}
99
100impl<'d> Rtc<'d> {
101 /// Create a new `Rtc` driver.
102 ///
103 /// fRTC \[Hz\] = 32_768 / (`prescaler` + 1 )
104 pub fn new<T: Instance>(_rtc: Peri<'d, T>, prescaler: u32) -> Result<Self, PrescalerOutOfRangeError> {
105 if prescaler >= (1 << 12) {
106 return Err(PrescalerOutOfRangeError(prescaler));
107 }
108
109 T::regs().prescaler().write(|w| w.set_prescaler(prescaler as u16));
110 Ok(Self {
111 r: T::regs(),
112 irq: T::Interrupt::IRQ,
113 _phantom: PhantomData,
114 })
115 }
116
117 /// Create a new `Rtc` driver, configuring it to run at the given frequency.
118 pub fn new_for_freq<T: Instance>(rtc: Peri<'d, T>, freq_hz: u32) -> Result<Self, PrescalerOutOfRangeError> {
119 let prescaler = (32_768 / freq_hz).saturating_sub(1);
120 Self::new(rtc, prescaler)
121 }
122
123 /// Steal the RTC peripheral, without checking if it's already taken.
124 ///
125 /// # Safety
126 ///
127 /// Potentially allows to create multiple instances of the driver for the same peripheral
128 /// which can lead to undefined behavior.
129 pub unsafe fn steal<T: Instance>() -> Self {
130 Self {
131 r: T::regs(),
132 irq: T::Interrupt::IRQ,
133 _phantom: PhantomData,
134 }
135 }
136
137 /// Direct access to the RTC registers.
138 #[cfg(feature = "unstable-pac")]
139 #[inline]
140 pub fn regs(&mut self) -> pac::rtc::Rtc {
141 self.r
142 }
143
144 /// Enable the RTC.
145 #[inline]
146 pub fn enable(&mut self) {
147 self.r.tasks_start().write_value(1);
148 }
149
150 /// Disable the RTC.
151 #[inline]
152 pub fn disable(&mut self) {
153 self.r.tasks_stop().write_value(1);
154 }
155
156 /// Enables interrupts for the given [Interrupt] source.
157 ///
158 /// Optionally also enables the interrupt in the NVIC.
159 pub fn enable_interrupt(&mut self, int: Interrupt, enable_in_nvic: bool) {
160 let regs = self.r;
161 match int {
162 Interrupt::Tick => regs.intenset().write(|w| w.set_tick(true)),
163 Interrupt::Overflow => regs.intenset().write(|w| w.set_ovrflw(true)),
164 Interrupt::Compare0 => regs.intenset().write(|w| w.set_compare(0, true)),
165 Interrupt::Compare1 => regs.intenset().write(|w| w.set_compare(1, true)),
166 Interrupt::Compare2 => regs.intenset().write(|w| w.set_compare(2, true)),
167 Interrupt::Compare3 => regs.intenset().write(|w| w.set_compare(3, true)),
168 }
169 if enable_in_nvic {
170 unsafe { self.irq.enable() };
171 }
172 }
173
174 /// Disables interrupts for the given [Interrupt] source.
175 ///
176 /// Optionally also disables the interrupt in the NVIC.
177 pub fn disable_interrupt(&mut self, int: Interrupt, disable_in_nvic: bool) {
178 let regs = self.r;
179 match int {
180 Interrupt::Tick => regs.intenclr().write(|w| w.set_tick(true)),
181 Interrupt::Overflow => regs.intenclr().write(|w| w.set_ovrflw(true)),
182 Interrupt::Compare0 => regs.intenclr().write(|w| w.set_compare(0, true)),
183 Interrupt::Compare1 => regs.intenclr().write(|w| w.set_compare(1, true)),
184 Interrupt::Compare2 => regs.intenclr().write(|w| w.set_compare(2, true)),
185 Interrupt::Compare3 => regs.intenclr().write(|w| w.set_compare(3, true)),
186 }
187 if disable_in_nvic {
188 self.irq.disable();
189 }
190 }
191
192 /// Enable the generation of a hardware event from a given stimulus.
193 pub fn enable_event(&mut self, evt: Interrupt) {
194 let regs = self.r;
195 match evt {
196 Interrupt::Tick => regs.evtenset().write(|w| w.set_tick(true)),
197 Interrupt::Overflow => regs.evtenset().write(|w| w.set_ovrflw(true)),
198 Interrupt::Compare0 => regs.evtenset().write(|w| w.set_compare(0, true)),
199 Interrupt::Compare1 => regs.evtenset().write(|w| w.set_compare(1, true)),
200 Interrupt::Compare2 => regs.evtenset().write(|w| w.set_compare(2, true)),
201 Interrupt::Compare3 => regs.evtenset().write(|w| w.set_compare(3, true)),
202 }
203 }
204
205 /// Disable the generation of a hardware event from a given stimulus.
206 pub fn disable_event(&mut self, evt: Interrupt) {
207 let regs = self.r;
208 match evt {
209 Interrupt::Tick => regs.evtenclr().write(|w| w.set_tick(true)),
210 Interrupt::Overflow => regs.evtenclr().write(|w| w.set_ovrflw(true)),
211 Interrupt::Compare0 => regs.evtenclr().write(|w| w.set_compare(0, true)),
212 Interrupt::Compare1 => regs.evtenclr().write(|w| w.set_compare(1, true)),
213 Interrupt::Compare2 => regs.evtenclr().write(|w| w.set_compare(2, true)),
214 Interrupt::Compare3 => regs.evtenclr().write(|w| w.set_compare(3, true)),
215 }
216 }
217
218 /// Resets the given event.
219 pub fn reset_event(&mut self, evt: Interrupt) {
220 let regs = self.r;
221 match evt {
222 Interrupt::Tick => regs.events_tick().write_value(0),
223 Interrupt::Overflow => regs.events_ovrflw().write_value(0),
224 Interrupt::Compare0 => regs.events_compare(0).write_value(0),
225 Interrupt::Compare1 => regs.events_compare(1).write_value(0),
226 Interrupt::Compare2 => regs.events_compare(2).write_value(0),
227 Interrupt::Compare3 => regs.events_compare(3).write_value(0),
228 }
229 }
230
231 /// Checks if the given event has been triggered.
232 pub fn is_event_triggered(&self, evt: Interrupt) -> bool {
233 let regs = self.r;
234 let val = match evt {
235 Interrupt::Tick => regs.events_tick().read(),
236 Interrupt::Overflow => regs.events_ovrflw().read(),
237 Interrupt::Compare0 => regs.events_compare(0).read(),
238 Interrupt::Compare1 => regs.events_compare(1).read(),
239 Interrupt::Compare2 => regs.events_compare(2).read(),
240 Interrupt::Compare3 => regs.events_compare(3).read(),
241 };
242 val == 1
243 }
244
245 /// Set the compare value of a given register. The compare registers have a width
246 /// of 24 bits.
247 pub fn set_compare(&mut self, reg: CompareChannel, val: u32) -> Result<(), CompareOutOfRangeError> {
248 if val >= (1 << 24) {
249 return Err(CompareOutOfRangeError(val));
250 }
251
252 let reg = match reg {
253 CompareChannel::_0 => 0,
254 CompareChannel::_1 => 1,
255 CompareChannel::_2 => 2,
256 CompareChannel::_3 => 3,
257 };
258
259 self.r.cc(reg).write(|w| w.set_compare(val));
260 Ok(())
261 }
262
263 /// Clear the Real Time Counter.
264 #[inline]
265 pub fn clear(&self) {
266 self.r.tasks_clear().write_value(1);
267 }
268
269 /// Obtain the current value of the Real Time Counter, 24 bits of range.
270 #[inline]
271 pub fn read(&self) -> u32 {
272 self.r.counter().read().counter()
273 }
274}
diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs
index 92b6fb01f..fd48faabb 100644
--- a/embassy-nrf/src/saadc.rs
+++ b/embassy-nrf/src/saadc.rs
@@ -457,6 +457,19 @@ impl<'d> Saadc<'d, 1> {
457 457
458impl<'d, const N: usize> Drop for Saadc<'d, N> { 458impl<'d, const N: usize> Drop for Saadc<'d, N> {
459 fn drop(&mut self) { 459 fn drop(&mut self) {
460 // Reset of SAADC.
461 //
462 // This is needed when more than one pin is sampled to avoid needless power consumption.
463 // More information can be found in [nrf52 Anomaly 241](https://docs.nordicsemi.com/bundle/errata_nRF52810_Rev1/page/ERR/nRF52810/Rev1/latest/anomaly_810_241.html).
464 // The workaround seems like it copies the configuration before reset and reapplies it after.
465 // The instance is dropped, forcing a reconfiguration at compile time, hence we only
466 // call what is the reset portion of the workaround.
467 #[cfg(feature = "_nrf52")]
468 {
469 unsafe { core::ptr::write_volatile(0x40007FFC as *mut u32, 0) }
470 unsafe { core::ptr::read_volatile(0x40007FFC as *const ()) }
471 unsafe { core::ptr::write_volatile(0x40007FFC as *mut u32, 1) }
472 }
460 let r = Self::regs(); 473 let r = Self::regs();
461 r.enable().write(|w| w.set_enable(false)); 474 r.enable().write(|w| w.set_enable(false));
462 for i in 0..N { 475 for i in 0..N {
diff --git a/embassy-nrf/src/spim.rs b/embassy-nrf/src/spim.rs
index 59f5b6d58..c410e49fd 100644
--- a/embassy-nrf/src/spim.rs
+++ b/embassy-nrf/src/spim.rs
@@ -99,13 +99,16 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
99} 99}
100 100
101/// SPIM driver. 101/// SPIM driver.
102pub struct Spim<'d, T: Instance> { 102pub struct Spim<'d> {
103 _p: Peri<'d, T>, 103 r: pac::spim::Spim,
104 irq: interrupt::Interrupt,
105 state: &'static State,
106 _p: PhantomData<&'d ()>,
104} 107}
105 108
106impl<'d, T: Instance> Spim<'d, T> { 109impl<'d> Spim<'d> {
107 /// Create a new SPIM driver. 110 /// Create a new SPIM driver.
108 pub fn new( 111 pub fn new<T: Instance>(
109 spim: Peri<'d, T>, 112 spim: Peri<'d, T>,
110 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 113 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
111 sck: Peri<'d, impl GpioPin>, 114 sck: Peri<'d, impl GpioPin>,
@@ -117,7 +120,7 @@ impl<'d, T: Instance> Spim<'d, T> {
117 } 120 }
118 121
119 /// Create a new SPIM driver, capable of TX only (MOSI only). 122 /// Create a new SPIM driver, capable of TX only (MOSI only).
120 pub fn new_txonly( 123 pub fn new_txonly<T: Instance>(
121 spim: Peri<'d, T>, 124 spim: Peri<'d, T>,
122 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 125 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
123 sck: Peri<'d, impl GpioPin>, 126 sck: Peri<'d, impl GpioPin>,
@@ -128,7 +131,7 @@ impl<'d, T: Instance> Spim<'d, T> {
128 } 131 }
129 132
130 /// Create a new SPIM driver, capable of RX only (MISO only). 133 /// Create a new SPIM driver, capable of RX only (MISO only).
131 pub fn new_rxonly( 134 pub fn new_rxonly<T: Instance>(
132 spim: Peri<'d, T>, 135 spim: Peri<'d, T>,
133 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 136 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
134 sck: Peri<'d, impl GpioPin>, 137 sck: Peri<'d, impl GpioPin>,
@@ -139,7 +142,7 @@ impl<'d, T: Instance> Spim<'d, T> {
139 } 142 }
140 143
141 /// Create a new SPIM driver, capable of TX only (MOSI only), without SCK pin. 144 /// Create a new SPIM driver, capable of TX only (MOSI only), without SCK pin.
142 pub fn new_txonly_nosck( 145 pub fn new_txonly_nosck<T: Instance>(
143 spim: Peri<'d, T>, 146 spim: Peri<'d, T>,
144 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 147 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
145 mosi: Peri<'d, impl GpioPin>, 148 mosi: Peri<'d, impl GpioPin>,
@@ -148,8 +151,8 @@ impl<'d, T: Instance> Spim<'d, T> {
148 Self::new_inner(spim, None, None, Some(mosi.into()), config) 151 Self::new_inner(spim, None, None, Some(mosi.into()), config)
149 } 152 }
150 153
151 fn new_inner( 154 fn new_inner<T: Instance>(
152 spim: Peri<'d, T>, 155 _spim: Peri<'d, T>,
153 sck: Option<Peri<'d, AnyPin>>, 156 sck: Option<Peri<'d, AnyPin>>,
154 miso: Option<Peri<'d, AnyPin>>, 157 miso: Option<Peri<'d, AnyPin>>,
155 mosi: Option<Peri<'d, AnyPin>>, 158 mosi: Option<Peri<'d, AnyPin>>,
@@ -201,7 +204,12 @@ impl<'d, T: Instance> Spim<'d, T> {
201 // Enable SPIM instance. 204 // Enable SPIM instance.
202 r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); 205 r.enable().write(|w| w.set_enable(vals::Enable::ENABLED));
203 206
204 let mut spim = Self { _p: spim }; 207 let mut spim = Self {
208 r: T::regs(),
209 irq: T::Interrupt::IRQ,
210 state: T::state(),
211 _p: PhantomData {},
212 };
205 213
206 // Apply runtime peripheral configuration 214 // Apply runtime peripheral configuration
207 Self::set_config(&mut spim, &config).unwrap(); 215 Self::set_config(&mut spim, &config).unwrap();
@@ -218,7 +226,7 @@ impl<'d, T: Instance> Spim<'d, T> {
218 fn prepare_dma_transfer(&mut self, rx: *mut [u8], tx: *const [u8], offset: usize, length: usize) { 226 fn prepare_dma_transfer(&mut self, rx: *mut [u8], tx: *const [u8], offset: usize, length: usize) {
219 compiler_fence(Ordering::SeqCst); 227 compiler_fence(Ordering::SeqCst);
220 228
221 let r = T::regs(); 229 let r = self.r;
222 230
223 fn xfer_params(ptr: u32, total: usize, offset: usize, length: usize) -> (u32, usize) { 231 fn xfer_params(ptr: u32, total: usize, offset: usize, length: usize) -> (u32, usize) {
224 if total > offset { 232 if total > offset {
@@ -246,7 +254,7 @@ impl<'d, T: Instance> Spim<'d, T> {
246 254
247 #[cfg(feature = "_nrf52832_anomaly_109")] 255 #[cfg(feature = "_nrf52832_anomaly_109")]
248 if offset == 0 { 256 if offset == 0 {
249 let s = T::state(); 257 let s = self.state;
250 258
251 r.events_started().write_value(0); 259 r.events_started().write_value(0);
252 260
@@ -279,7 +287,7 @@ impl<'d, T: Instance> Spim<'d, T> {
279 } 287 }
280 288
281 // Wait for 'end' event. 289 // Wait for 'end' event.
282 while T::regs().events_end().read() == 0 {} 290 while self.r.events_end().read() == 0 {}
283 291
284 compiler_fence(Ordering::SeqCst); 292 compiler_fence(Ordering::SeqCst);
285 } 293 }
@@ -315,7 +323,7 @@ impl<'d, T: Instance> Spim<'d, T> {
315 #[cfg(feature = "_nrf52832_anomaly_109")] 323 #[cfg(feature = "_nrf52832_anomaly_109")]
316 if offset == 0 { 324 if offset == 0 {
317 poll_fn(|cx| { 325 poll_fn(|cx| {
318 let s = T::state(); 326 let s = self.state;
319 327
320 s.waker.register(cx.waker()); 328 s.waker.register(cx.waker());
321 329
@@ -326,8 +334,8 @@ impl<'d, T: Instance> Spim<'d, T> {
326 334
327 // Wait for 'end' event. 335 // Wait for 'end' event.
328 poll_fn(|cx| { 336 poll_fn(|cx| {
329 T::state().waker.register(cx.waker()); 337 self.state.waker.register(cx.waker());
330 if T::regs().events_end().read() != 0 { 338 if self.r.events_end().read() != 0 {
331 return Poll::Ready(()); 339 return Poll::Ready(());
332 } 340 }
333 341
@@ -430,9 +438,9 @@ impl<'d, T: Instance> Spim<'d, T> {
430 438
431 #[cfg(feature = "_nrf52832_anomaly_109")] 439 #[cfg(feature = "_nrf52832_anomaly_109")]
432 fn nrf52832_dma_workaround_status(&mut self) -> Poll<()> { 440 fn nrf52832_dma_workaround_status(&mut self) -> Poll<()> {
433 let r = T::regs(); 441 let r = self.r;
434 if r.events_started().read() != 0 { 442 if r.events_started().read() != 0 {
435 let s = T::state(); 443 let s = self.state;
436 444
437 // Handle the first "fake" transmission 445 // Handle the first "fake" transmission
438 r.events_started().write_value(0); 446 r.events_started().write_value(0);
@@ -451,14 +459,14 @@ impl<'d, T: Instance> Spim<'d, T> {
451 } 459 }
452} 460}
453 461
454impl<'d, T: Instance> Drop for Spim<'d, T> { 462impl<'d> Drop for Spim<'d> {
455 fn drop(&mut self) { 463 fn drop(&mut self) {
456 trace!("spim drop"); 464 trace!("spim drop");
457 465
458 // TODO check for abort, wait for xxxstopped 466 // TODO check for abort, wait for xxxstopped
459 467
460 // disable! 468 // disable!
461 let r = T::regs(); 469 let r = self.r;
462 r.enable().write(|w| w.set_enable(vals::Enable::DISABLED)); 470 r.enable().write(|w| w.set_enable(vals::Enable::DISABLED));
463 471
464 gpio::deconfigure_pin(r.psel().sck().read()); 472 gpio::deconfigure_pin(r.psel().sck().read());
@@ -466,7 +474,7 @@ impl<'d, T: Instance> Drop for Spim<'d, T> {
466 gpio::deconfigure_pin(r.psel().mosi().read()); 474 gpio::deconfigure_pin(r.psel().mosi().read());
467 475
468 // Disable all events interrupts 476 // Disable all events interrupts
469 T::Interrupt::disable(); 477 cortex_m::peripheral::NVIC::mask(self.irq);
470 478
471 trace!("spim drop: done"); 479 trace!("spim drop: done");
472 } 480 }
@@ -526,7 +534,7 @@ macro_rules! impl_spim {
526mod eh02 { 534mod eh02 {
527 use super::*; 535 use super::*;
528 536
529 impl<'d, T: Instance> embedded_hal_02::blocking::spi::Transfer<u8> for Spim<'d, T> { 537 impl<'d> embedded_hal_02::blocking::spi::Transfer<u8> for Spim<'d> {
530 type Error = Error; 538 type Error = Error;
531 fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { 539 fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
532 self.blocking_transfer_in_place(words)?; 540 self.blocking_transfer_in_place(words)?;
@@ -534,7 +542,7 @@ mod eh02 {
534 } 542 }
535 } 543 }
536 544
537 impl<'d, T: Instance> embedded_hal_02::blocking::spi::Write<u8> for Spim<'d, T> { 545 impl<'d> embedded_hal_02::blocking::spi::Write<u8> for Spim<'d> {
538 type Error = Error; 546 type Error = Error;
539 547
540 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { 548 fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
@@ -551,11 +559,11 @@ impl embedded_hal_1::spi::Error for Error {
551 } 559 }
552} 560}
553 561
554impl<'d, T: Instance> embedded_hal_1::spi::ErrorType for Spim<'d, T> { 562impl<'d> embedded_hal_1::spi::ErrorType for Spim<'d> {
555 type Error = Error; 563 type Error = Error;
556} 564}
557 565
558impl<'d, T: Instance> embedded_hal_1::spi::SpiBus<u8> for Spim<'d, T> { 566impl<'d> embedded_hal_1::spi::SpiBus<u8> for Spim<'d> {
559 fn flush(&mut self) -> Result<(), Self::Error> { 567 fn flush(&mut self) -> Result<(), Self::Error> {
560 Ok(()) 568 Ok(())
561 } 569 }
@@ -577,7 +585,7 @@ impl<'d, T: Instance> embedded_hal_1::spi::SpiBus<u8> for Spim<'d, T> {
577 } 585 }
578} 586}
579 587
580impl<'d, T: Instance> embedded_hal_async::spi::SpiBus<u8> for Spim<'d, T> { 588impl<'d> embedded_hal_async::spi::SpiBus<u8> for Spim<'d> {
581 async fn flush(&mut self) -> Result<(), Error> { 589 async fn flush(&mut self) -> Result<(), Error> {
582 Ok(()) 590 Ok(())
583 } 591 }
@@ -599,11 +607,11 @@ impl<'d, T: Instance> embedded_hal_async::spi::SpiBus<u8> for Spim<'d, T> {
599 } 607 }
600} 608}
601 609
602impl<'d, T: Instance> SetConfig for Spim<'d, T> { 610impl<'d> SetConfig for Spim<'d> {
603 type Config = Config; 611 type Config = Config;
604 type ConfigError = (); 612 type ConfigError = ();
605 fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { 613 fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
606 let r = T::regs(); 614 let r = self.r;
607 // Configure mode. 615 // Configure mode.
608 let mode = config.mode; 616 let mode = config.mode;
609 r.config().write(|w| { 617 r.config().write(|w| {
diff --git a/embassy-nrf/src/spis.rs b/embassy-nrf/src/spis.rs
index 2a3928d25..713163a55 100644
--- a/embassy-nrf/src/spis.rs
+++ b/embassy-nrf/src/spis.rs
@@ -96,14 +96,16 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
96 } 96 }
97} 97}
98 98
99/// SPIS driver. 99/// Serial Peripheral Interface in slave mode.
100pub struct Spis<'d, T: Instance> { 100pub struct Spis<'d> {
101 _p: Peri<'d, T>, 101 r: pac::spis::Spis,
102 state: &'static State,
103 _p: PhantomData<&'d ()>,
102} 104}
103 105
104impl<'d, T: Instance> Spis<'d, T> { 106impl<'d> Spis<'d> {
105 /// Create a new SPIS driver. 107 /// Create a new SPIS driver.
106 pub fn new( 108 pub fn new<T: Instance>(
107 spis: Peri<'d, T>, 109 spis: Peri<'d, T>,
108 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 110 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
109 cs: Peri<'d, impl GpioPin>, 111 cs: Peri<'d, impl GpioPin>,
@@ -123,7 +125,7 @@ impl<'d, T: Instance> Spis<'d, T> {
123 } 125 }
124 126
125 /// Create a new SPIS driver, capable of TX only (MISO only). 127 /// Create a new SPIS driver, capable of TX only (MISO only).
126 pub fn new_txonly( 128 pub fn new_txonly<T: Instance>(
127 spis: Peri<'d, T>, 129 spis: Peri<'d, T>,
128 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 130 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
129 cs: Peri<'d, impl GpioPin>, 131 cs: Peri<'d, impl GpioPin>,
@@ -135,7 +137,7 @@ impl<'d, T: Instance> Spis<'d, T> {
135 } 137 }
136 138
137 /// Create a new SPIS driver, capable of RX only (MOSI only). 139 /// Create a new SPIS driver, capable of RX only (MOSI only).
138 pub fn new_rxonly( 140 pub fn new_rxonly<T: Instance>(
139 spis: Peri<'d, T>, 141 spis: Peri<'d, T>,
140 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 142 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
141 cs: Peri<'d, impl GpioPin>, 143 cs: Peri<'d, impl GpioPin>,
@@ -147,7 +149,7 @@ impl<'d, T: Instance> Spis<'d, T> {
147 } 149 }
148 150
149 /// Create a new SPIS driver, capable of TX only (MISO only) without SCK pin. 151 /// Create a new SPIS driver, capable of TX only (MISO only) without SCK pin.
150 pub fn new_txonly_nosck( 152 pub fn new_txonly_nosck<T: Instance>(
151 spis: Peri<'d, T>, 153 spis: Peri<'d, T>,
152 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 154 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
153 cs: Peri<'d, impl GpioPin>, 155 cs: Peri<'d, impl GpioPin>,
@@ -157,8 +159,8 @@ impl<'d, T: Instance> Spis<'d, T> {
157 Self::new_inner(spis, cs.into(), None, Some(miso.into()), None, config) 159 Self::new_inner(spis, cs.into(), None, Some(miso.into()), None, config)
158 } 160 }
159 161
160 fn new_inner( 162 fn new_inner<T: Instance>(
161 spis: Peri<'d, T>, 163 _spis: Peri<'d, T>,
162 cs: Peri<'d, AnyPin>, 164 cs: Peri<'d, AnyPin>,
163 sck: Option<Peri<'d, AnyPin>>, 165 sck: Option<Peri<'d, AnyPin>>,
164 miso: Option<Peri<'d, AnyPin>>, 166 miso: Option<Peri<'d, AnyPin>>,
@@ -191,10 +193,14 @@ impl<'d, T: Instance> Spis<'d, T> {
191 // Enable SPIS instance. 193 // Enable SPIS instance.
192 r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); 194 r.enable().write(|w| w.set_enable(vals::Enable::ENABLED));
193 195
194 let mut spis = Self { _p: spis }; 196 let mut spis = Self {
197 r: T::regs(),
198 state: T::state(),
199 _p: PhantomData,
200 };
195 201
196 // Apply runtime peripheral configuration 202 // Apply runtime peripheral configuration
197 Self::set_config(&mut spis, &config).unwrap(); 203 spis.set_config(&config).unwrap();
198 204
199 // Disable all events interrupts. 205 // Disable all events interrupts.
200 r.intenclr().write(|w| w.0 = 0xFFFF_FFFF); 206 r.intenclr().write(|w| w.0 = 0xFFFF_FFFF);
@@ -212,7 +218,7 @@ impl<'d, T: Instance> Spis<'d, T> {
212 218
213 compiler_fence(Ordering::SeqCst); 219 compiler_fence(Ordering::SeqCst);
214 220
215 let r = T::regs(); 221 let r = self.r;
216 222
217 // Set up the DMA write. 223 // Set up the DMA write.
218 if tx.len() > EASY_DMA_SIZE { 224 if tx.len() > EASY_DMA_SIZE {
@@ -239,7 +245,7 @@ impl<'d, T: Instance> Spis<'d, T> {
239 245
240 fn blocking_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(usize, usize), Error> { 246 fn blocking_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(usize, usize), Error> {
241 compiler_fence(Ordering::SeqCst); 247 compiler_fence(Ordering::SeqCst);
242 let r = T::regs(); 248 let r = self.r;
243 249
244 // Acquire semaphore. 250 // Acquire semaphore.
245 if r.semstat().read().0 != 1 { 251 if r.semstat().read().0 != 1 {
@@ -276,8 +282,8 @@ impl<'d, T: Instance> Spis<'d, T> {
276 } 282 }
277 283
278 async fn async_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(usize, usize), Error> { 284 async fn async_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(usize, usize), Error> {
279 let r = T::regs(); 285 let r = self.r;
280 let s = T::state(); 286 let s = self.state;
281 287
282 // Clear status register. 288 // Clear status register.
283 r.status().write(|w| { 289 r.status().write(|w| {
@@ -420,21 +426,21 @@ impl<'d, T: Instance> Spis<'d, T> {
420 426
421 /// Checks if last transaction overread. 427 /// Checks if last transaction overread.
422 pub fn is_overread(&mut self) -> bool { 428 pub fn is_overread(&mut self) -> bool {
423 T::regs().status().read().overread() 429 self.r.status().read().overread()
424 } 430 }
425 431
426 /// Checks if last transaction overflowed. 432 /// Checks if last transaction overflowed.
427 pub fn is_overflow(&mut self) -> bool { 433 pub fn is_overflow(&mut self) -> bool {
428 T::regs().status().read().overflow() 434 self.r.status().read().overflow()
429 } 435 }
430} 436}
431 437
432impl<'d, T: Instance> Drop for Spis<'d, T> { 438impl<'d> Drop for Spis<'d> {
433 fn drop(&mut self) { 439 fn drop(&mut self) {
434 trace!("spis drop"); 440 trace!("spis drop");
435 441
436 // Disable 442 // Disable
437 let r = T::regs(); 443 let r = self.r;
438 r.enable().write(|w| w.set_enable(vals::Enable::DISABLED)); 444 r.enable().write(|w| w.set_enable(vals::Enable::DISABLED));
439 445
440 gpio::deconfigure_pin(r.psel().sck().read()); 446 gpio::deconfigure_pin(r.psel().sck().read());
@@ -489,11 +495,11 @@ macro_rules! impl_spis {
489 495
490// ==================== 496// ====================
491 497
492impl<'d, T: Instance> SetConfig for Spis<'d, T> { 498impl<'d> SetConfig for Spis<'d> {
493 type Config = Config; 499 type Config = Config;
494 type ConfigError = (); 500 type ConfigError = ();
495 fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { 501 fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
496 let r = T::regs(); 502 let r = self.r;
497 // Configure mode. 503 // Configure mode.
498 let mode = config.mode; 504 let mode = config.mode;
499 r.config().write(|w| { 505 r.config().write(|w| {
diff --git a/embassy-nrf/src/timer.rs b/embassy-nrf/src/timer.rs
index 5b58b0a50..0b0bb9780 100644
--- a/embassy-nrf/src/timer.rs
+++ b/embassy-nrf/src/timer.rs
@@ -6,6 +6,8 @@
6 6
7#![macro_use] 7#![macro_use]
8 8
9use core::marker::PhantomData;
10
9use embassy_hal_internal::{Peri, PeripheralType}; 11use embassy_hal_internal::{Peri, PeripheralType};
10 12
11use crate::pac; 13use crate::pac;
@@ -81,40 +83,44 @@ pub enum Frequency {
81/// 83///
82/// It has either 4 or 6 Capture/Compare registers, which can be used to capture the current state of the counter 84/// It has either 4 or 6 Capture/Compare registers, which can be used to capture the current state of the counter
83/// or trigger an event when the counter reaches a certain value. 85/// or trigger an event when the counter reaches a certain value.
84 86pub struct Timer<'d> {
85/// Timer driver. 87 r: pac::timer::Timer,
86pub struct Timer<'d, T: Instance> { 88 ccs: usize,
87 _p: Peri<'d, T>, 89 _p: PhantomData<&'d ()>,
88} 90}
89 91
90impl<'d, T: Instance> Timer<'d, T> { 92impl<'d> Timer<'d> {
91 /// Create a new `Timer` driver. 93 /// Create a new `Timer` driver.
92 /// 94 ///
93 /// This can be useful for triggering tasks via PPI 95 /// This can be useful for triggering tasks via PPI.
94 /// `Uarte` uses this internally. 96 /// `Uarte` uses this internally.
95 pub fn new(timer: Peri<'d, T>) -> Self { 97 pub fn new<T: Instance>(timer: Peri<'d, T>) -> Self {
96 Self::new_inner(timer, false) 98 Self::new_inner(timer, false)
97 } 99 }
98 100
99 /// Create a new `Timer` driver in counter mode. 101 /// Create a new `Timer` driver in counter mode.
100 /// 102 ///
101 /// This can be useful for triggering tasks via PPI 103 /// This can be useful for triggering tasks via PPI.
102 /// `Uarte` uses this internally. 104 /// `Uarte` uses this internally.
103 pub fn new_counter(timer: Peri<'d, T>) -> Self { 105 pub fn new_counter<T: Instance>(timer: Peri<'d, T>) -> Self {
104 Self::new_inner(timer, true) 106 Self::new_inner(timer, true)
105 } 107 }
106 108
107 fn new_inner(timer: Peri<'d, T>, _is_counter: bool) -> Self { 109 fn new_inner<T: Instance>(_timer: Peri<'d, T>, is_counter: bool) -> Self {
108 let regs = T::regs(); 110 let regs = T::regs();
109 111
110 let this = Self { _p: timer }; 112 let this = Self {
113 r: regs,
114 ccs: T::CCS,
115 _p: PhantomData,
116 };
111 117
112 // Stop the timer before doing anything else, 118 // Stop the timer before doing anything else,
113 // since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification. 119 // since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification.
114 this.stop(); 120 this.stop();
115 121
116 regs.mode().write(|w| { 122 regs.mode().write(|w| {
117 w.set_mode(match _is_counter { 123 w.set_mode(match is_counter {
118 #[cfg(not(feature = "_nrf51"))] 124 #[cfg(not(feature = "_nrf51"))]
119 true => vals::Mode::LOW_POWER_COUNTER, 125 true => vals::Mode::LOW_POWER_COUNTER,
120 #[cfg(feature = "_nrf51")] 126 #[cfg(feature = "_nrf51")]
@@ -133,7 +139,7 @@ impl<'d, T: Instance> Timer<'d, T> {
133 // Default to the max frequency of the lower power clock 139 // Default to the max frequency of the lower power clock
134 this.set_frequency(Frequency::F1MHz); 140 this.set_frequency(Frequency::F1MHz);
135 141
136 for n in 0..T::CCS { 142 for n in 0..this.ccs {
137 let cc = this.cc(n); 143 let cc = this.cc(n);
138 // Initialize all the shorts as disabled. 144 // Initialize all the shorts as disabled.
139 cc.unshort_compare_clear(); 145 cc.unshort_compare_clear();
@@ -145,40 +151,47 @@ impl<'d, T: Instance> Timer<'d, T> {
145 this 151 this
146 } 152 }
147 153
154 /// Direct access to the register block.
155 #[cfg(feature = "unstable-pac")]
156 #[inline]
157 pub fn regs(&mut self) -> pac::timer::Timer {
158 self.r
159 }
160
148 /// Starts the timer. 161 /// Starts the timer.
149 pub fn start(&self) { 162 pub fn start(&self) {
150 T::regs().tasks_start().write_value(1) 163 self.r.tasks_start().write_value(1)
151 } 164 }
152 165
153 /// Stops the timer. 166 /// Stops the timer.
154 pub fn stop(&self) { 167 pub fn stop(&self) {
155 T::regs().tasks_stop().write_value(1) 168 self.r.tasks_stop().write_value(1)
156 } 169 }
157 170
158 /// Reset the timer's counter to 0. 171 /// Reset the timer's counter to 0.
159 pub fn clear(&self) { 172 pub fn clear(&self) {
160 T::regs().tasks_clear().write_value(1) 173 self.r.tasks_clear().write_value(1)
161 } 174 }
162 175
163 /// Returns the START task, for use with PPI. 176 /// Returns the START task, for use with PPI.
164 /// 177 ///
165 /// When triggered, this task starts the timer. 178 /// When triggered, this task starts the timer.
166 pub fn task_start(&self) -> Task<'d> { 179 pub fn task_start(&self) -> Task<'d> {
167 Task::from_reg(T::regs().tasks_start()) 180 Task::from_reg(self.r.tasks_start())
168 } 181 }
169 182
170 /// Returns the STOP task, for use with PPI. 183 /// Returns the STOP task, for use with PPI.
171 /// 184 ///
172 /// When triggered, this task stops the timer. 185 /// When triggered, this task stops the timer.
173 pub fn task_stop(&self) -> Task<'d> { 186 pub fn task_stop(&self) -> Task<'d> {
174 Task::from_reg(T::regs().tasks_stop()) 187 Task::from_reg(self.r.tasks_stop())
175 } 188 }
176 189
177 /// Returns the CLEAR task, for use with PPI. 190 /// Returns the CLEAR task, for use with PPI.
178 /// 191 ///
179 /// When triggered, this task resets the timer's counter to 0. 192 /// When triggered, this task resets the timer's counter to 0.
180 pub fn task_clear(&self) -> Task<'d> { 193 pub fn task_clear(&self) -> Task<'d> {
181 Task::from_reg(T::regs().tasks_clear()) 194 Task::from_reg(self.r.tasks_clear())
182 } 195 }
183 196
184 /// Returns the COUNT task, for use with PPI. 197 /// Returns the COUNT task, for use with PPI.
@@ -186,7 +199,7 @@ impl<'d, T: Instance> Timer<'d, T> {
186 /// When triggered, this task increments the timer's counter by 1. 199 /// When triggered, this task increments the timer's counter by 1.
187 /// Only works in counter mode. 200 /// Only works in counter mode.
188 pub fn task_count(&self) -> Task<'d> { 201 pub fn task_count(&self) -> Task<'d> {
189 Task::from_reg(T::regs().tasks_count()) 202 Task::from_reg(self.r.tasks_count())
190 } 203 }
191 204
192 /// Change the timer's frequency. 205 /// Change the timer's frequency.
@@ -196,7 +209,7 @@ impl<'d, T: Instance> Timer<'d, T> {
196 pub fn set_frequency(&self, frequency: Frequency) { 209 pub fn set_frequency(&self, frequency: Frequency) {
197 self.stop(); 210 self.stop();
198 211
199 T::regs() 212 self.r
200 .prescaler() 213 .prescaler()
201 // SAFETY: `frequency` is a variant of `Frequency`, 214 // SAFETY: `frequency` is a variant of `Frequency`,
202 // whose values are all in the range of 0-9 (the valid range of `prescaler`). 215 // whose values are all in the range of 0-9 (the valid range of `prescaler`).
@@ -207,17 +220,33 @@ impl<'d, T: Instance> Timer<'d, T> {
207 /// 220 ///
208 /// # Panics 221 /// # Panics
209 /// Panics if `n` >= the number of CC registers this timer has (4 for a normal timer, 6 for an extended timer). 222 /// Panics if `n` >= the number of CC registers this timer has (4 for a normal timer, 6 for an extended timer).
210 pub fn cc(&self, n: usize) -> Cc<'d, T> { 223 pub fn cc(&self, n: usize) -> Cc<'d> {
211 if n >= T::CCS { 224 if n >= self.ccs {
212 panic!("Cannot get CC register {} of timer with {} CC registers.", n, T::CCS); 225 panic!("Cannot get CC register {} of timer with {} CC registers.", n, self.ccs);
213 } 226 }
214 Cc { 227 Cc {
215 n, 228 n,
216 _p: unsafe { self._p.clone_unchecked() }, 229 r: self.r,
230 _p: PhantomData,
217 } 231 }
218 } 232 }
219} 233}
220 234
235impl Timer<'static> {
236 /// Persist the timer's configuration for the rest of the program's lifetime. This method
237 /// should be preferred over [`core::mem::forget()`] because the `'static` bound prevents
238 /// accidental reuse of the underlying peripheral.
239 pub fn persist(self) {
240 core::mem::forget(self);
241 }
242}
243
244impl<'d> Drop for Timer<'d> {
245 fn drop(&mut self) {
246 self.stop();
247 }
248}
249
221/// A representation of a timer's Capture/Compare (CC) register. 250/// A representation of a timer's Capture/Compare (CC) register.
222/// 251///
223/// A CC register holds a 32-bit value. 252/// A CC register holds a 32-bit value.
@@ -225,27 +254,28 @@ impl<'d, T: Instance> Timer<'d, T> {
225/// 254///
226/// The timer will fire the register's COMPARE event when its counter reaches the value stored in the register. 255/// The timer will fire the register's COMPARE event when its counter reaches the value stored in the register.
227/// When the register's CAPTURE task is triggered, the timer will store the current value of its counter in the register 256/// When the register's CAPTURE task is triggered, the timer will store the current value of its counter in the register
228pub struct Cc<'d, T: Instance> { 257pub struct Cc<'d> {
229 n: usize, 258 n: usize,
230 _p: Peri<'d, T>, 259 r: pac::timer::Timer,
260 _p: PhantomData<&'d ()>,
231} 261}
232 262
233impl<'d, T: Instance> Cc<'d, T> { 263impl<'d> Cc<'d> {
234 /// Get the current value stored in the register. 264 /// Get the current value stored in the register.
235 pub fn read(&self) -> u32 { 265 pub fn read(&self) -> u32 {
236 return T::regs().cc(self.n).read(); 266 self.r.cc(self.n).read()
237 } 267 }
238 268
239 /// Set the value stored in the register. 269 /// Set the value stored in the register.
240 /// 270 ///
241 /// `event_compare` will fire when the timer's counter reaches this value. 271 /// `event_compare` will fire when the timer's counter reaches this value.
242 pub fn write(&self, value: u32) { 272 pub fn write(&self, value: u32) {
243 T::regs().cc(self.n).write_value(value); 273 self.r.cc(self.n).write_value(value);
244 } 274 }
245 275
246 /// Capture the current value of the timer's counter in this register, and return it. 276 /// Capture the current value of the timer's counter in this register, and return it.
247 pub fn capture(&self) -> u32 { 277 pub fn capture(&self) -> u32 {
248 T::regs().tasks_capture(self.n).write_value(1); 278 self.r.tasks_capture(self.n).write_value(1);
249 self.read() 279 self.read()
250 } 280 }
251 281
@@ -253,14 +283,20 @@ impl<'d, T: Instance> Cc<'d, T> {
253 /// 283 ///
254 /// When triggered, this task will capture the current value of the timer's counter in this register. 284 /// When triggered, this task will capture the current value of the timer's counter in this register.
255 pub fn task_capture(&self) -> Task<'d> { 285 pub fn task_capture(&self) -> Task<'d> {
256 Task::from_reg(T::regs().tasks_capture(self.n)) 286 Task::from_reg(self.r.tasks_capture(self.n))
257 } 287 }
258 288
259 /// Returns this CC register's COMPARE event, for use with PPI. 289 /// Returns this CC register's COMPARE event, for use with PPI.
260 /// 290 ///
261 /// This event will fire when the timer's counter reaches the value in this CC register. 291 /// This event will fire when the timer's counter reaches the value in this CC register.
262 pub fn event_compare(&self) -> Event<'d> { 292 pub fn event_compare(&self) -> Event<'d> {
263 Event::from_reg(T::regs().events_compare(self.n)) 293 Event::from_reg(self.r.events_compare(self.n))
294 }
295
296 /// Clear the COMPARE event for this CC register.
297 #[inline]
298 pub fn clear_events(&self) {
299 self.r.events_compare(self.n).write_value(0);
264 } 300 }
265 301
266 /// Enable the shortcut between this CC register's COMPARE event and the timer's CLEAR task. 302 /// Enable the shortcut between this CC register's COMPARE event and the timer's CLEAR task.
@@ -269,12 +305,12 @@ impl<'d, T: Instance> Cc<'d, T> {
269 /// 305 ///
270 /// So, when the timer's counter reaches the value stored in this register, the timer's counter will be reset to 0. 306 /// So, when the timer's counter reaches the value stored in this register, the timer's counter will be reset to 0.
271 pub fn short_compare_clear(&self) { 307 pub fn short_compare_clear(&self) {
272 T::regs().shorts().modify(|w| w.set_compare_clear(self.n, true)) 308 self.r.shorts().modify(|w| w.set_compare_clear(self.n, true))
273 } 309 }
274 310
275 /// Disable the shortcut between this CC register's COMPARE event and the timer's CLEAR task. 311 /// Disable the shortcut between this CC register's COMPARE event and the timer's CLEAR task.
276 pub fn unshort_compare_clear(&self) { 312 pub fn unshort_compare_clear(&self) {
277 T::regs().shorts().modify(|w| w.set_compare_clear(self.n, false)) 313 self.r.shorts().modify(|w| w.set_compare_clear(self.n, false))
278 } 314 }
279 315
280 /// Enable the shortcut between this CC register's COMPARE event and the timer's STOP task. 316 /// Enable the shortcut between this CC register's COMPARE event and the timer's STOP task.
@@ -283,11 +319,11 @@ impl<'d, T: Instance> Cc<'d, T> {
283 /// 319 ///
284 /// So, when the timer's counter reaches the value stored in this register, the timer will stop counting up. 320 /// So, when the timer's counter reaches the value stored in this register, the timer will stop counting up.
285 pub fn short_compare_stop(&self) { 321 pub fn short_compare_stop(&self) {
286 T::regs().shorts().modify(|w| w.set_compare_stop(self.n, true)) 322 self.r.shorts().modify(|w| w.set_compare_stop(self.n, true))
287 } 323 }
288 324
289 /// Disable the shortcut between this CC register's COMPARE event and the timer's STOP task. 325 /// Disable the shortcut between this CC register's COMPARE event and the timer's STOP task.
290 pub fn unshort_compare_stop(&self) { 326 pub fn unshort_compare_stop(&self) {
291 T::regs().shorts().modify(|w| w.set_compare_stop(self.n, false)) 327 self.r.shorts().modify(|w| w.set_compare_stop(self.n, false))
292 } 328 }
293} 329}
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs
index 3d5e841d1..943ea9d31 100644
--- a/embassy-nrf/src/twim.rs
+++ b/embassy-nrf/src/twim.rs
@@ -2,7 +2,7 @@
2 2
3#![macro_use] 3#![macro_use]
4 4
5use core::future::{poll_fn, Future}; 5use core::future::poll_fn;
6use core::marker::PhantomData; 6use core::marker::PhantomData;
7use core::sync::atomic::compiler_fence; 7use core::sync::atomic::compiler_fence;
8use core::sync::atomic::Ordering::SeqCst; 8use core::sync::atomic::Ordering::SeqCst;
@@ -112,12 +112,14 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
112} 112}
113 113
114/// TWI driver. 114/// TWI driver.
115pub struct Twim<'d, T: Instance> { 115pub struct Twim<'d> {
116 _p: Peri<'d, T>, 116 r: pac::twim::Twim,
117 state: &'static State,
117 tx_ram_buffer: &'d mut [u8], 118 tx_ram_buffer: &'d mut [u8],
119 _p: PhantomData<&'d ()>,
118} 120}
119 121
120impl<'d, T: Instance> Twim<'d, T> { 122impl<'d> Twim<'d> {
121 /// Create a new TWI driver. 123 /// Create a new TWI driver.
122 /// 124 ///
123 /// `tx_ram_buffer` is required if any write operations will be performed with data that is not in RAM. 125 /// `tx_ram_buffer` is required if any write operations will be performed with data that is not in RAM.
@@ -125,8 +127,8 @@ impl<'d, T: Instance> Twim<'d, T> {
125 /// needs to be at least as large as the largest write operation that will be executed with a buffer 127 /// needs to be at least as large as the largest write operation that will be executed with a buffer
126 /// that is not in RAM. If all write operations will be performed from RAM, an empty buffer (`&[]`) may 128 /// that is not in RAM. If all write operations will be performed from RAM, an empty buffer (`&[]`) may
127 /// be used. 129 /// be used.
128 pub fn new( 130 pub fn new<T: Instance>(
129 twim: Peri<'d, T>, 131 _twim: Peri<'d, T>,
130 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 132 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
131 sda: Peri<'d, impl GpioPin>, 133 sda: Peri<'d, impl GpioPin>,
132 scl: Peri<'d, impl GpioPin>, 134 scl: Peri<'d, impl GpioPin>,
@@ -167,8 +169,10 @@ impl<'d, T: Instance> Twim<'d, T> {
167 r.enable().write(|w| w.set_enable(vals::Enable::ENABLED)); 169 r.enable().write(|w| w.set_enable(vals::Enable::ENABLED));
168 170
169 let mut twim = Self { 171 let mut twim = Self {
170 _p: twim, 172 r: T::regs(),
173 state: T::state(),
171 tx_ram_buffer, 174 tx_ram_buffer,
175 _p: PhantomData {},
172 }; 176 };
173 177
174 // Apply runtime peripheral configuration 178 // Apply runtime peripheral configuration
@@ -201,7 +205,7 @@ impl<'d, T: Instance> Twim<'d, T> {
201 return Err(Error::TxBufferTooLong); 205 return Err(Error::TxBufferTooLong);
202 } 206 }
203 207
204 let r = T::regs(); 208 let r = self.r;
205 209
206 // We're giving the register a pointer to the stack. Since we're 210 // We're giving the register a pointer to the stack. Since we're
207 // waiting for the I2C transaction to end before this stack pointer 211 // waiting for the I2C transaction to end before this stack pointer
@@ -228,7 +232,7 @@ impl<'d, T: Instance> Twim<'d, T> {
228 return Err(Error::RxBufferTooLong); 232 return Err(Error::RxBufferTooLong);
229 } 233 }
230 234
231 let r = T::regs(); 235 let r = self.r;
232 236
233 // We're giving the register a pointer to the stack. Since we're 237 // We're giving the register a pointer to the stack. Since we're
234 // waiting for the I2C transaction to end before this stack pointer 238 // waiting for the I2C transaction to end before this stack pointer
@@ -250,7 +254,7 @@ impl<'d, T: Instance> Twim<'d, T> {
250 } 254 }
251 255
252 fn clear_errorsrc(&mut self) { 256 fn clear_errorsrc(&mut self) {
253 let r = T::regs(); 257 let r = self.r;
254 r.errorsrc().write(|w| { 258 r.errorsrc().write(|w| {
255 w.set_anack(true); 259 w.set_anack(true);
256 w.set_dnack(true); 260 w.set_dnack(true);
@@ -259,8 +263,8 @@ impl<'d, T: Instance> Twim<'d, T> {
259 } 263 }
260 264
261 /// Get Error instance, if any occurred. 265 /// Get Error instance, if any occurred.
262 fn check_errorsrc() -> Result<(), Error> { 266 fn check_errorsrc(&mut self) -> Result<(), Error> {
263 let r = T::regs(); 267 let r = self.r;
264 268
265 let err = r.errorsrc().read(); 269 let err = r.errorsrc().read();
266 if err.anack() { 270 if err.anack() {
@@ -276,7 +280,7 @@ impl<'d, T: Instance> Twim<'d, T> {
276 } 280 }
277 281
278 fn check_rx(&self, len: usize) -> Result<(), Error> { 282 fn check_rx(&self, len: usize) -> Result<(), Error> {
279 let r = T::regs(); 283 let r = self.r;
280 if r.rxd().amount().read().0 != len as u32 { 284 if r.rxd().amount().read().0 != len as u32 {
281 Err(Error::Receive) 285 Err(Error::Receive)
282 } else { 286 } else {
@@ -285,7 +289,7 @@ impl<'d, T: Instance> Twim<'d, T> {
285 } 289 }
286 290
287 fn check_tx(&self, len: usize) -> Result<(), Error> { 291 fn check_tx(&self, len: usize) -> Result<(), Error> {
288 let r = T::regs(); 292 let r = self.r;
289 if r.txd().amount().read().0 != len as u32 { 293 if r.txd().amount().read().0 != len as u32 {
290 Err(Error::Transmit) 294 Err(Error::Transmit)
291 } else { 295 } else {
@@ -295,7 +299,7 @@ impl<'d, T: Instance> Twim<'d, T> {
295 299
296 /// Wait for stop or error 300 /// Wait for stop or error
297 fn blocking_wait(&mut self) { 301 fn blocking_wait(&mut self) {
298 let r = T::regs(); 302 let r = self.r;
299 loop { 303 loop {
300 if r.events_suspended().read() != 0 || r.events_stopped().read() != 0 { 304 if r.events_suspended().read() != 0 || r.events_stopped().read() != 0 {
301 r.events_suspended().write_value(0); 305 r.events_suspended().write_value(0);
@@ -312,7 +316,7 @@ impl<'d, T: Instance> Twim<'d, T> {
312 /// Wait for stop or error 316 /// Wait for stop or error
313 #[cfg(feature = "time")] 317 #[cfg(feature = "time")]
314 fn blocking_wait_timeout(&mut self, timeout: Duration) -> Result<(), Error> { 318 fn blocking_wait_timeout(&mut self, timeout: Duration) -> Result<(), Error> {
315 let r = T::regs(); 319 let r = self.r;
316 let deadline = Instant::now() + timeout; 320 let deadline = Instant::now() + timeout;
317 loop { 321 loop {
318 if r.events_suspended().read() != 0 || r.events_stopped().read() != 0 { 322 if r.events_suspended().read() != 0 || r.events_stopped().read() != 0 {
@@ -333,10 +337,10 @@ impl<'d, T: Instance> Twim<'d, T> {
333 } 337 }
334 338
335 /// Wait for stop or error 339 /// Wait for stop or error
336 fn async_wait(&mut self) -> impl Future<Output = Result<(), Error>> { 340 async fn async_wait(&mut self) -> Result<(), Error> {
337 poll_fn(move |cx| { 341 poll_fn(|cx| {
338 let r = T::regs(); 342 let r = self.r;
339 let s = T::state(); 343 let s = self.state;
340 344
341 s.end_waker.register(cx.waker()); 345 s.end_waker.register(cx.waker());
342 if r.events_suspended().read() != 0 || r.events_stopped().read() != 0 { 346 if r.events_suspended().read() != 0 || r.events_stopped().read() != 0 {
@@ -349,15 +353,16 @@ impl<'d, T: Instance> Twim<'d, T> {
349 if r.events_error().read() != 0 { 353 if r.events_error().read() != 0 {
350 r.events_error().write_value(0); 354 r.events_error().write_value(0);
351 r.tasks_stop().write_value(1); 355 r.tasks_stop().write_value(1);
352 if let Err(e) = Self::check_errorsrc() { 356 if let Err(e) = self.check_errorsrc() {
353 return Poll::Ready(Err(e)); 357 return Poll::Ready(Err(e));
354 } else { 358 } else {
355 panic!("Found events_error bit without an error in errorsrc reg"); 359 return Poll::Ready(Err(Error::Timeout));
356 } 360 }
357 } 361 }
358 362
359 Poll::Pending 363 Poll::Pending
360 }) 364 })
365 .await
361 } 366 }
362 367
363 fn setup_operations( 368 fn setup_operations(
@@ -367,7 +372,7 @@ impl<'d, T: Instance> Twim<'d, T> {
367 last_op: Option<&Operation<'_>>, 372 last_op: Option<&Operation<'_>>,
368 inten: bool, 373 inten: bool,
369 ) -> Result<usize, Error> { 374 ) -> Result<usize, Error> {
370 let r = T::regs(); 375 let r = self.r;
371 376
372 compiler_fence(SeqCst); 377 compiler_fence(SeqCst);
373 378
@@ -511,7 +516,7 @@ impl<'d, T: Instance> Twim<'d, T> {
511 516
512 fn check_operations(&mut self, operations: &[Operation<'_>]) -> Result<(), Error> { 517 fn check_operations(&mut self, operations: &[Operation<'_>]) -> Result<(), Error> {
513 compiler_fence(SeqCst); 518 compiler_fence(SeqCst);
514 Self::check_errorsrc()?; 519 self.check_errorsrc()?;
515 520
516 assert!(operations.len() == 1 || operations.len() == 2); 521 assert!(operations.len() == 1 || operations.len() == 2);
517 match operations { 522 match operations {
@@ -558,7 +563,7 @@ impl<'d, T: Instance> Twim<'d, T> {
558 563
559 /// Execute the provided operations on the I2C bus with timeout. 564 /// Execute the provided operations on the I2C bus with timeout.
560 /// 565 ///
561 /// See [`blocking_transaction`]. 566 /// See [Self::blocking_transaction].
562 #[cfg(feature = "time")] 567 #[cfg(feature = "time")]
563 pub fn blocking_transaction_timeout( 568 pub fn blocking_transaction_timeout(
564 &mut self, 569 &mut self,
@@ -632,7 +637,7 @@ impl<'d, T: Instance> Twim<'d, T> {
632 637
633 /// Write to an I2C slave with timeout. 638 /// Write to an I2C slave with timeout.
634 /// 639 ///
635 /// See [`blocking_write`]. 640 /// See [Self::blocking_write].
636 #[cfg(feature = "time")] 641 #[cfg(feature = "time")]
637 pub fn blocking_write_timeout(&mut self, address: u8, buffer: &[u8], timeout: Duration) -> Result<(), Error> { 642 pub fn blocking_write_timeout(&mut self, address: u8, buffer: &[u8], timeout: Duration) -> Result<(), Error> {
638 self.blocking_transaction_timeout(address, &mut [Operation::Write(buffer)], timeout) 643 self.blocking_transaction_timeout(address, &mut [Operation::Write(buffer)], timeout)
@@ -696,14 +701,14 @@ impl<'d, T: Instance> Twim<'d, T> {
696 } 701 }
697} 702}
698 703
699impl<'a, T: Instance> Drop for Twim<'a, T> { 704impl<'a> Drop for Twim<'a> {
700 fn drop(&mut self) { 705 fn drop(&mut self) {
701 trace!("twim drop"); 706 trace!("twim drop");
702 707
703 // TODO: check for abort 708 // TODO: check for abort
704 709
705 // disable! 710 // disable!
706 let r = T::regs(); 711 let r = self.r;
707 r.enable().write(|w| w.set_enable(vals::Enable::DISABLED)); 712 r.enable().write(|w| w.set_enable(vals::Enable::DISABLED));
708 713
709 gpio::deconfigure_pin(r.psel().sda().read()); 714 gpio::deconfigure_pin(r.psel().sda().read());
@@ -759,7 +764,7 @@ macro_rules! impl_twim {
759mod eh02 { 764mod eh02 {
760 use super::*; 765 use super::*;
761 766
762 impl<'a, T: Instance> embedded_hal_02::blocking::i2c::Write for Twim<'a, T> { 767 impl<'a> embedded_hal_02::blocking::i2c::Write for Twim<'a> {
763 type Error = Error; 768 type Error = Error;
764 769
765 fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> { 770 fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
@@ -767,7 +772,7 @@ mod eh02 {
767 } 772 }
768 } 773 }
769 774
770 impl<'a, T: Instance> embedded_hal_02::blocking::i2c::Read for Twim<'a, T> { 775 impl<'a> embedded_hal_02::blocking::i2c::Read for Twim<'a> {
771 type Error = Error; 776 type Error = Error;
772 777
773 fn read(&mut self, addr: u8, bytes: &mut [u8]) -> Result<(), Error> { 778 fn read(&mut self, addr: u8, bytes: &mut [u8]) -> Result<(), Error> {
@@ -775,7 +780,7 @@ mod eh02 {
775 } 780 }
776 } 781 }
777 782
778 impl<'a, T: Instance> embedded_hal_02::blocking::i2c::WriteRead for Twim<'a, T> { 783 impl<'a> embedded_hal_02::blocking::i2c::WriteRead for Twim<'a> {
779 type Error = Error; 784 type Error = Error;
780 785
781 fn write_read<'w>(&mut self, addr: u8, bytes: &'w [u8], buffer: &'w mut [u8]) -> Result<(), Error> { 786 fn write_read<'w>(&mut self, addr: u8, bytes: &'w [u8], buffer: &'w mut [u8]) -> Result<(), Error> {
@@ -804,27 +809,27 @@ impl embedded_hal_1::i2c::Error for Error {
804 } 809 }
805} 810}
806 811
807impl<'d, T: Instance> embedded_hal_1::i2c::ErrorType for Twim<'d, T> { 812impl<'d> embedded_hal_1::i2c::ErrorType for Twim<'d> {
808 type Error = Error; 813 type Error = Error;
809} 814}
810 815
811impl<'d, T: Instance> embedded_hal_1::i2c::I2c for Twim<'d, T> { 816impl<'d> embedded_hal_1::i2c::I2c for Twim<'d> {
812 fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> { 817 fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> {
813 self.blocking_transaction(address, operations) 818 self.blocking_transaction(address, operations)
814 } 819 }
815} 820}
816 821
817impl<'d, T: Instance> embedded_hal_async::i2c::I2c for Twim<'d, T> { 822impl<'d> embedded_hal_async::i2c::I2c for Twim<'d> {
818 async fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> { 823 async fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> {
819 self.transaction(address, operations).await 824 self.transaction(address, operations).await
820 } 825 }
821} 826}
822 827
823impl<'d, T: Instance> SetConfig for Twim<'d, T> { 828impl<'d> SetConfig for Twim<'d> {
824 type Config = Config; 829 type Config = Config;
825 type ConfigError = (); 830 type ConfigError = ();
826 fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { 831 fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
827 let r = T::regs(); 832 let r = self.r;
828 r.frequency().write(|w| w.set_frequency(config.frequency)); 833 r.frequency().write(|w| w.set_frequency(config.frequency));
829 834
830 Ok(()) 835 Ok(())
diff --git a/embassy-nrf/src/twis.rs b/embassy-nrf/src/twis.rs
index 3e4d537ae..dd4978b3e 100644
--- a/embassy-nrf/src/twis.rs
+++ b/embassy-nrf/src/twis.rs
@@ -140,14 +140,16 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
140} 140}
141 141
142/// TWIS driver. 142/// TWIS driver.
143pub struct Twis<'d, T: Instance> { 143pub struct Twis<'d> {
144 _p: Peri<'d, T>, 144 r: pac::twis::Twis,
145 state: &'static State,
146 _p: PhantomData<&'d ()>,
145} 147}
146 148
147impl<'d, T: Instance> Twis<'d, T> { 149impl<'d> Twis<'d> {
148 /// Create a new TWIS driver. 150 /// Create a new TWIS driver.
149 pub fn new( 151 pub fn new<T: Instance>(
150 twis: Peri<'d, T>, 152 _twis: Peri<'d, T>,
151 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 153 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
152 sda: Peri<'d, impl GpioPin>, 154 sda: Peri<'d, impl GpioPin>,
153 scl: Peri<'d, impl GpioPin>, 155 scl: Peri<'d, impl GpioPin>,
@@ -206,7 +208,11 @@ impl<'d, T: Instance> Twis<'d, T> {
206 T::Interrupt::unpend(); 208 T::Interrupt::unpend();
207 unsafe { T::Interrupt::enable() }; 209 unsafe { T::Interrupt::enable() };
208 210
209 Self { _p: twis } 211 Self {
212 r: T::regs(),
213 state: T::state(),
214 _p: PhantomData,
215 }
210 } 216 }
211 217
212 /// Set TX buffer, checking that it is in RAM and has suitable length. 218 /// Set TX buffer, checking that it is in RAM and has suitable length.
@@ -217,7 +223,7 @@ impl<'d, T: Instance> Twis<'d, T> {
217 return Err(Error::TxBufferTooLong); 223 return Err(Error::TxBufferTooLong);
218 } 224 }
219 225
220 let r = T::regs(); 226 let r = self.r;
221 227
222 // We're giving the register a pointer to the stack. Since we're 228 // We're giving the register a pointer to the stack. Since we're
223 // waiting for the I2C transaction to end before this stack pointer 229 // waiting for the I2C transaction to end before this stack pointer
@@ -244,7 +250,7 @@ impl<'d, T: Instance> Twis<'d, T> {
244 return Err(Error::RxBufferTooLong); 250 return Err(Error::RxBufferTooLong);
245 } 251 }
246 252
247 let r = T::regs(); 253 let r = self.r;
248 254
249 // We're giving the register a pointer to the stack. Since we're 255 // We're giving the register a pointer to the stack. Since we're
250 // waiting for the I2C transaction to end before this stack pointer 256 // waiting for the I2C transaction to end before this stack pointer
@@ -266,7 +272,7 @@ impl<'d, T: Instance> Twis<'d, T> {
266 } 272 }
267 273
268 fn clear_errorsrc(&mut self) { 274 fn clear_errorsrc(&mut self) {
269 let r = T::regs(); 275 let r = self.r;
270 r.errorsrc().write(|w| { 276 r.errorsrc().write(|w| {
271 w.set_overflow(true); 277 w.set_overflow(true);
272 w.set_overread(true); 278 w.set_overread(true);
@@ -276,18 +282,18 @@ impl<'d, T: Instance> Twis<'d, T> {
276 282
277 /// Returns matched address for latest command. 283 /// Returns matched address for latest command.
278 pub fn address_match(&self) -> u8 { 284 pub fn address_match(&self) -> u8 {
279 let r = T::regs(); 285 let r = self.r;
280 r.address(r.match_().read().0 as usize).read().address() 286 r.address(r.match_().read().0 as usize).read().address()
281 } 287 }
282 288
283 /// Returns the index of the address matched in the latest command. 289 /// Returns the index of the address matched in the latest command.
284 pub fn address_match_index(&self) -> usize { 290 pub fn address_match_index(&self) -> usize {
285 T::regs().match_().read().0 as _ 291 self.r.match_().read().0 as _
286 } 292 }
287 293
288 /// Wait for read, write, stop or error 294 /// Wait for read, write, stop or error
289 fn blocking_listen_wait(&mut self) -> Result<Status, Error> { 295 fn blocking_listen_wait(&mut self) -> Result<Status, Error> {
290 let r = T::regs(); 296 let r = self.r;
291 loop { 297 loop {
292 if r.events_error().read() != 0 { 298 if r.events_error().read() != 0 {
293 r.events_error().write_value(0); 299 r.events_error().write_value(0);
@@ -312,7 +318,7 @@ impl<'d, T: Instance> Twis<'d, T> {
312 318
313 /// Wait for stop, repeated start or error 319 /// Wait for stop, repeated start or error
314 fn blocking_listen_wait_end(&mut self, status: Status) -> Result<Command, Error> { 320 fn blocking_listen_wait_end(&mut self, status: Status) -> Result<Command, Error> {
315 let r = T::regs(); 321 let r = self.r;
316 loop { 322 loop {
317 // stop if an error occurred 323 // stop if an error occurred
318 if r.events_error().read() != 0 { 324 if r.events_error().read() != 0 {
@@ -338,7 +344,7 @@ impl<'d, T: Instance> Twis<'d, T> {
338 344
339 /// Wait for stop or error 345 /// Wait for stop or error
340 fn blocking_wait(&mut self) -> Result<usize, Error> { 346 fn blocking_wait(&mut self) -> Result<usize, Error> {
341 let r = T::regs(); 347 let r = self.r;
342 loop { 348 loop {
343 // stop if an error occurred 349 // stop if an error occurred
344 if r.events_error().read() != 0 { 350 if r.events_error().read() != 0 {
@@ -363,7 +369,7 @@ impl<'d, T: Instance> Twis<'d, T> {
363 /// Wait for stop or error with timeout 369 /// Wait for stop or error with timeout
364 #[cfg(feature = "time")] 370 #[cfg(feature = "time")]
365 fn blocking_wait_timeout(&mut self, timeout: Duration) -> Result<usize, Error> { 371 fn blocking_wait_timeout(&mut self, timeout: Duration) -> Result<usize, Error> {
366 let r = T::regs(); 372 let r = self.r;
367 let deadline = Instant::now() + timeout; 373 let deadline = Instant::now() + timeout;
368 loop { 374 loop {
369 // stop if an error occurred 375 // stop if an error occurred
@@ -392,7 +398,7 @@ impl<'d, T: Instance> Twis<'d, T> {
392 /// Wait for read, write, stop or error with timeout 398 /// Wait for read, write, stop or error with timeout
393 #[cfg(feature = "time")] 399 #[cfg(feature = "time")]
394 fn blocking_listen_wait_timeout(&mut self, timeout: Duration) -> Result<Status, Error> { 400 fn blocking_listen_wait_timeout(&mut self, timeout: Duration) -> Result<Status, Error> {
395 let r = T::regs(); 401 let r = self.r;
396 let deadline = Instant::now() + timeout; 402 let deadline = Instant::now() + timeout;
397 loop { 403 loop {
398 if r.events_error().read() != 0 { 404 if r.events_error().read() != 0 {
@@ -423,7 +429,7 @@ impl<'d, T: Instance> Twis<'d, T> {
423 /// Wait for stop, repeated start or error with timeout 429 /// Wait for stop, repeated start or error with timeout
424 #[cfg(feature = "time")] 430 #[cfg(feature = "time")]
425 fn blocking_listen_wait_end_timeout(&mut self, status: Status, timeout: Duration) -> Result<Command, Error> { 431 fn blocking_listen_wait_end_timeout(&mut self, status: Status, timeout: Duration) -> Result<Command, Error> {
426 let r = T::regs(); 432 let r = self.r;
427 let deadline = Instant::now() + timeout; 433 let deadline = Instant::now() + timeout;
428 loop { 434 loop {
429 // stop if an error occurred 435 // stop if an error occurred
@@ -453,10 +459,9 @@ impl<'d, T: Instance> Twis<'d, T> {
453 459
454 /// Wait for stop or error 460 /// Wait for stop or error
455 fn async_wait(&mut self) -> impl Future<Output = Result<usize, Error>> { 461 fn async_wait(&mut self) -> impl Future<Output = Result<usize, Error>> {
462 let r = self.r;
463 let s = self.state;
456 poll_fn(move |cx| { 464 poll_fn(move |cx| {
457 let r = T::regs();
458 let s = T::state();
459
460 s.waker.register(cx.waker()); 465 s.waker.register(cx.waker());
461 466
462 // stop if an error occurred 467 // stop if an error occurred
@@ -483,10 +488,9 @@ impl<'d, T: Instance> Twis<'d, T> {
483 488
484 /// Wait for read or write 489 /// Wait for read or write
485 fn async_listen_wait(&mut self) -> impl Future<Output = Result<Status, Error>> { 490 fn async_listen_wait(&mut self) -> impl Future<Output = Result<Status, Error>> {
491 let r = self.r;
492 let s = self.state;
486 poll_fn(move |cx| { 493 poll_fn(move |cx| {
487 let r = T::regs();
488 let s = T::state();
489
490 s.waker.register(cx.waker()); 494 s.waker.register(cx.waker());
491 495
492 // stop if an error occurred 496 // stop if an error occurred
@@ -510,10 +514,9 @@ impl<'d, T: Instance> Twis<'d, T> {
510 514
511 /// Wait for stop, repeated start or error 515 /// Wait for stop, repeated start or error
512 fn async_listen_wait_end(&mut self, status: Status) -> impl Future<Output = Result<Command, Error>> { 516 fn async_listen_wait_end(&mut self, status: Status) -> impl Future<Output = Result<Command, Error>> {
517 let r = self.r;
518 let s = self.state;
513 poll_fn(move |cx| { 519 poll_fn(move |cx| {
514 let r = T::regs();
515 let s = T::state();
516
517 s.waker.register(cx.waker()); 520 s.waker.register(cx.waker());
518 521
519 // stop if an error occurred 522 // stop if an error occurred
@@ -540,7 +543,7 @@ impl<'d, T: Instance> Twis<'d, T> {
540 } 543 }
541 544
542 fn setup_respond_from_ram(&mut self, buffer: &[u8], inten: bool) -> Result<(), Error> { 545 fn setup_respond_from_ram(&mut self, buffer: &[u8], inten: bool) -> Result<(), Error> {
543 let r = T::regs(); 546 let r = self.r;
544 547
545 compiler_fence(SeqCst); 548 compiler_fence(SeqCst);
546 549
@@ -584,7 +587,7 @@ impl<'d, T: Instance> Twis<'d, T> {
584 } 587 }
585 588
586 fn setup_listen(&mut self, buffer: &mut [u8], inten: bool) -> Result<(), Error> { 589 fn setup_listen(&mut self, buffer: &mut [u8], inten: bool) -> Result<(), Error> {
587 let r = T::regs(); 590 let r = self.r;
588 compiler_fence(SeqCst); 591 compiler_fence(SeqCst);
589 592
590 // Set up the DMA read. 593 // Set up the DMA read.
@@ -620,7 +623,7 @@ impl<'d, T: Instance> Twis<'d, T> {
620 } 623 }
621 624
622 fn setup_listen_end(&mut self, inten: bool) -> Result<(), Error> { 625 fn setup_listen_end(&mut self, inten: bool) -> Result<(), Error> {
623 let r = T::regs(); 626 let r = self.r;
624 compiler_fence(SeqCst); 627 compiler_fence(SeqCst);
625 628
626 // Clear events 629 // Clear events
@@ -700,7 +703,7 @@ impl<'d, T: Instance> Twis<'d, T> {
700 703
701 /// Respond to an I2C master READ command with timeout. 704 /// Respond to an I2C master READ command with timeout.
702 /// Returns the number of bytes written. 705 /// Returns the number of bytes written.
703 /// See [`blocking_respond_to_read`]. 706 /// See [Self::blocking_respond_to_read].
704 #[cfg(feature = "time")] 707 #[cfg(feature = "time")]
705 pub fn blocking_respond_to_read_timeout(&mut self, buffer: &[u8], timeout: Duration) -> Result<usize, Error> { 708 pub fn blocking_respond_to_read_timeout(&mut self, buffer: &[u8], timeout: Duration) -> Result<usize, Error> {
706 self.setup_respond(buffer, false)?; 709 self.setup_respond(buffer, false)?;
@@ -753,14 +756,14 @@ impl<'d, T: Instance> Twis<'d, T> {
753 } 756 }
754} 757}
755 758
756impl<'a, T: Instance> Drop for Twis<'a, T> { 759impl<'a> Drop for Twis<'a> {
757 fn drop(&mut self) { 760 fn drop(&mut self) {
758 trace!("twis drop"); 761 trace!("twis drop");
759 762
760 // TODO: check for abort 763 // TODO: check for abort
761 764
762 // disable! 765 // disable!
763 let r = T::regs(); 766 let r = self.r;
764 r.enable().write(|w| w.set_enable(vals::Enable::DISABLED)); 767 r.enable().write(|w| w.set_enable(vals::Enable::DISABLED));
765 768
766 gpio::deconfigure_pin(r.psel().sda().read()); 769 gpio::deconfigure_pin(r.psel().sda().read());
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs
index 927a0ac08..66fb3b3f2 100644
--- a/embassy-nrf/src/uarte.rs
+++ b/embassy-nrf/src/uarte.rs
@@ -132,28 +132,32 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
132} 132}
133 133
134/// UARTE driver. 134/// UARTE driver.
135pub struct Uarte<'d, T: Instance> { 135pub struct Uarte<'d> {
136 tx: UarteTx<'d, T>, 136 tx: UarteTx<'d>,
137 rx: UarteRx<'d, T>, 137 rx: UarteRx<'d>,
138} 138}
139 139
140/// Transmitter part of the UARTE driver. 140/// Transmitter part of the UARTE driver.
141/// 141///
142/// This can be obtained via [`Uarte::split`], or created directly. 142/// This can be obtained via [`Uarte::split`], or created directly.
143pub struct UarteTx<'d, T: Instance> { 143pub struct UarteTx<'d> {
144 _p: Peri<'d, T>, 144 r: pac::uarte::Uarte,
145 state: &'static State,
146 _p: PhantomData<&'d ()>,
145} 147}
146 148
147/// Receiver part of the UARTE driver. 149/// Receiver part of the UARTE driver.
148/// 150///
149/// This can be obtained via [`Uarte::split`], or created directly. 151/// This can be obtained via [`Uarte::split`], or created directly.
150pub struct UarteRx<'d, T: Instance> { 152pub struct UarteRx<'d> {
151 _p: Peri<'d, T>, 153 r: pac::uarte::Uarte,
154 state: &'static State,
155 _p: PhantomData<&'d ()>,
152} 156}
153 157
154impl<'d, T: Instance> Uarte<'d, T> { 158impl<'d> Uarte<'d> {
155 /// Create a new UARTE without hardware flow control 159 /// Create a new UARTE without hardware flow control
156 pub fn new( 160 pub fn new<T: Instance>(
157 uarte: Peri<'d, T>, 161 uarte: Peri<'d, T>,
158 rxd: Peri<'d, impl GpioPin>, 162 rxd: Peri<'d, impl GpioPin>,
159 txd: Peri<'d, impl GpioPin>, 163 txd: Peri<'d, impl GpioPin>,
@@ -164,7 +168,7 @@ impl<'d, T: Instance> Uarte<'d, T> {
164 } 168 }
165 169
166 /// Create a new UARTE with hardware flow control (RTS/CTS) 170 /// Create a new UARTE with hardware flow control (RTS/CTS)
167 pub fn new_with_rtscts( 171 pub fn new_with_rtscts<T: Instance>(
168 uarte: Peri<'d, T>, 172 uarte: Peri<'d, T>,
169 rxd: Peri<'d, impl GpioPin>, 173 rxd: Peri<'d, impl GpioPin>,
170 txd: Peri<'d, impl GpioPin>, 174 txd: Peri<'d, impl GpioPin>,
@@ -183,8 +187,8 @@ impl<'d, T: Instance> Uarte<'d, T> {
183 ) 187 )
184 } 188 }
185 189
186 fn new_inner( 190 fn new_inner<T: Instance>(
187 uarte: Peri<'d, T>, 191 _uarte: Peri<'d, T>,
188 rxd: Peri<'d, AnyPin>, 192 rxd: Peri<'d, AnyPin>,
189 txd: Peri<'d, AnyPin>, 193 txd: Peri<'d, AnyPin>,
190 cts: Option<Peri<'d, AnyPin>>, 194 cts: Option<Peri<'d, AnyPin>>,
@@ -211,16 +215,22 @@ impl<'d, T: Instance> Uarte<'d, T> {
211 215
212 Self { 216 Self {
213 tx: UarteTx { 217 tx: UarteTx {
214 _p: unsafe { uarte.clone_unchecked() }, 218 r: T::regs(),
219 state: T::state(),
220 _p: PhantomData {},
221 },
222 rx: UarteRx {
223 r: T::regs(),
224 state: T::state(),
225 _p: PhantomData {},
215 }, 226 },
216 rx: UarteRx { _p: uarte },
217 } 227 }
218 } 228 }
219 229
220 /// Split the Uarte into the transmitter and receiver parts. 230 /// Split the Uarte into the transmitter and receiver parts.
221 /// 231 ///
222 /// This is useful to concurrently transmit and receive from independent tasks. 232 /// This is useful to concurrently transmit and receive from independent tasks.
223 pub fn split(self) -> (UarteTx<'d, T>, UarteRx<'d, T>) { 233 pub fn split(self) -> (UarteTx<'d>, UarteRx<'d>) {
224 (self.tx, self.rx) 234 (self.tx, self.rx)
225 } 235 }
226 236
@@ -228,7 +238,7 @@ impl<'d, T: Instance> Uarte<'d, T> {
228 /// 238 ///
229 /// The returned halves borrow from `self`, so you can drop them and go back to using 239 /// The returned halves borrow from `self`, so you can drop them and go back to using
230 /// the "un-split" `self`. This allows temporarily splitting the UART. 240 /// the "un-split" `self`. This allows temporarily splitting the UART.
231 pub fn split_by_ref(&mut self) -> (&mut UarteTx<'d, T>, &mut UarteRx<'d, T>) { 241 pub fn split_by_ref(&mut self) -> (&mut UarteTx<'d>, &mut UarteRx<'d>) {
232 (&mut self.tx, &mut self.rx) 242 (&mut self.tx, &mut self.rx)
233 } 243 }
234 244
@@ -240,13 +250,13 @@ impl<'d, T: Instance> Uarte<'d, T> {
240 timer: Peri<'d, U>, 250 timer: Peri<'d, U>,
241 ppi_ch1: Peri<'d, impl ConfigurableChannel + 'd>, 251 ppi_ch1: Peri<'d, impl ConfigurableChannel + 'd>,
242 ppi_ch2: Peri<'d, impl ConfigurableChannel + 'd>, 252 ppi_ch2: Peri<'d, impl ConfigurableChannel + 'd>,
243 ) -> (UarteTx<'d, T>, UarteRxWithIdle<'d, T, U>) { 253 ) -> (UarteTx<'d>, UarteRxWithIdle<'d>) {
244 (self.tx, self.rx.with_idle(timer, ppi_ch1, ppi_ch2)) 254 (self.tx, self.rx.with_idle(timer, ppi_ch1, ppi_ch2))
245 } 255 }
246 256
247 /// Return the endtx event for use with PPI 257 /// Return the endtx event for use with PPI
248 pub fn event_endtx(&self) -> Event<'_> { 258 pub fn event_endtx(&self) -> Event<'_> {
249 let r = T::regs(); 259 let r = self.tx.r;
250 Event::from_reg(r.events_endtx()) 260 Event::from_reg(r.events_endtx())
251 } 261 }
252 262
@@ -343,9 +353,9 @@ pub(crate) fn configure(r: pac::uarte::Uarte, config: Config, hardware_flow_cont
343 apply_workaround_for_enable_anomaly(r); 353 apply_workaround_for_enable_anomaly(r);
344} 354}
345 355
346impl<'d, T: Instance> UarteTx<'d, T> { 356impl<'d> UarteTx<'d> {
347 /// Create a new tx-only UARTE without hardware flow control 357 /// Create a new tx-only UARTE without hardware flow control
348 pub fn new( 358 pub fn new<T: Instance>(
349 uarte: Peri<'d, T>, 359 uarte: Peri<'d, T>,
350 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 360 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
351 txd: Peri<'d, impl GpioPin>, 361 txd: Peri<'d, impl GpioPin>,
@@ -355,7 +365,7 @@ impl<'d, T: Instance> UarteTx<'d, T> {
355 } 365 }
356 366
357 /// Create a new tx-only UARTE with hardware flow control (RTS/CTS) 367 /// Create a new tx-only UARTE with hardware flow control (RTS/CTS)
358 pub fn new_with_rtscts( 368 pub fn new_with_rtscts<T: Instance>(
359 uarte: Peri<'d, T>, 369 uarte: Peri<'d, T>,
360 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 370 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
361 txd: Peri<'d, impl GpioPin>, 371 txd: Peri<'d, impl GpioPin>,
@@ -365,7 +375,12 @@ impl<'d, T: Instance> UarteTx<'d, T> {
365 Self::new_inner(uarte, txd.into(), Some(cts.into()), config) 375 Self::new_inner(uarte, txd.into(), Some(cts.into()), config)
366 } 376 }
367 377
368 fn new_inner(uarte: Peri<'d, T>, txd: Peri<'d, AnyPin>, cts: Option<Peri<'d, AnyPin>>, config: Config) -> Self { 378 fn new_inner<T: Instance>(
379 _uarte: Peri<'d, T>,
380 txd: Peri<'d, AnyPin>,
381 cts: Option<Peri<'d, AnyPin>>,
382 config: Config,
383 ) -> Self {
369 let r = T::regs(); 384 let r = T::regs();
370 385
371 configure(r, config, cts.is_some()); 386 configure(r, config, cts.is_some());
@@ -378,7 +393,11 @@ impl<'d, T: Instance> UarteTx<'d, T> {
378 let s = T::state(); 393 let s = T::state();
379 s.tx_rx_refcount.store(1, Ordering::Relaxed); 394 s.tx_rx_refcount.store(1, Ordering::Relaxed);
380 395
381 Self { _p: uarte } 396 Self {
397 r: T::regs(),
398 state: T::state(),
399 _p: PhantomData {},
400 }
382 } 401 }
383 402
384 /// Write all bytes in the buffer. 403 /// Write all bytes in the buffer.
@@ -409,8 +428,8 @@ impl<'d, T: Instance> UarteTx<'d, T> {
409 let ptr = buffer.as_ptr(); 428 let ptr = buffer.as_ptr();
410 let len = buffer.len(); 429 let len = buffer.len();
411 430
412 let r = T::regs(); 431 let r = self.r;
413 let s = T::state(); 432 let s = self.state;
414 433
415 let drop = OnDrop::new(move || { 434 let drop = OnDrop::new(move || {
416 trace!("write drop: stopping"); 435 trace!("write drop: stopping");
@@ -479,7 +498,7 @@ impl<'d, T: Instance> UarteTx<'d, T> {
479 let ptr = buffer.as_ptr(); 498 let ptr = buffer.as_ptr();
480 let len = buffer.len(); 499 let len = buffer.len();
481 500
482 let r = T::regs(); 501 let r = self.r;
483 502
484 r.txd().ptr().write_value(ptr as u32); 503 r.txd().ptr().write_value(ptr as u32);
485 r.txd().maxcnt().write(|w| w.set_maxcnt(len as _)); 504 r.txd().maxcnt().write(|w| w.set_maxcnt(len as _));
@@ -501,11 +520,11 @@ impl<'d, T: Instance> UarteTx<'d, T> {
501 } 520 }
502} 521}
503 522
504impl<'a, T: Instance> Drop for UarteTx<'a, T> { 523impl<'a> Drop for UarteTx<'a> {
505 fn drop(&mut self) { 524 fn drop(&mut self) {
506 trace!("uarte tx drop"); 525 trace!("uarte tx drop");
507 526
508 let r = T::regs(); 527 let r = self.r;
509 528
510 let did_stoptx = r.events_txstarted().read() != 0; 529 let did_stoptx = r.events_txstarted().read() != 0;
511 trace!("did_stoptx {}", did_stoptx); 530 trace!("did_stoptx {}", did_stoptx);
@@ -513,15 +532,15 @@ impl<'a, T: Instance> Drop for UarteTx<'a, T> {
513 // Wait for txstopped, if needed. 532 // Wait for txstopped, if needed.
514 while did_stoptx && r.events_txstopped().read() == 0 {} 533 while did_stoptx && r.events_txstopped().read() == 0 {}
515 534
516 let s = T::state(); 535 let s = self.state;
517 536
518 drop_tx_rx(r, s); 537 drop_tx_rx(r, s);
519 } 538 }
520} 539}
521 540
522impl<'d, T: Instance> UarteRx<'d, T> { 541impl<'d> UarteRx<'d> {
523 /// Create a new rx-only UARTE without hardware flow control 542 /// Create a new rx-only UARTE without hardware flow control
524 pub fn new( 543 pub fn new<T: Instance>(
525 uarte: Peri<'d, T>, 544 uarte: Peri<'d, T>,
526 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 545 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
527 rxd: Peri<'d, impl GpioPin>, 546 rxd: Peri<'d, impl GpioPin>,
@@ -531,7 +550,7 @@ impl<'d, T: Instance> UarteRx<'d, T> {
531 } 550 }
532 551
533 /// Create a new rx-only UARTE with hardware flow control (RTS/CTS) 552 /// Create a new rx-only UARTE with hardware flow control (RTS/CTS)
534 pub fn new_with_rtscts( 553 pub fn new_with_rtscts<T: Instance>(
535 uarte: Peri<'d, T>, 554 uarte: Peri<'d, T>,
536 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 555 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
537 rxd: Peri<'d, impl GpioPin>, 556 rxd: Peri<'d, impl GpioPin>,
@@ -543,13 +562,18 @@ impl<'d, T: Instance> UarteRx<'d, T> {
543 562
544 /// Check for errors and clear the error register if an error occured. 563 /// Check for errors and clear the error register if an error occured.
545 fn check_and_clear_errors(&mut self) -> Result<(), Error> { 564 fn check_and_clear_errors(&mut self) -> Result<(), Error> {
546 let r = T::regs(); 565 let r = self.r;
547 let err_bits = r.errorsrc().read(); 566 let err_bits = r.errorsrc().read();
548 r.errorsrc().write_value(err_bits); 567 r.errorsrc().write_value(err_bits);
549 ErrorSource::from_bits_truncate(err_bits.0).check() 568 ErrorSource::from_bits_truncate(err_bits.0).check()
550 } 569 }
551 570
552 fn new_inner(uarte: Peri<'d, T>, rxd: Peri<'d, AnyPin>, rts: Option<Peri<'d, AnyPin>>, config: Config) -> Self { 571 fn new_inner<T: Instance>(
572 _uarte: Peri<'d, T>,
573 rxd: Peri<'d, AnyPin>,
574 rts: Option<Peri<'d, AnyPin>>,
575 config: Config,
576 ) -> Self {
553 let r = T::regs(); 577 let r = T::regs();
554 578
555 configure(r, config, rts.is_some()); 579 configure(r, config, rts.is_some());
@@ -562,7 +586,11 @@ impl<'d, T: Instance> UarteRx<'d, T> {
562 let s = T::state(); 586 let s = T::state();
563 s.tx_rx_refcount.store(1, Ordering::Relaxed); 587 s.tx_rx_refcount.store(1, Ordering::Relaxed);
564 588
565 Self { _p: uarte } 589 Self {
590 r: T::regs(),
591 state: T::state(),
592 _p: PhantomData {},
593 }
566 } 594 }
567 595
568 /// Upgrade to an instance that supports idle line detection. 596 /// Upgrade to an instance that supports idle line detection.
@@ -571,10 +599,10 @@ impl<'d, T: Instance> UarteRx<'d, T> {
571 timer: Peri<'d, U>, 599 timer: Peri<'d, U>,
572 ppi_ch1: Peri<'d, impl ConfigurableChannel + 'd>, 600 ppi_ch1: Peri<'d, impl ConfigurableChannel + 'd>,
573 ppi_ch2: Peri<'d, impl ConfigurableChannel + 'd>, 601 ppi_ch2: Peri<'d, impl ConfigurableChannel + 'd>,
574 ) -> UarteRxWithIdle<'d, T, U> { 602 ) -> UarteRxWithIdle<'d> {
575 let timer = Timer::new(timer); 603 let timer = Timer::new(timer);
576 604
577 let r = T::regs(); 605 let r = self.r;
578 606
579 // BAUDRATE register values are `baudrate * 2^32 / 16000000` 607 // BAUDRATE register values are `baudrate * 2^32 / 16000000`
580 // source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values 608 // source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values
@@ -605,11 +633,15 @@ impl<'d, T: Instance> UarteRx<'d, T> {
605 ); 633 );
606 ppi_ch2.enable(); 634 ppi_ch2.enable();
607 635
636 let state = self.state;
637
608 UarteRxWithIdle { 638 UarteRxWithIdle {
609 rx: self, 639 rx: self,
610 timer, 640 timer,
611 ppi_ch1, 641 ppi_ch1: ppi_ch1,
612 _ppi_ch2: ppi_ch2, 642 _ppi_ch2: ppi_ch2,
643 r: r,
644 state: state,
613 } 645 }
614 } 646 }
615 647
@@ -625,8 +657,8 @@ impl<'d, T: Instance> UarteRx<'d, T> {
625 let ptr = buffer.as_ptr(); 657 let ptr = buffer.as_ptr();
626 let len = buffer.len(); 658 let len = buffer.len();
627 659
628 let r = T::regs(); 660 let r = self.r;
629 let s = T::state(); 661 let s = self.state;
630 662
631 let drop = OnDrop::new(move || { 663 let drop = OnDrop::new(move || {
632 trace!("read drop: stopping"); 664 trace!("read drop: stopping");
@@ -692,7 +724,7 @@ impl<'d, T: Instance> UarteRx<'d, T> {
692 let ptr = buffer.as_ptr(); 724 let ptr = buffer.as_ptr();
693 let len = buffer.len(); 725 let len = buffer.len();
694 726
695 let r = T::regs(); 727 let r = self.r;
696 728
697 r.rxd().ptr().write_value(ptr as u32); 729 r.rxd().ptr().write_value(ptr as u32);
698 r.rxd().maxcnt().write(|w| w.set_maxcnt(len as _)); 730 r.rxd().maxcnt().write(|w| w.set_maxcnt(len as _));
@@ -718,11 +750,11 @@ impl<'d, T: Instance> UarteRx<'d, T> {
718 } 750 }
719} 751}
720 752
721impl<'a, T: Instance> Drop for UarteRx<'a, T> { 753impl<'a> Drop for UarteRx<'a> {
722 fn drop(&mut self) { 754 fn drop(&mut self) {
723 trace!("uarte rx drop"); 755 trace!("uarte rx drop");
724 756
725 let r = T::regs(); 757 let r = self.r;
726 758
727 let did_stoprx = r.events_rxstarted().read() != 0; 759 let did_stoprx = r.events_rxstarted().read() != 0;
728 trace!("did_stoprx {}", did_stoprx); 760 trace!("did_stoprx {}", did_stoprx);
@@ -730,7 +762,7 @@ impl<'a, T: Instance> Drop for UarteRx<'a, T> {
730 // Wait for rxto, if needed. 762 // Wait for rxto, if needed.
731 while did_stoprx && r.events_rxto().read() == 0 {} 763 while did_stoprx && r.events_rxto().read() == 0 {}
732 764
733 let s = T::state(); 765 let s = self.state;
734 766
735 drop_tx_rx(r, s); 767 drop_tx_rx(r, s);
736 } 768 }
@@ -739,14 +771,16 @@ impl<'a, T: Instance> Drop for UarteRx<'a, T> {
739/// Receiver part of the UARTE driver, with `read_until_idle` support. 771/// Receiver part of the UARTE driver, with `read_until_idle` support.
740/// 772///
741/// This can be obtained via [`Uarte::split_with_idle`]. 773/// This can be obtained via [`Uarte::split_with_idle`].
742pub struct UarteRxWithIdle<'d, T: Instance, U: TimerInstance> { 774pub struct UarteRxWithIdle<'d> {
743 rx: UarteRx<'d, T>, 775 rx: UarteRx<'d>,
744 timer: Timer<'d, U>, 776 timer: Timer<'d>,
745 ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 2>, 777 ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 2>,
746 _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 1>, 778 _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 1>,
779 r: pac::uarte::Uarte,
780 state: &'static State,
747} 781}
748 782
749impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> { 783impl<'d> UarteRxWithIdle<'d> {
750 /// Read bytes until the buffer is filled. 784 /// Read bytes until the buffer is filled.
751 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 785 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
752 self.ppi_ch1.disable(); 786 self.ppi_ch1.disable();
@@ -773,8 +807,8 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> {
773 let ptr = buffer.as_ptr(); 807 let ptr = buffer.as_ptr();
774 let len = buffer.len(); 808 let len = buffer.len();
775 809
776 let r = T::regs(); 810 let r = self.r;
777 let s = T::state(); 811 let s = self.state;
778 812
779 self.ppi_ch1.enable(); 813 self.ppi_ch1.enable();
780 814
@@ -846,7 +880,7 @@ impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> {
846 let ptr = buffer.as_ptr(); 880 let ptr = buffer.as_ptr();
847 let len = buffer.len(); 881 let len = buffer.len();
848 882
849 let r = T::regs(); 883 let r = self.r;
850 884
851 self.ppi_ch1.enable(); 885 self.ppi_ch1.enable();
852 886
@@ -997,7 +1031,7 @@ macro_rules! impl_uarte {
997mod eh02 { 1031mod eh02 {
998 use super::*; 1032 use super::*;
999 1033
1000 impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for Uarte<'d, T> { 1034 impl<'d> embedded_hal_02::blocking::serial::Write<u8> for Uarte<'d> {
1001 type Error = Error; 1035 type Error = Error;
1002 1036
1003 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { 1037 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
@@ -1009,7 +1043,7 @@ mod eh02 {
1009 } 1043 }
1010 } 1044 }
1011 1045
1012 impl<'d, T: Instance> embedded_hal_02::blocking::serial::Write<u8> for UarteTx<'d, T> { 1046 impl<'d> embedded_hal_02::blocking::serial::Write<u8> for UarteTx<'d> {
1013 type Error = Error; 1047 type Error = Error;
1014 1048
1015 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { 1049 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
@@ -1038,22 +1072,22 @@ mod _embedded_io {
1038 } 1072 }
1039 } 1073 }
1040 1074
1041 impl<'d, U: Instance> embedded_io_async::ErrorType for Uarte<'d, U> { 1075 impl<'d> embedded_io_async::ErrorType for Uarte<'d> {
1042 type Error = Error; 1076 type Error = Error;
1043 } 1077 }
1044 1078
1045 impl<'d, U: Instance> embedded_io_async::ErrorType for UarteTx<'d, U> { 1079 impl<'d> embedded_io_async::ErrorType for UarteTx<'d> {
1046 type Error = Error; 1080 type Error = Error;
1047 } 1081 }
1048 1082
1049 impl<'d, U: Instance> embedded_io_async::Write for Uarte<'d, U> { 1083 impl<'d> embedded_io_async::Write for Uarte<'d> {
1050 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 1084 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
1051 self.write(buf).await?; 1085 self.write(buf).await?;
1052 Ok(buf.len()) 1086 Ok(buf.len())
1053 } 1087 }
1054 } 1088 }
1055 1089
1056 impl<'d: 'd, U: Instance> embedded_io_async::Write for UarteTx<'d, U> { 1090 impl<'d> embedded_io_async::Write for UarteTx<'d> {
1057 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 1091 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
1058 self.write(buf).await?; 1092 self.write(buf).await?;
1059 Ok(buf.len()) 1093 Ok(buf.len())
diff --git a/embassy-nrf/src/usb/mod.rs b/embassy-nrf/src/usb/mod.rs
index c6970fc0f..2a32fe922 100644
--- a/embassy-nrf/src/usb/mod.rs
+++ b/embassy-nrf/src/usb/mod.rs
@@ -86,17 +86,18 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
86} 86}
87 87
88/// USB driver. 88/// USB driver.
89pub struct Driver<'d, T: Instance, V: VbusDetect> { 89pub struct Driver<'d, V: VbusDetect> {
90 _p: Peri<'d, T>, 90 regs: pac::usbd::Usbd,
91 alloc_in: Allocator, 91 alloc_in: Allocator,
92 alloc_out: Allocator, 92 alloc_out: Allocator,
93 vbus_detect: V, 93 vbus_detect: V,
94 _phantom: PhantomData<&'d ()>,
94} 95}
95 96
96impl<'d, T: Instance, V: VbusDetect> Driver<'d, T, V> { 97impl<'d, V: VbusDetect> Driver<'d, V> {
97 /// Create a new USB driver. 98 /// Create a new USB driver.
98 pub fn new( 99 pub fn new<T: Instance>(
99 usb: Peri<'d, T>, 100 _usb: Peri<'d, T>,
100 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 101 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
101 vbus_detect: V, 102 vbus_detect: V,
102 ) -> Self { 103 ) -> Self {
@@ -104,19 +105,20 @@ impl<'d, T: Instance, V: VbusDetect> Driver<'d, T, V> {
104 unsafe { T::Interrupt::enable() }; 105 unsafe { T::Interrupt::enable() };
105 106
106 Self { 107 Self {
107 _p: usb, 108 regs: crate::pac::USBD,
108 alloc_in: Allocator::new(), 109 alloc_in: Allocator::new(),
109 alloc_out: Allocator::new(), 110 alloc_out: Allocator::new(),
110 vbus_detect, 111 vbus_detect,
112 _phantom: PhantomData,
111 } 113 }
112 } 114 }
113} 115}
114 116
115impl<'d, T: Instance, V: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, V> { 117impl<'d, V: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, V> {
116 type EndpointOut = Endpoint<'d, T, Out>; 118 type EndpointOut = Endpoint<'d, Out>;
117 type EndpointIn = Endpoint<'d, T, In>; 119 type EndpointIn = Endpoint<'d, In>;
118 type ControlPipe = ControlPipe<'d, T>; 120 type ControlPipe = ControlPipe<'d>;
119 type Bus = Bus<'d, T, V>; 121 type Bus = Bus<'d, V>;
120 122
121 fn alloc_endpoint_in( 123 fn alloc_endpoint_in(
122 &mut self, 124 &mut self,
@@ -127,12 +129,15 @@ impl<'d, T: Instance, V: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, V
127 ) -> Result<Self::EndpointIn, driver::EndpointAllocError> { 129 ) -> Result<Self::EndpointIn, driver::EndpointAllocError> {
128 let index = self.alloc_in.allocate(ep_type, ep_addr)?; 130 let index = self.alloc_in.allocate(ep_type, ep_addr)?;
129 let ep_addr = EndpointAddress::from_parts(index, Direction::In); 131 let ep_addr = EndpointAddress::from_parts(index, Direction::In);
130 Ok(Endpoint::new(EndpointInfo { 132 Ok(Endpoint::new(
131 addr: ep_addr, 133 self.regs,
132 ep_type, 134 EndpointInfo {
133 max_packet_size: packet_size, 135 addr: ep_addr,
134 interval_ms, 136 ep_type,
135 })) 137 max_packet_size: packet_size,
138 interval_ms,
139 },
140 ))
136 } 141 }
137 142
138 fn alloc_endpoint_out( 143 fn alloc_endpoint_out(
@@ -144,39 +149,45 @@ impl<'d, T: Instance, V: VbusDetect + 'd> driver::Driver<'d> for Driver<'d, T, V
144 ) -> Result<Self::EndpointOut, driver::EndpointAllocError> { 149 ) -> Result<Self::EndpointOut, driver::EndpointAllocError> {
145 let index = self.alloc_out.allocate(ep_type, ep_addr)?; 150 let index = self.alloc_out.allocate(ep_type, ep_addr)?;
146 let ep_addr = EndpointAddress::from_parts(index, Direction::Out); 151 let ep_addr = EndpointAddress::from_parts(index, Direction::Out);
147 Ok(Endpoint::new(EndpointInfo { 152 Ok(Endpoint::new(
148 addr: ep_addr, 153 self.regs,
149 ep_type, 154 EndpointInfo {
150 max_packet_size: packet_size, 155 addr: ep_addr,
151 interval_ms, 156 ep_type,
152 })) 157 max_packet_size: packet_size,
158 interval_ms,
159 },
160 ))
153 } 161 }
154 162
155 fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) { 163 fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
156 ( 164 (
157 Bus { 165 Bus {
158 _p: unsafe { self._p.clone_unchecked() }, 166 regs: self.regs,
159 power_available: false, 167 power_available: false,
160 vbus_detect: self.vbus_detect, 168 vbus_detect: self.vbus_detect,
169 _phantom: PhantomData,
161 }, 170 },
162 ControlPipe { 171 ControlPipe {
163 _p: self._p, 172 regs: self.regs,
164 max_packet_size: control_max_packet_size, 173 max_packet_size: control_max_packet_size,
174 _phantom: PhantomData,
165 }, 175 },
166 ) 176 )
167 } 177 }
168} 178}
169 179
170/// USB bus. 180/// USB bus.
171pub struct Bus<'d, T: Instance, V: VbusDetect> { 181pub struct Bus<'d, V: VbusDetect> {
172 _p: Peri<'d, T>, 182 regs: pac::usbd::Usbd,
173 power_available: bool, 183 power_available: bool,
174 vbus_detect: V, 184 vbus_detect: V,
185 _phantom: PhantomData<&'d ()>,
175} 186}
176 187
177impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> { 188impl<'d, V: VbusDetect> driver::Bus for Bus<'d, V> {
178 async fn enable(&mut self) { 189 async fn enable(&mut self) {
179 let regs = T::regs(); 190 let regs = self.regs;
180 191
181 errata::pre_enable(); 192 errata::pre_enable();
182 193
@@ -215,14 +226,14 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> {
215 } 226 }
216 227
217 async fn disable(&mut self) { 228 async fn disable(&mut self) {
218 let regs = T::regs(); 229 let regs = self.regs;
219 regs.enable().write(|x| x.set_enable(false)); 230 regs.enable().write(|x| x.set_enable(false));
220 } 231 }
221 232
222 fn poll(&mut self) -> impl Future<Output = Event> { 233 fn poll(&mut self) -> impl Future<Output = Event> {
223 poll_fn(|cx| { 234 poll_fn(|cx| {
224 BUS_WAKER.register(cx.waker()); 235 BUS_WAKER.register(cx.waker());
225 let regs = T::regs(); 236 let regs = self.regs;
226 237
227 if regs.events_usbreset().read() != 0 { 238 if regs.events_usbreset().read() != 0 {
228 regs.events_usbreset().write_value(0); 239 regs.events_usbreset().write_value(0);
@@ -280,7 +291,7 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> {
280 } 291 }
281 292
282 fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool) { 293 fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool) {
283 let regs = T::regs(); 294 let regs = self.regs;
284 if ep_addr.index() == 0 { 295 if ep_addr.index() == 0 {
285 if stalled { 296 if stalled {
286 regs.tasks_ep0stall().write_value(1); 297 regs.tasks_ep0stall().write_value(1);
@@ -298,7 +309,7 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> {
298 } 309 }
299 310
300 fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool { 311 fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool {
301 let regs = T::regs(); 312 let regs = self.regs;
302 let i = ep_addr.index(); 313 let i = ep_addr.index();
303 match ep_addr.direction() { 314 match ep_addr.direction() {
304 Direction::Out => regs.halted().epout(i).read().getstatus() == vals::Getstatus::HALTED, 315 Direction::Out => regs.halted().epout(i).read().getstatus() == vals::Getstatus::HALTED,
@@ -307,7 +318,7 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> {
307 } 318 }
308 319
309 fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool) { 320 fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool) {
310 let regs = T::regs(); 321 let regs = self.regs;
311 322
312 let i = ep_addr.index(); 323 let i = ep_addr.index();
313 let mask = 1 << i; 324 let mask = 1 << i;
@@ -359,7 +370,7 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> {
359 370
360 #[inline] 371 #[inline]
361 async fn remote_wakeup(&mut self) -> Result<(), Unsupported> { 372 async fn remote_wakeup(&mut self) -> Result<(), Unsupported> {
362 let regs = T::regs(); 373 let regs = self.regs;
363 374
364 if regs.lowpower().read().lowpower() == vals::Lowpower::LOW_POWER { 375 if regs.lowpower().read().lowpower() == vals::Lowpower::LOW_POWER {
365 errata::pre_wakeup(); 376 errata::pre_wakeup();
@@ -368,7 +379,7 @@ impl<'d, T: Instance, V: VbusDetect> driver::Bus for Bus<'d, T, V> {
368 379
369 poll_fn(|cx| { 380 poll_fn(|cx| {
370 BUS_WAKER.register(cx.waker()); 381 BUS_WAKER.register(cx.waker());
371 let regs = T::regs(); 382 let regs = self.regs;
372 let r = regs.eventcause().read(); 383 let r = regs.eventcause().read();
373 384
374 if regs.events_usbreset().read() != 0 { 385 if regs.events_usbreset().read() != 0 {
@@ -441,21 +452,23 @@ impl EndpointDir for Out {
441} 452}
442 453
443/// USB endpoint. 454/// USB endpoint.
444pub struct Endpoint<'d, T: Instance, Dir> { 455pub struct Endpoint<'d, Dir> {
445 _phantom: PhantomData<(&'d mut T, Dir)>, 456 regs: pac::usbd::Usbd,
446 info: EndpointInfo, 457 info: EndpointInfo,
458 _phantom: PhantomData<(&'d (), Dir)>,
447} 459}
448 460
449impl<'d, T: Instance, Dir> Endpoint<'d, T, Dir> { 461impl<'d, Dir> Endpoint<'d, Dir> {
450 fn new(info: EndpointInfo) -> Self { 462 fn new(regs: pac::usbd::Usbd, info: EndpointInfo) -> Self {
451 Self { 463 Self {
464 regs,
452 info, 465 info,
453 _phantom: PhantomData, 466 _phantom: PhantomData,
454 } 467 }
455 } 468 }
456} 469}
457 470
458impl<'d, T: Instance, Dir: EndpointDir> driver::Endpoint for Endpoint<'d, T, Dir> { 471impl<'d, Dir: EndpointDir> driver::Endpoint for Endpoint<'d, Dir> {
459 fn info(&self) -> &EndpointInfo { 472 fn info(&self) -> &EndpointInfo {
460 &self.info 473 &self.info
461 } 474 }
@@ -466,14 +479,14 @@ impl<'d, T: Instance, Dir: EndpointDir> driver::Endpoint for Endpoint<'d, T, Dir
466} 479}
467 480
468#[allow(private_bounds)] 481#[allow(private_bounds)]
469impl<'d, T: Instance, Dir: EndpointDir> Endpoint<'d, T, Dir> { 482impl<'d, Dir: EndpointDir> Endpoint<'d, Dir> {
470 fn wait_enabled_state(&mut self, state: bool) -> impl Future<Output = ()> { 483 fn wait_enabled_state(&mut self, state: bool) -> impl Future<Output = ()> + use<'_, 'd, Dir> {
471 let i = self.info.addr.index(); 484 let i = self.info.addr.index();
472 assert!(i != 0); 485 assert!(i != 0);
473 486
474 poll_fn(move |cx| { 487 poll_fn(move |cx| {
475 Dir::waker(i).register(cx.waker()); 488 Dir::waker(i).register(cx.waker());
476 if Dir::is_enabled(T::regs(), i) == state { 489 if Dir::is_enabled(self.regs, i) == state {
477 Poll::Ready(()) 490 Poll::Ready(())
478 } else { 491 } else {
479 Poll::Pending 492 Poll::Pending
@@ -482,12 +495,12 @@ impl<'d, T: Instance, Dir: EndpointDir> Endpoint<'d, T, Dir> {
482 } 495 }
483 496
484 /// Wait for the endpoint to be disabled 497 /// Wait for the endpoint to be disabled
485 pub fn wait_disabled(&mut self) -> impl Future<Output = ()> { 498 pub fn wait_disabled(&mut self) -> impl Future<Output = ()> + use<'_, 'd, Dir> {
486 self.wait_enabled_state(false) 499 self.wait_enabled_state(false)
487 } 500 }
488} 501}
489 502
490impl<'d, T: Instance, Dir> Endpoint<'d, T, Dir> { 503impl<'d, Dir> Endpoint<'d, Dir> {
491 async fn wait_data_ready(&mut self) -> Result<(), ()> 504 async fn wait_data_ready(&mut self) -> Result<(), ()>
492 where 505 where
493 Dir: EndpointDir, 506 Dir: EndpointDir,
@@ -497,7 +510,7 @@ impl<'d, T: Instance, Dir> Endpoint<'d, T, Dir> {
497 poll_fn(|cx| { 510 poll_fn(|cx| {
498 Dir::waker(i).register(cx.waker()); 511 Dir::waker(i).register(cx.waker());
499 let r = READY_ENDPOINTS.load(Ordering::Acquire); 512 let r = READY_ENDPOINTS.load(Ordering::Acquire);
500 if !Dir::is_enabled(T::regs(), i) { 513 if !Dir::is_enabled(self.regs, i) {
501 Poll::Ready(Err(())) 514 Poll::Ready(Err(()))
502 } else if r & Dir::mask(i) != 0 { 515 } else if r & Dir::mask(i) != 0 {
503 Poll::Ready(Ok(())) 516 Poll::Ready(Ok(()))
@@ -514,9 +527,7 @@ impl<'d, T: Instance, Dir> Endpoint<'d, T, Dir> {
514 } 527 }
515} 528}
516 529
517unsafe fn read_dma<T: Instance>(i: usize, buf: &mut [u8]) -> Result<usize, EndpointError> { 530unsafe fn read_dma(regs: pac::usbd::Usbd, i: usize, buf: &mut [u8]) -> Result<usize, EndpointError> {
518 let regs = T::regs();
519
520 // Check that the packet fits into the buffer 531 // Check that the packet fits into the buffer
521 let size = regs.size().epout(i).read().0 as usize; 532 let size = regs.size().epout(i).read().0 as usize;
522 if size > buf.len() { 533 if size > buf.len() {
@@ -539,8 +550,7 @@ unsafe fn read_dma<T: Instance>(i: usize, buf: &mut [u8]) -> Result<usize, Endpo
539 Ok(size) 550 Ok(size)
540} 551}
541 552
542unsafe fn write_dma<T: Instance>(i: usize, buf: &[u8]) { 553unsafe fn write_dma(regs: pac::usbd::Usbd, i: usize, buf: &[u8]) {
543 let regs = T::regs();
544 assert!(buf.len() <= 64); 554 assert!(buf.len() <= 64);
545 555
546 let mut ram_buf: MaybeUninit<[u8; 64]> = MaybeUninit::uninit(); 556 let mut ram_buf: MaybeUninit<[u8; 64]> = MaybeUninit::uninit();
@@ -566,43 +576,44 @@ unsafe fn write_dma<T: Instance>(i: usize, buf: &[u8]) {
566 dma_end(); 576 dma_end();
567} 577}
568 578
569impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { 579impl<'d> driver::EndpointOut for Endpoint<'d, Out> {
570 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> { 580 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, EndpointError> {
571 let i = self.info.addr.index(); 581 let i = self.info.addr.index();
572 assert!(i != 0); 582 assert!(i != 0);
573 583
574 self.wait_data_ready().await.map_err(|_| EndpointError::Disabled)?; 584 self.wait_data_ready().await.map_err(|_| EndpointError::Disabled)?;
575 585
576 unsafe { read_dma::<T>(i, buf) } 586 unsafe { read_dma(self.regs, i, buf) }
577 } 587 }
578} 588}
579 589
580impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { 590impl<'d> driver::EndpointIn for Endpoint<'d, In> {
581 async fn write(&mut self, buf: &[u8]) -> Result<(), EndpointError> { 591 async fn write(&mut self, buf: &[u8]) -> Result<(), EndpointError> {
582 let i = self.info.addr.index(); 592 let i = self.info.addr.index();
583 assert!(i != 0); 593 assert!(i != 0);
584 594
585 self.wait_data_ready().await.map_err(|_| EndpointError::Disabled)?; 595 self.wait_data_ready().await.map_err(|_| EndpointError::Disabled)?;
586 596
587 unsafe { write_dma::<T>(i, buf) } 597 unsafe { write_dma(self.regs, i, buf) }
588 598
589 Ok(()) 599 Ok(())
590 } 600 }
591} 601}
592 602
593/// USB control pipe. 603/// USB control pipe.
594pub struct ControlPipe<'d, T: Instance> { 604pub struct ControlPipe<'d> {
595 _p: Peri<'d, T>, 605 regs: pac::usbd::Usbd,
596 max_packet_size: u16, 606 max_packet_size: u16,
607 _phantom: PhantomData<&'d ()>,
597} 608}
598 609
599impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { 610impl<'d> driver::ControlPipe for ControlPipe<'d> {
600 fn max_packet_size(&self) -> usize { 611 fn max_packet_size(&self) -> usize {
601 usize::from(self.max_packet_size) 612 usize::from(self.max_packet_size)
602 } 613 }
603 614
604 async fn setup(&mut self) -> [u8; 8] { 615 async fn setup(&mut self) -> [u8; 8] {
605 let regs = T::regs(); 616 let regs = self.regs;
606 617
607 // Reset shorts 618 // Reset shorts
608 regs.shorts().write(|_| ()); 619 regs.shorts().write(|_| ());
@@ -611,7 +622,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
611 regs.intenset().write(|w| w.set_ep0setup(true)); 622 regs.intenset().write(|w| w.set_ep0setup(true));
612 poll_fn(|cx| { 623 poll_fn(|cx| {
613 EP0_WAKER.register(cx.waker()); 624 EP0_WAKER.register(cx.waker());
614 let regs = T::regs(); 625 let regs = self.regs;
615 if regs.events_ep0setup().read() != 0 { 626 if regs.events_ep0setup().read() != 0 {
616 Poll::Ready(()) 627 Poll::Ready(())
617 } else { 628 } else {
@@ -636,7 +647,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
636 } 647 }
637 648
638 async fn data_out(&mut self, buf: &mut [u8], _first: bool, _last: bool) -> Result<usize, EndpointError> { 649 async fn data_out(&mut self, buf: &mut [u8], _first: bool, _last: bool) -> Result<usize, EndpointError> {
639 let regs = T::regs(); 650 let regs = self.regs;
640 651
641 regs.events_ep0datadone().write_value(0); 652 regs.events_ep0datadone().write_value(0);
642 653
@@ -651,7 +662,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
651 }); 662 });
652 poll_fn(|cx| { 663 poll_fn(|cx| {
653 EP0_WAKER.register(cx.waker()); 664 EP0_WAKER.register(cx.waker());
654 let regs = T::regs(); 665 let regs = self.regs;
655 if regs.events_ep0datadone().read() != 0 { 666 if regs.events_ep0datadone().read() != 0 {
656 Poll::Ready(Ok(())) 667 Poll::Ready(Ok(()))
657 } else if regs.events_usbreset().read() != 0 { 668 } else if regs.events_usbreset().read() != 0 {
@@ -666,17 +677,17 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
666 }) 677 })
667 .await?; 678 .await?;
668 679
669 unsafe { read_dma::<T>(0, buf) } 680 unsafe { read_dma(self.regs, 0, buf) }
670 } 681 }
671 682
672 async fn data_in(&mut self, buf: &[u8], _first: bool, last: bool) -> Result<(), EndpointError> { 683 async fn data_in(&mut self, buf: &[u8], _first: bool, last: bool) -> Result<(), EndpointError> {
673 let regs = T::regs(); 684 let regs = self.regs;
674 regs.events_ep0datadone().write_value(0); 685 regs.events_ep0datadone().write_value(0);
675 686
676 regs.shorts().write(|w| w.set_ep0datadone_ep0status(last)); 687 regs.shorts().write(|w| w.set_ep0datadone_ep0status(last));
677 688
678 // This starts a TX on EP0. events_ep0datadone notifies when done. 689 // This starts a TX on EP0. events_ep0datadone notifies when done.
679 unsafe { write_dma::<T>(0, buf) } 690 unsafe { write_dma(self.regs, 0, buf) }
680 691
681 regs.intenset().write(|w| { 692 regs.intenset().write(|w| {
682 w.set_usbreset(true); 693 w.set_usbreset(true);
@@ -687,7 +698,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
687 poll_fn(|cx| { 698 poll_fn(|cx| {
688 cx.waker().wake_by_ref(); 699 cx.waker().wake_by_ref();
689 EP0_WAKER.register(cx.waker()); 700 EP0_WAKER.register(cx.waker());
690 let regs = T::regs(); 701 let regs = self.regs;
691 if regs.events_ep0datadone().read() != 0 { 702 if regs.events_ep0datadone().read() != 0 {
692 Poll::Ready(Ok(())) 703 Poll::Ready(Ok(()))
693 } else if regs.events_usbreset().read() != 0 { 704 } else if regs.events_usbreset().read() != 0 {
@@ -704,12 +715,12 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
704 } 715 }
705 716
706 async fn accept(&mut self) { 717 async fn accept(&mut self) {
707 let regs = T::regs(); 718 let regs = self.regs;
708 regs.tasks_ep0status().write_value(1); 719 regs.tasks_ep0status().write_value(1);
709 } 720 }
710 721
711 async fn reject(&mut self) { 722 async fn reject(&mut self) {
712 let regs = T::regs(); 723 let regs = self.regs;
713 regs.tasks_ep0stall().write_value(1); 724 regs.tasks_ep0stall().write_value(1);
714 } 725 }
715 726
diff --git a/embassy-nrf/src/usb/vbus_detect.rs b/embassy-nrf/src/usb/vbus_detect.rs
index 8794beb2d..33cf91ee2 100644
--- a/embassy-nrf/src/usb/vbus_detect.rs
+++ b/embassy-nrf/src/usb/vbus_detect.rs
@@ -68,7 +68,7 @@ impl interrupt::typelevel::Handler<UsbRegIrq> for InterruptHandler {
68/// [`VbusDetect`] implementation using the native hardware POWER peripheral. 68/// [`VbusDetect`] implementation using the native hardware POWER peripheral.
69/// 69///
70/// Unsuitable for usage with the nRF softdevice, since it reserves exclusive acces 70/// Unsuitable for usage with the nRF softdevice, since it reserves exclusive acces
71/// to POWER. In that case, use [`VbusDetectSignal`]. 71/// to POWER. In that case, use [SoftwareVbusDetect].
72pub struct HardwareVbusDetect { 72pub struct HardwareVbusDetect {
73 _private: (), 73 _private: (),
74} 74}
diff --git a/embassy-nrf/src/wdt.rs b/embassy-nrf/src/wdt.rs
index 7ab9adc29..dc99a16f5 100644
--- a/embassy-nrf/src/wdt.rs
+++ b/embassy-nrf/src/wdt.rs
@@ -66,11 +66,11 @@ impl Default for Config {
66} 66}
67 67
68/// Watchdog driver. 68/// Watchdog driver.
69pub struct Watchdog<T: Instance> { 69pub struct Watchdog {
70 _wdt: Peri<'static, T>, 70 r: pac::wdt::Wdt,
71} 71}
72 72
73impl<T: Instance> Watchdog<T> { 73impl Watchdog {
74 /// Try to create a new watchdog driver. 74 /// Try to create a new watchdog driver.
75 /// 75 ///
76 /// This function will return an error if the watchdog is already active 76 /// This function will return an error if the watchdog is already active
@@ -79,7 +79,7 @@ impl<T: Instance> Watchdog<T> {
79 /// 79 ///
80 /// `N` must be between 1 and 8, inclusive. 80 /// `N` must be between 1 and 8, inclusive.
81 #[inline] 81 #[inline]
82 pub fn try_new<const N: usize>( 82 pub fn try_new<T: Instance, const N: usize>(
83 wdt: Peri<'static, T>, 83 wdt: Peri<'static, T>,
84 config: Config, 84 config: Config,
85 ) -> Result<(Self, [WatchdogHandle; N]), Peri<'static, T>> { 85 ) -> Result<(Self, [WatchdogHandle; N]), Peri<'static, T>> {
@@ -116,7 +116,7 @@ impl<T: Instance> Watchdog<T> {
116 r.tasks_start().write_value(1); 116 r.tasks_start().write_value(1);
117 } 117 }
118 118
119 let this = Self { _wdt: wdt }; 119 let this = Self { r: T::REGS };
120 120
121 let mut handles = [const { WatchdogHandle { index: 0 } }; N]; 121 let mut handles = [const { WatchdogHandle { index: 0 } }; N];
122 for i in 0..N { 122 for i in 0..N {
@@ -135,7 +135,7 @@ impl<T: Instance> Watchdog<T> {
135 /// interrupt has been enabled. 135 /// interrupt has been enabled.
136 #[inline(always)] 136 #[inline(always)]
137 pub fn enable_interrupt(&mut self) { 137 pub fn enable_interrupt(&mut self) {
138 T::REGS.intenset().write(|w| w.set_timeout(true)); 138 self.r.intenset().write(|w| w.set_timeout(true));
139 } 139 }
140 140
141 /// Disable the watchdog interrupt. 141 /// Disable the watchdog interrupt.
@@ -143,7 +143,7 @@ impl<T: Instance> Watchdog<T> {
143 /// NOTE: This has no effect on the reset caused by the Watchdog. 143 /// NOTE: This has no effect on the reset caused by the Watchdog.
144 #[inline(always)] 144 #[inline(always)]
145 pub fn disable_interrupt(&mut self) { 145 pub fn disable_interrupt(&mut self) {
146 T::REGS.intenclr().write(|w| w.set_timeout(true)); 146 self.r.intenclr().write(|w| w.set_timeout(true));
147 } 147 }
148 148
149 /// Is the watchdog still awaiting pets from any handle? 149 /// Is the watchdog still awaiting pets from any handle?
@@ -152,9 +152,8 @@ impl<T: Instance> Watchdog<T> {
152 /// handles to prevent a reset this time period. 152 /// handles to prevent a reset this time period.
153 #[inline(always)] 153 #[inline(always)]
154 pub fn awaiting_pets(&self) -> bool { 154 pub fn awaiting_pets(&self) -> bool {
155 let r = T::REGS; 155 let enabled = self.r.rren().read().0;
156 let enabled = r.rren().read().0; 156 let status = self.r.reqstatus().read().0;
157 let status = r.reqstatus().read().0;
158 (status & enabled) == 0 157 (status & enabled) == 0
159 } 158 }
160} 159}
diff --git a/embassy-nxp/CHANGELOG.md b/embassy-nxp/CHANGELOG.md
index ab97c4185..0fb677cd8 100644
--- a/embassy-nxp/CHANGELOG.md
+++ b/embassy-nxp/CHANGELOG.md
@@ -7,5 +7,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7 7
8<!-- next-header --> 8<!-- next-header -->
9## Unreleased - ReleaseDate 9## Unreleased - ReleaseDate
10- LPC55: DMA Controller and asynchronous version of USART
10- Moved NXP LPC55S69 from `lpc55-pac` to `nxp-pac` 11- Moved NXP LPC55S69 from `lpc55-pac` to `nxp-pac`
11- First release with changelog. 12- First release with changelog.
diff --git a/embassy-nxp/Cargo.toml b/embassy-nxp/Cargo.toml
index 455915f29..f3c828313 100644
--- a/embassy-nxp/Cargo.toml
+++ b/embassy-nxp/Cargo.toml
@@ -2,6 +2,7 @@
2name = "embassy-nxp" 2name = "embassy-nxp"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0"
5 6
6publish = false 7publish = false
7 8
@@ -28,6 +29,7 @@ cortex-m-rt = "0.7.0"
28critical-section = "1.1.2" 29critical-section = "1.1.2"
29embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } 30embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] }
30embassy-sync = { version = "0.7.2", path = "../embassy-sync" } 31embassy-sync = { version = "0.7.2", path = "../embassy-sync" }
32embassy-futures = { version = "0.1.2", path = "../embassy-futures"}
31defmt = { version = "1", optional = true } 33defmt = { version = "1", optional = true }
32log = { version = "0.4.27", optional = true } 34log = { version = "0.4.27", optional = true }
33embassy-time = { version = "0.5.0", path = "../embassy-time", optional = true } 35embassy-time = { version = "0.5.0", path = "../embassy-time", optional = true }
diff --git a/embassy-nxp/src/chips/lpc55.rs b/embassy-nxp/src/chips/lpc55.rs
index 711bff3e7..9f4e7269f 100644
--- a/embassy-nxp/src/chips/lpc55.rs
+++ b/embassy-nxp/src/chips/lpc55.rs
@@ -1,5 +1,9 @@
1pub use nxp_pac as pac; 1pub use nxp_pac as pac;
2 2
3embassy_hal_internal::interrupt_mod!(
4 FLEXCOMM0, FLEXCOMM1, FLEXCOMM2, FLEXCOMM3, FLEXCOMM4, FLEXCOMM5, FLEXCOMM6, FLEXCOMM7
5);
6
3embassy_hal_internal::peripherals! { 7embassy_hal_internal::peripherals! {
4 // External pins. These are not only GPIOs, they are multi-purpose pins and can be used by other 8 // External pins. These are not only GPIOs, they are multi-purpose pins and can be used by other
5 // peripheral types (e.g. I2C). 9 // peripheral types (e.g. I2C).
@@ -68,6 +72,32 @@ embassy_hal_internal::peripherals! {
68 PIO1_30, 72 PIO1_30,
69 PIO1_31, 73 PIO1_31,
70 74
75 // Direct Memory Access (DMA) channels. They are used for asynchronous modes of peripherals.
76 DMA_CH0,
77 DMA_CH1,
78 DMA_CH2,
79 DMA_CH3,
80 DMA_CH4,
81 DMA_CH5,
82 DMA_CH6,
83 DMA_CH7,
84 DMA_CH8,
85 DMA_CH9,
86 DMA_CH10,
87 DMA_CH11,
88 DMA_CH12,
89 DMA_CH13,
90 DMA_CH14,
91 DMA_CH15,
92 DMA_CH16,
93 DMA_CH17,
94 DMA_CH18,
95 DMA_CH19,
96 DMA_CH20,
97 DMA_CH21,
98 DMA_CH22,
99
100 // Universal Synchronous/Asynchronous Receiver/Transmitter (USART) instances.
71 USART0, 101 USART0,
72 USART1, 102 USART1,
73 USART2, 103 USART2,
diff --git a/embassy-nxp/src/dma.rs b/embassy-nxp/src/dma.rs
new file mode 100644
index 000000000..e2df65fc9
--- /dev/null
+++ b/embassy-nxp/src/dma.rs
@@ -0,0 +1,5 @@
1//! Direct Memory Access (DMA) driver.
2
3#[cfg_attr(feature = "lpc55-core0", path = "./dma/lpc55.rs")]
4mod inner;
5pub use inner::*;
diff --git a/embassy-nxp/src/dma/lpc55.rs b/embassy-nxp/src/dma/lpc55.rs
new file mode 100644
index 000000000..578d1fd88
--- /dev/null
+++ b/embassy-nxp/src/dma/lpc55.rs
@@ -0,0 +1,377 @@
1use core::cell::RefCell;
2use core::future::Future;
3use core::pin::Pin;
4use core::sync::atomic::{compiler_fence, Ordering};
5use core::task::{Context, Poll};
6
7use critical_section::Mutex;
8use embassy_hal_internal::interrupt::InterruptExt;
9use embassy_hal_internal::{impl_peripheral, PeripheralType};
10use embassy_sync::waitqueue::AtomicWaker;
11
12use crate::pac::{DMA0, SYSCON, *};
13use crate::{peripherals, Peri};
14
15#[interrupt]
16fn DMA0() {
17 let inta = DMA0.inta0().read().ia();
18 for channel in 0..CHANNEL_COUNT {
19 if (DMA0.errint0().read().err() & (1 << channel)) != 0 {
20 panic!("DMA: error on DMA_0 channel {}", channel);
21 }
22
23 if (inta & (1 << channel)) != 0 {
24 CHANNEL_WAKERS[channel].wake();
25 DMA0.inta0().modify(|w| w.set_ia(1 << channel));
26 }
27 }
28}
29
30pub(crate) fn init() {
31 assert_eq!(core::mem::size_of::<DmaDescriptor>(), 16, "Descriptor must be 16 bytes");
32 assert_eq!(
33 core::mem::align_of::<DmaDescriptor>(),
34 16,
35 "Descriptor must be 16-byte aligned"
36 );
37 assert_eq!(
38 core::mem::align_of::<DmaDescriptorTable>(),
39 512,
40 "Table must be 512-byte aligned"
41 );
42 // Start clock for DMA
43 SYSCON.ahbclkctrl0().modify(|w| w.set_dma0(true));
44 // Reset DMA
45 SYSCON
46 .presetctrl0()
47 .modify(|w| w.set_dma0_rst(syscon::vals::Dma0Rst::ASSERTED));
48 SYSCON
49 .presetctrl0()
50 .modify(|w| w.set_dma0_rst(syscon::vals::Dma0Rst::RELEASED));
51
52 // Address bits 31:9 of the beginning of the DMA descriptor table
53 critical_section::with(|cs| {
54 DMA0.srambase()
55 .write(|w| w.set_offset((DMA_DESCRIPTORS.borrow(cs).as_ptr() as u32) >> 9));
56 });
57 // Enable DMA controller
58 DMA0.ctrl().modify(|w| w.set_enable(true));
59
60 unsafe {
61 crate::pac::interrupt::DMA0.enable();
62 }
63 info!("DMA initialized");
64}
65
66/// DMA read.
67///
68/// SAFETY: Slice must point to a valid location reachable by DMA.
69pub unsafe fn read<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: *const W, to: *mut [W]) -> Transfer<'a, C> {
70 copy_inner(
71 ch,
72 from as *const u32,
73 to as *mut W as *mut u32,
74 to.len(),
75 W::size(),
76 false,
77 true,
78 )
79}
80
81/// DMA write.
82///
83/// SAFETY: Slice must point to a valid location reachable by DMA.
84pub unsafe fn write<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: *const [W], to: *mut W) -> Transfer<'a, C> {
85 copy_inner(
86 ch,
87 from as *const W as *const u32,
88 to as *mut u32,
89 from.len(),
90 W::size(),
91 true,
92 false,
93 )
94}
95
96/// DMA copy between slices.
97///
98/// SAFETY: Slices must point to locations reachable by DMA.
99pub unsafe fn copy<'a, C: Channel, W: Word>(ch: Peri<'a, C>, from: &[W], to: &mut [W]) -> Transfer<'a, C> {
100 let from_len = from.len();
101 let to_len = to.len();
102 assert_eq!(from_len, to_len);
103 copy_inner(
104 ch,
105 from.as_ptr() as *const u32,
106 to.as_mut_ptr() as *mut u32,
107 from_len,
108 W::size(),
109 true,
110 true,
111 )
112}
113
114fn copy_inner<'a, C: Channel>(
115 ch: Peri<'a, C>,
116 from: *const u32,
117 to: *mut u32,
118 len: usize,
119 data_size: crate::pac::dma::vals::Width,
120 incr_src: bool,
121 incr_dest: bool,
122) -> Transfer<'a, C> {
123 let p = ch.regs();
124
125 // Buffer ending address = buffer starting address + (XFERCOUNT * the transfer increment)
126 // XREFCOUNT = the number of transfers performed - 1.
127 // The 1st transfer is included in the starting address.
128 let source_end_addr = if incr_src {
129 from as u32 + len as u32 - 1
130 } else {
131 from as u32
132 };
133 let dest_end_addr = if incr_dest {
134 to as u32 + len as u32 - 1
135 } else {
136 to as u32
137 };
138
139 compiler_fence(Ordering::SeqCst);
140
141 critical_section::with(|cs| {
142 DMA_DESCRIPTORS.borrow(cs).borrow_mut().descriptors[ch.number() as usize] = DmaDescriptor {
143 reserved: 0,
144 source_end_addr,
145 dest_end_addr,
146 next_desc: 0, // Since only single transfers are made, there is no need for reload descriptor address.
147 }
148 });
149
150 compiler_fence(Ordering::SeqCst);
151
152 p.cfg().modify(|w| {
153 // Peripheral DMA requests are enabled.
154 // DMA requests that pace transfers can be interpreted then.
155 w.set_periphreqen(true);
156 // There is no need to have them on.
157 // No complex transfers are performed for now.
158 w.set_hwtrigen(false);
159 w.set_chpriority(0);
160 });
161
162 p.xfercfg().modify(|w| {
163 // This bit indicates whether the current channel descriptor is
164 // valid and can potentially be acted upon,
165 // if all other activation criteria are fulfilled.
166 w.set_cfgvalid(true);
167 // Indicates whether the channel’s control structure will be reloaded
168 // when the current descriptor is exhausted.
169 // Reloading allows ping-pong and linked transfers.
170 w.set_reload(false);
171 // There is no hardware distinction between interrupt A and B.
172 // They can be used by software to assist with more complex descriptor usage.
173 // By convention, interrupt A may be used when only one interrupt flag is needed.
174 w.set_setinta(true);
175 w.set_setintb(false);
176 w.set_width(data_size);
177 w.set_srcinc(if incr_src {
178 dma::vals::Srcinc::WIDTH_X_1
179 } else {
180 dma::vals::Srcinc::NO_INCREMENT
181 });
182 w.set_dstinc(if incr_dest {
183 dma::vals::Dstinc::WIDTH_X_1
184 } else {
185 dma::vals::Dstinc::NO_INCREMENT
186 });
187 // Total number of transfers to be performed, minus 1 encoded.
188 w.set_xfercount((len as u16) - 1);
189 // Before triggering the channel, it has to be enabled.
190 w.set_swtrig(false);
191 });
192
193 compiler_fence(Ordering::SeqCst);
194 DMA0.enableset0().write(|w| w.set_ena(1 << ch.number()));
195 DMA0.intenset0().write(|w| w.set_inten(1 << ch.number()));
196
197 compiler_fence(Ordering::SeqCst);
198 // Start transfer.
199 DMA0.settrig0().write(|w| w.set_trig(1 << ch.number()));
200 compiler_fence(Ordering::SeqCst);
201 Transfer::new(ch)
202}
203
204/// DMA transfer driver.
205#[must_use = "futures do nothing unless you `.await` or poll them"]
206pub struct Transfer<'a, C: Channel> {
207 channel: Peri<'a, C>,
208}
209
210impl<'a, C: Channel> Transfer<'a, C> {
211 pub(crate) fn new(channel: Peri<'a, C>) -> Self {
212 Self { channel }
213 }
214}
215
216impl<'a, C: Channel> Drop for Transfer<'a, C> {
217 fn drop(&mut self) {
218 DMA0.enableclr0().write(|w| w.set_clr(1 << self.channel.number()));
219 while (DMA0.busy0().read().bsy() & (1 << self.channel.number())) != 0 {}
220 DMA0.abort0().write(|w| w.set_abortctrl(1 << self.channel.number()));
221 }
222}
223
224impl<'a, C: Channel> Unpin for Transfer<'a, C> {}
225impl<'a, C: Channel> Future for Transfer<'a, C> {
226 type Output = ();
227 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
228 // We need to register/re-register the waker for each poll because any
229 // calls to wake will deregister the waker.
230 CHANNEL_WAKERS[self.channel.number() as usize].register(cx.waker());
231 // Check if it is busy or not.
232 if (DMA0.busy0().read().bsy() & (1 << self.channel.number())) != 0 {
233 Poll::Pending
234 } else {
235 Poll::Ready(())
236 }
237 }
238}
239
240// Total number of channles including both DMA0 and DMA1.
241// In spite of using only DMA0 channels, the descriptor table
242// should be of this size.
243pub(crate) const CHANNEL_COUNT: usize = 32;
244
245static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT];
246
247// See section 22.5.2 (table 450)
248// UM11126, Rev. 2.8
249// The size of a descriptor must be aligned to a multiple of 16 bytes.
250#[repr(C, align(16))]
251#[derive(Clone, Copy)]
252struct DmaDescriptor {
253 /// 0x0 Reserved.
254 reserved: u32,
255 /// 0x4 Source data end address.
256 source_end_addr: u32,
257 /// 0x8 Destination end address.
258 dest_end_addr: u32,
259 /// 0xC Link to next descriptor.
260 next_desc: u32,
261}
262
263// See section 22.6.3
264// UM11126, Rev. 2.8
265// The table must begin on a 512 byte boundary.
266#[repr(C, align(512))]
267struct DmaDescriptorTable {
268 descriptors: [DmaDescriptor; CHANNEL_COUNT],
269}
270
271// DMA descriptors are stored in on-chip SRAM.
272static DMA_DESCRIPTORS: Mutex<RefCell<DmaDescriptorTable>> = Mutex::new(RefCell::new(DmaDescriptorTable {
273 descriptors: [DmaDescriptor {
274 reserved: 0,
275 source_end_addr: 0,
276 dest_end_addr: 0,
277 next_desc: 0,
278 }; CHANNEL_COUNT],
279}));
280
281trait SealedChannel {}
282trait SealedWord {}
283
284/// DMA channel interface.
285#[allow(private_bounds)]
286pub trait Channel: PeripheralType + SealedChannel + Into<AnyChannel> + Sized + 'static {
287 /// Channel number.
288 fn number(&self) -> u8;
289
290 /// Channel registry block.
291 fn regs(&self) -> crate::pac::dma::Channel {
292 crate::pac::DMA0.channel(self.number() as _)
293 }
294}
295
296/// DMA word.
297#[allow(private_bounds)]
298pub trait Word: SealedWord {
299 /// Word size.
300 fn size() -> crate::pac::dma::vals::Width;
301}
302
303impl SealedWord for u8 {}
304impl Word for u8 {
305 fn size() -> crate::pac::dma::vals::Width {
306 crate::pac::dma::vals::Width::BIT_8
307 }
308}
309
310impl SealedWord for u16 {}
311impl Word for u16 {
312 fn size() -> crate::pac::dma::vals::Width {
313 crate::pac::dma::vals::Width::BIT_16
314 }
315}
316
317impl SealedWord for u32 {}
318impl Word for u32 {
319 fn size() -> crate::pac::dma::vals::Width {
320 crate::pac::dma::vals::Width::BIT_32
321 }
322}
323
324/// Type erased DMA channel.
325pub struct AnyChannel {
326 number: u8,
327}
328
329impl_peripheral!(AnyChannel);
330
331impl SealedChannel for AnyChannel {}
332impl Channel for AnyChannel {
333 fn number(&self) -> u8 {
334 self.number
335 }
336}
337
338macro_rules! channel {
339 ($name:ident, $num:expr) => {
340 impl SealedChannel for peripherals::$name {}
341 impl Channel for peripherals::$name {
342 fn number(&self) -> u8 {
343 $num
344 }
345 }
346
347 impl From<peripherals::$name> for crate::dma::AnyChannel {
348 fn from(val: peripherals::$name) -> Self {
349 Self { number: val.number() }
350 }
351 }
352 };
353}
354
355channel!(DMA_CH0, 0);
356channel!(DMA_CH1, 1);
357channel!(DMA_CH2, 2);
358channel!(DMA_CH3, 3);
359channel!(DMA_CH4, 4);
360channel!(DMA_CH5, 5);
361channel!(DMA_CH6, 6);
362channel!(DMA_CH7, 7);
363channel!(DMA_CH8, 8);
364channel!(DMA_CH9, 9);
365channel!(DMA_CH10, 10);
366channel!(DMA_CH11, 11);
367channel!(DMA_CH12, 12);
368channel!(DMA_CH13, 13);
369channel!(DMA_CH14, 14);
370channel!(DMA_CH15, 15);
371channel!(DMA_CH16, 16);
372channel!(DMA_CH17, 17);
373channel!(DMA_CH18, 18);
374channel!(DMA_CH19, 19);
375channel!(DMA_CH20, 20);
376channel!(DMA_CH21, 21);
377channel!(DMA_CH22, 22);
diff --git a/embassy-nxp/src/lib.rs b/embassy-nxp/src/lib.rs
index 74142a10b..f0f0afb6c 100644
--- a/embassy-nxp/src/lib.rs
+++ b/embassy-nxp/src/lib.rs
@@ -3,6 +3,8 @@
3// This mod MUST go first, so that the others see its macros. 3// This mod MUST go first, so that the others see its macros.
4pub(crate) mod fmt; 4pub(crate) mod fmt;
5 5
6#[cfg(feature = "lpc55-core0")]
7pub mod dma;
6pub mod gpio; 8pub mod gpio;
7#[cfg(feature = "lpc55-core0")] 9#[cfg(feature = "lpc55-core0")]
8pub mod pint; 10pub mod pint;
@@ -20,6 +22,9 @@ mod time_driver;
20#[cfg_attr(feature = "mimxrt1062", path = "chips/mimxrt1062.rs")] 22#[cfg_attr(feature = "mimxrt1062", path = "chips/mimxrt1062.rs")]
21mod chip; 23mod chip;
22 24
25// TODO: Remove when this module is implemented for other chips
26#[cfg(feature = "lpc55-core0")]
27pub use chip::interrupt;
23#[cfg(feature = "unstable-pac")] 28#[cfg(feature = "unstable-pac")]
24pub use chip::pac; 29pub use chip::pac;
25#[cfg(not(feature = "unstable-pac"))] 30#[cfg(not(feature = "unstable-pac"))]
@@ -27,6 +32,67 @@ pub(crate) use chip::pac;
27pub use chip::{peripherals, Peripherals}; 32pub use chip::{peripherals, Peripherals};
28pub use embassy_hal_internal::{Peri, PeripheralType}; 33pub use embassy_hal_internal::{Peri, PeripheralType};
29 34
35/// Macro to bind interrupts to handlers.
36/// (Copied from `embassy-rp`)
37/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
38/// and implements the right [`Binding`]s for it. You can pass this struct to drivers to
39/// prove at compile-time that the right interrupts have been bound.
40///
41/// Example of how to bind one interrupt:
42///
43/// ```rust,ignore
44/// use embassy_nxp::{bind_interrupts, usart, peripherals};
45///
46/// bind_interrupts!(
47/// /// Binds the USART Interrupts.
48/// struct Irqs {
49/// FLEXCOMM0 => usart::InterruptHandler<peripherals::USART0>;
50/// }
51/// );
52/// ```
53#[macro_export]
54macro_rules! bind_interrupts {
55 ($(#[$attr:meta])* $vis:vis struct $name:ident {
56 $(
57 $(#[cfg($cond_irq:meta)])?
58 $irq:ident => $(
59 $(#[cfg($cond_handler:meta)])?
60 $handler:ty
61 ),*;
62 )*
63 }) => {
64 #[derive(Copy, Clone)]
65 $(#[$attr])*
66 $vis struct $name;
67
68 $(
69 #[allow(non_snake_case)]
70 #[no_mangle]
71 $(#[cfg($cond_irq)])?
72 unsafe extern "C" fn $irq() {
73 unsafe {
74 $(
75 $(#[cfg($cond_handler)])?
76 <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt();
77
78 )*
79 }
80 }
81
82 $(#[cfg($cond_irq)])?
83 $crate::bind_interrupts!(@inner
84 $(
85 $(#[cfg($cond_handler)])?
86 unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {}
87 )*
88 );
89 )*
90 };
91 (@inner $($t:tt)*) => {
92 $($t)*
93 }
94}
95
30/// Initialize the `embassy-nxp` HAL with the provided configuration. 96/// Initialize the `embassy-nxp` HAL with the provided configuration.
31/// 97///
32/// This returns the peripheral singletons that can be used for creating drivers. 98/// This returns the peripheral singletons that can be used for creating drivers.
@@ -92,6 +158,9 @@ pub fn init(_config: config::Config) -> Peripherals {
92 #[cfg(feature = "_time_driver")] 158 #[cfg(feature = "_time_driver")]
93 time_driver::init(); 159 time_driver::init();
94 160
161 #[cfg(feature = "lpc55-core0")]
162 dma::init();
163
95 peripherals 164 peripherals
96} 165}
97 166
@@ -133,5 +202,8 @@ macro_rules! impl_mode {
133 202
134/// Blocking mode. 203/// Blocking mode.
135pub struct Blocking; 204pub struct Blocking;
205/// Asynchronous mode.
206pub struct Async;
136 207
137impl_mode!(Blocking); 208impl_mode!(Blocking);
209impl_mode!(Async);
diff --git a/embassy-nxp/src/usart/lpc55.rs b/embassy-nxp/src/usart/lpc55.rs
index 428b80c4b..9034ed429 100644
--- a/embassy-nxp/src/usart/lpc55.rs
+++ b/embassy-nxp/src/usart/lpc55.rs
@@ -1,14 +1,24 @@
1use core::fmt::Debug;
2use core::future::poll_fn;
1use core::marker::PhantomData; 3use core::marker::PhantomData;
4use core::sync::atomic::{AtomicBool, Ordering};
5use core::task::Poll;
2 6
7use embassy_futures::select::{select, Either};
8use embassy_hal_internal::interrupt::InterruptExt;
3use embassy_hal_internal::{Peri, PeripheralType}; 9use embassy_hal_internal::{Peri, PeripheralType};
10use embassy_sync::waitqueue::AtomicWaker;
4use embedded_io::{self, ErrorKind}; 11use embedded_io::{self, ErrorKind};
5 12
13use crate::dma::{AnyChannel, Channel};
6use crate::gpio::{match_iocon, AnyPin, Bank, SealedPin}; 14use crate::gpio::{match_iocon, AnyPin, Bank, SealedPin};
15use crate::interrupt::typelevel::{Binding, Interrupt as _};
16use crate::interrupt::Interrupt;
7use crate::pac::flexcomm::Flexcomm as FlexcommReg; 17use crate::pac::flexcomm::Flexcomm as FlexcommReg;
8use crate::pac::iocon::vals::PioFunc; 18use crate::pac::iocon::vals::PioFunc;
9use crate::pac::usart::Usart as UsartReg; 19use crate::pac::usart::Usart as UsartReg;
10use crate::pac::*; 20use crate::pac::*;
11use crate::{Blocking, Mode}; 21use crate::{Async, Blocking, Mode};
12 22
13/// Serial error 23/// Serial error
14#[derive(Debug, Eq, PartialEq, Copy, Clone)] 24#[derive(Debug, Eq, PartialEq, Copy, Clone)]
@@ -101,6 +111,12 @@ impl Default for Config {
101 } 111 }
102} 112}
103 113
114/// Internal DMA state of UART RX.
115pub struct DmaState {
116 rx_err_waker: AtomicWaker,
117 rx_err: AtomicBool,
118}
119
104/// # Type parameters 120/// # Type parameters
105/// 'd: the lifetime marker ensuring correct borrow checking for peripherals used at compile time 121/// 'd: the lifetime marker ensuring correct borrow checking for peripherals used at compile time
106/// T: the peripheral instance type allowing usage of peripheral specific registers 122/// T: the peripheral instance type allowing usage of peripheral specific registers
@@ -112,24 +128,33 @@ pub struct Usart<'d, M: Mode> {
112 128
113pub struct UsartTx<'d, M: Mode> { 129pub struct UsartTx<'d, M: Mode> {
114 info: &'static Info, 130 info: &'static Info,
115 phantom: PhantomData<(&'d (), M)>, 131 tx_dma: Option<Peri<'d, AnyChannel>>,
132 phantom: PhantomData<M>,
116} 133}
117 134
118pub struct UsartRx<'d, M: Mode> { 135pub struct UsartRx<'d, M: Mode> {
119 info: &'static Info, 136 info: &'static Info,
120 phantom: PhantomData<(&'d (), M)>, 137 dma_state: &'static DmaState,
138 rx_dma: Option<Peri<'d, AnyChannel>>,
139 phantom: PhantomData<M>,
121} 140}
122 141
123impl<'d, M: Mode> UsartTx<'d, M> { 142impl<'d, M: Mode> UsartTx<'d, M> {
124 pub fn new<T: Instance>(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self { 143 pub fn new<T: Instance>(
144 _usart: Peri<'d, T>,
145 tx: Peri<'d, impl TxPin<T>>,
146 tx_dma: Peri<'d, impl Channel>,
147 config: Config,
148 ) -> Self {
125 Usart::<M>::init::<T>(Some(tx.into()), None, config); 149 Usart::<M>::init::<T>(Some(tx.into()), None, config);
126 Self::new_inner(T::info()) 150 Self::new_inner(T::info(), Some(tx_dma.into()))
127 } 151 }
128 152
129 #[inline] 153 #[inline]
130 fn new_inner(info: &'static Info) -> Self { 154 fn new_inner(info: &'static Info, tx_dma: Option<Peri<'d, AnyChannel>>) -> Self {
131 Self { 155 Self {
132 info, 156 info,
157 tx_dma,
133 phantom: PhantomData, 158 phantom: PhantomData,
134 } 159 }
135 } 160 }
@@ -155,20 +180,65 @@ impl<'d, M: Mode> UsartTx<'d, M> {
155impl<'d> UsartTx<'d, Blocking> { 180impl<'d> UsartTx<'d, Blocking> {
156 pub fn new_blocking<T: Instance>(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self { 181 pub fn new_blocking<T: Instance>(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self {
157 Usart::<Blocking>::init::<T>(Some(tx.into()), None, config); 182 Usart::<Blocking>::init::<T>(Some(tx.into()), None, config);
158 Self::new_inner(T::info()) 183 Self::new_inner(T::info(), None)
159 } 184 }
160} 185}
161 186
187impl<'d> UsartTx<'d, Async> {
188 /// Write to UART TX from the provided buffer using DMA.
189 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
190 // Unwrap() can be used because UsartTx::new() in Async mode always sets it to Some
191 let ch = self.tx_dma.as_mut().unwrap().reborrow();
192 let transfer = unsafe {
193 // Enable to pace DMA transfers.
194 self.info.usart_reg.fifocfg().modify(|w| w.set_dmatx(true));
195 // If future is not assigned to a variable, the data register pointer
196 // is held across an await and makes the future non-Send.
197 crate::dma::write(ch, buffer, self.info.usart_reg.fifowr().as_ptr() as *mut _)
198 };
199 transfer.await;
200 Ok(())
201 }
202}
162impl<'d, M: Mode> UsartRx<'d, M> { 203impl<'d, M: Mode> UsartRx<'d, M> {
163 pub fn new<T: Instance>(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self { 204 pub fn new<T: Instance>(
205 _usart: Peri<'d, T>,
206 rx: Peri<'d, impl RxPin<T>>,
207 has_irq: bool,
208 rx_dma: Peri<'d, impl Channel>,
209 config: Config,
210 ) -> Self {
164 Usart::<M>::init::<T>(None, Some(rx.into()), config); 211 Usart::<M>::init::<T>(None, Some(rx.into()), config);
165 Self::new_inner(T::info()) 212 Self::new_inner(T::info(), T::dma_state(), has_irq, Some(rx_dma.into()))
166 } 213 }
167 214
168 #[inline] 215 fn new_inner(
169 fn new_inner(info: &'static Info) -> Self { 216 info: &'static Info,
217 dma_state: &'static DmaState,
218 has_irq: bool,
219 rx_dma: Option<Peri<'d, AnyChannel>>,
220 ) -> Self {
221 core::debug_assert_eq!(has_irq, rx_dma.is_some());
222 if has_irq {
223 // Disable all the related interrupts for now.
224 info.usart_reg.intenclr().write(|w| {
225 w.set_framerrclr(true);
226 w.set_parityerrclr(true);
227 w.set_rxnoiseclr(true);
228 });
229 info.usart_reg.fifointenclr().modify(|w| {
230 w.set_rxlvl(true);
231 w.set_rxerr(true);
232 });
233 info.interrupt.unpend();
234 unsafe {
235 info.interrupt.enable();
236 }
237 }
170 Self { 238 Self {
171 info, 239 info,
240 dma_state,
241 rx_dma,
172 phantom: PhantomData, 242 phantom: PhantomData,
173 } 243 }
174 } 244 }
@@ -211,7 +281,120 @@ impl<'d, M: Mode> UsartRx<'d, M> {
211impl<'d> UsartRx<'d, Blocking> { 281impl<'d> UsartRx<'d, Blocking> {
212 pub fn new_blocking<T: Instance>(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self { 282 pub fn new_blocking<T: Instance>(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self {
213 Usart::<Blocking>::init::<T>(None, Some(rx.into()), config); 283 Usart::<Blocking>::init::<T>(None, Some(rx.into()), config);
214 Self::new_inner(T::info()) 284 Self::new_inner(T::info(), T::dma_state(), false, None)
285 }
286}
287
288/// Interrupt handler.
289pub struct InterruptHandler<T: Instance> {
290 _uart: PhantomData<T>,
291}
292
293impl<T: Instance> crate::interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
294 unsafe fn on_interrupt() {
295 let regs = T::info().usart_reg;
296 if !regs.fifocfg().read().dmarx() {
297 return;
298 }
299 let state = T::dma_state();
300 state.rx_err.store(true, Ordering::Relaxed);
301 state.rx_err_waker.wake();
302 // Disable the error interrupts instead of clearing the flags. Clearing the
303 // flags would allow the DMA transfer to continue, potentially signaling
304 // completion before we can check for errors that happened *during* the transfer.
305 regs.intenclr().write(|w| {
306 w.set_framerrclr(true);
307 w.set_rxnoiseclr(true);
308 w.set_parityerrclr(true);
309 });
310 regs.fifointenclr().write(|w| w.set_rxerr(true));
311 }
312}
313
314impl<'d> UsartRx<'d, Async> {
315 /// Read from USART RX into the provided buffer.
316 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
317 // Clear error flags before the FIFO is drained. Errors that have accumulated
318 // in the flags will also be present in the FIFO.
319 self.dma_state.rx_err.store(false, Ordering::Relaxed);
320 self.info.usart_reg.intenclr().write(|w| {
321 w.set_framerrclr(true);
322 w.set_parityerrclr(true);
323 w.set_rxnoiseclr(true);
324 });
325 self.info.usart_reg.fifointenclr().modify(|w| w.set_rxerr(true));
326 // Then drain the fifo. It is necessary to read at most 16 bytes (the size of FIFO).
327 // Errors that apply to FIFO bytes will be reported directly.
328 let buffer = match {
329 let limit = buffer.len().min(16);
330 self.drain_fifo(&mut buffer[0..limit])
331 } {
332 Ok(len) if len < buffer.len() => &mut buffer[len..],
333 Ok(_) => return Ok(()),
334 Err((_i, e)) => return Err(e),
335 };
336
337 // Start a DMA transfer. If errors have happened in the interim some error
338 // interrupt flags will have been raised, and those will be picked up immediately
339 // by the interrupt handler.
340 // Unwrap() can be used because UsartRx::new() in Async mode always sets it to Some
341 let ch = self.rx_dma.as_mut().unwrap().reborrow();
342
343 self.info.usart_reg.intenset().write(|w| {
344 w.set_framerren(true);
345 w.set_parityerren(true);
346 w.set_rxnoiseen(true);
347 });
348 self.info.usart_reg.fifointenset().modify(|w| w.set_rxerr(true));
349 self.info.usart_reg.fifocfg().modify(|w| w.set_dmarx(true));
350 let transfer = unsafe {
351 // If we don't assign future to a variable, the data register pointer
352 // is held across an await and makes the future non-Send.
353 crate::dma::read(ch, self.info.usart_reg.fiford().as_ptr() as *const _, buffer)
354 };
355
356 // wait for either the transfer to complete or an error to happen.
357 let transfer_result = select(
358 transfer,
359 poll_fn(|cx| {
360 self.dma_state.rx_err_waker.register(cx.waker());
361 match self.dma_state.rx_err.swap(false, Ordering::Relaxed) {
362 false => Poll::Pending,
363 e => Poll::Ready(e),
364 }
365 }),
366 )
367 .await;
368
369 let errors = match transfer_result {
370 Either::First(()) => {
371 // The DMA controller finished, BUT if an error occurred on the LAST
372 // byte, then we may still need to grab the error state!
373 self.dma_state.rx_err.swap(false, Ordering::Relaxed)
374 }
375 Either::Second(e) => {
376 // There is an error, which means this is the error that
377 // was problematic.
378 e
379 }
380 };
381
382 // If we got no error, just return at this point
383 if !errors {
384 return Ok(());
385 }
386
387 // If we DID get an error, we need to figure out which one it was.
388 if self.info.usart_reg.intstat().read().framerrint() {
389 return Err(Error::Framing);
390 } else if self.info.usart_reg.intstat().read().parityerrint() {
391 return Err(Error::Parity);
392 } else if self.info.usart_reg.intstat().read().rxnoiseint() {
393 return Err(Error::Noise);
394 } else if self.info.usart_reg.fifointstat().read().rxerr() {
395 return Err(Error::Overrun);
396 }
397 unreachable!("unrecognized rx error");
215 } 398 }
216} 399}
217 400
@@ -222,7 +405,29 @@ impl<'d> Usart<'d, Blocking> {
222 rx: Peri<'d, impl RxPin<T>>, 405 rx: Peri<'d, impl RxPin<T>>,
223 config: Config, 406 config: Config,
224 ) -> Self { 407 ) -> Self {
225 Self::new_inner(usart, tx.into(), rx.into(), config) 408 Self::new_inner(usart, tx.into(), rx.into(), false, None, None, config)
409 }
410}
411
412impl<'d> Usart<'d, Async> {
413 pub fn new<T: Instance>(
414 uart: Peri<'d, T>,
415 tx: Peri<'d, impl TxPin<T>>,
416 rx: Peri<'d, impl RxPin<T>>,
417 _irq: impl Binding<T::Interrupt, InterruptHandler<T>>,
418 tx_dma: Peri<'d, impl TxChannel<T>>,
419 rx_dma: Peri<'d, impl RxChannel<T>>,
420 config: Config,
421 ) -> Self {
422 Self::new_inner(
423 uart,
424 tx.into(),
425 rx.into(),
426 true,
427 Some(tx_dma.into()),
428 Some(rx_dma.into()),
429 config,
430 )
226 } 431 }
227} 432}
228 433
@@ -231,12 +436,15 @@ impl<'d, M: Mode> Usart<'d, M> {
231 _usart: Peri<'d, T>, 436 _usart: Peri<'d, T>,
232 mut tx: Peri<'d, AnyPin>, 437 mut tx: Peri<'d, AnyPin>,
233 mut rx: Peri<'d, AnyPin>, 438 mut rx: Peri<'d, AnyPin>,
439 has_irq: bool,
440 tx_dma: Option<Peri<'d, AnyChannel>>,
441 rx_dma: Option<Peri<'d, AnyChannel>>,
234 config: Config, 442 config: Config,
235 ) -> Self { 443 ) -> Self {
236 Self::init::<T>(Some(tx.reborrow()), Some(rx.reborrow()), config); 444 Self::init::<T>(Some(tx.reborrow()), Some(rx.reborrow()), config);
237 Self { 445 Self {
238 tx: UsartTx::new_inner(T::info()), 446 tx: UsartTx::new_inner(T::info(), tx_dma),
239 rx: UsartRx::new_inner(T::info()), 447 rx: UsartRx::new_inner(T::info(), T::dma_state(), has_irq, rx_dma),
240 } 448 }
241 } 449 }
242 450
@@ -390,9 +598,11 @@ impl<'d, M: Mode> Usart<'d, M> {
390 SYSCON 598 SYSCON
391 .presetctrl1() 599 .presetctrl1()
392 .modify(|w| w.set_fc_rst(instance_number, syscon::vals::FcRst::RELEASED)); 600 .modify(|w| w.set_fc_rst(instance_number, syscon::vals::FcRst::RELEASED));
393 flexcomm_register 601 flexcomm_register.pselid().modify(|w| {
394 .pselid() 602 w.set_persel(flexcomm::vals::Persel::USART);
395 .modify(|w| w.set_persel(flexcomm::vals::Persel::USART)); 603 // This will lock the peripheral PERSEL and will not allow any changes until the board is reset.
604 w.set_lock(true);
605 });
396 } 606 }
397 607
398 fn configure_usart(info: &'static Info, config: &Config) { 608 fn configure_usart(info: &'static Info, config: &Config) {
@@ -471,6 +681,8 @@ impl<'d, M: Mode> Usart<'d, M> {
471 }); 681 });
472 registers.cfg().modify(|w| w.set_enable(true)); 682 registers.cfg().modify(|w| w.set_enable(true));
473 683
684 registers.fifointenset().modify(|w| w.set_rxerr(true));
685
474 // Drain RX FIFO in case it still has some unrelevant data 686 // Drain RX FIFO in case it still has some unrelevant data
475 while registers.fifostat().read().rxnotempty() { 687 while registers.fifostat().read().rxnotempty() {
476 let _ = registers.fiford().read().0; 688 let _ = registers.fiford().read().0;
@@ -513,6 +725,17 @@ impl<'d, M: Mode> Usart<'d, M> {
513 } 725 }
514} 726}
515 727
728impl<'d> Usart<'d, Async> {
729 /// Write to UART TX from the provided buffer.
730 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
731 self.tx.write(buffer).await
732 }
733
734 /// Read from UART RX into the provided buffer.
735 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
736 self.rx.read(buffer).await
737 }
738}
516impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UsartTx<'d, M> { 739impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UsartTx<'d, M> {
517 type Error = Error; 740 type Error = Error;
518 741
@@ -584,10 +807,12 @@ impl<'d> embedded_io::Read for Usart<'d, Blocking> {
584struct Info { 807struct Info {
585 usart_reg: UsartReg, 808 usart_reg: UsartReg,
586 fc_reg: FlexcommReg, 809 fc_reg: FlexcommReg,
810 interrupt: Interrupt,
587} 811}
588 812
589trait SealedInstance { 813trait SealedInstance {
590 fn info() -> &'static Info; 814 fn info() -> &'static Info;
815 fn dma_state() -> &'static DmaState;
591 fn instance_number() -> usize; 816 fn instance_number() -> usize;
592 fn tx_pin_func() -> PioFunc; 817 fn tx_pin_func() -> PioFunc;
593 fn rx_pin_func() -> PioFunc; 818 fn rx_pin_func() -> PioFunc;
@@ -595,7 +820,10 @@ trait SealedInstance {
595 820
596/// UART instance. 821/// UART instance.
597#[allow(private_bounds)] 822#[allow(private_bounds)]
598pub trait Instance: SealedInstance + PeripheralType {} 823pub trait Instance: SealedInstance + PeripheralType {
824 /// Interrupt for this instance.
825 type Interrupt: crate::interrupt::typelevel::Interrupt;
826}
599 827
600macro_rules! impl_instance { 828macro_rules! impl_instance {
601 ($inst:ident, $fc:ident, $tx_pin:ident, $rx_pin:ident, $fc_num:expr) => { 829 ($inst:ident, $fc:ident, $tx_pin:ident, $rx_pin:ident, $fc_num:expr) => {
@@ -604,9 +832,18 @@ macro_rules! impl_instance {
604 static INFO: Info = Info { 832 static INFO: Info = Info {
605 usart_reg: crate::pac::$inst, 833 usart_reg: crate::pac::$inst,
606 fc_reg: crate::pac::$fc, 834 fc_reg: crate::pac::$fc,
835 interrupt: crate::interrupt::typelevel::$fc::IRQ,
607 }; 836 };
608 &INFO 837 &INFO
609 } 838 }
839
840 fn dma_state() -> &'static DmaState {
841 static STATE: DmaState = DmaState {
842 rx_err_waker: AtomicWaker::new(),
843 rx_err: AtomicBool::new(false),
844 };
845 &STATE
846 }
610 #[inline] 847 #[inline]
611 fn instance_number() -> usize { 848 fn instance_number() -> usize {
612 $fc_num 849 $fc_num
@@ -620,7 +857,9 @@ macro_rules! impl_instance {
620 PioFunc::$rx_pin 857 PioFunc::$rx_pin
621 } 858 }
622 } 859 }
623 impl $crate::usart::Instance for $crate::peripherals::$inst {} 860 impl $crate::usart::Instance for $crate::peripherals::$inst {
861 type Interrupt = crate::interrupt::typelevel::$fc;
862 }
624 }; 863 };
625} 864}
626 865
@@ -663,3 +902,34 @@ impl_pin!(PIO1_16, USART6, Tx);
663impl_pin!(PIO1_13, USART6, Rx); 902impl_pin!(PIO1_13, USART6, Rx);
664impl_pin!(PIO0_19, USART7, Tx); 903impl_pin!(PIO0_19, USART7, Tx);
665impl_pin!(PIO0_20, USART7, Rx); 904impl_pin!(PIO0_20, USART7, Rx);
905
906/// Trait for TX DMA channels.
907pub trait TxChannel<T: Instance>: crate::dma::Channel {}
908/// Trait for RX DMA channels.
909pub trait RxChannel<T: Instance>: crate::dma::Channel {}
910
911macro_rules! impl_channel {
912 ($dma:ident, $instance:ident, Tx) => {
913 impl TxChannel<crate::peripherals::$instance> for crate::peripherals::$dma {}
914 };
915 ($dma:ident, $instance:ident, Rx) => {
916 impl RxChannel<crate::peripherals::$instance> for crate::peripherals::$dma {}
917 };
918}
919
920impl_channel!(DMA_CH4, USART0, Rx);
921impl_channel!(DMA_CH5, USART0, Tx);
922impl_channel!(DMA_CH6, USART1, Rx);
923impl_channel!(DMA_CH7, USART1, Tx);
924impl_channel!(DMA_CH10, USART2, Rx);
925impl_channel!(DMA_CH11, USART2, Tx);
926impl_channel!(DMA_CH8, USART3, Rx);
927impl_channel!(DMA_CH9, USART3, Tx);
928impl_channel!(DMA_CH12, USART4, Rx);
929impl_channel!(DMA_CH13, USART4, Tx);
930impl_channel!(DMA_CH14, USART5, Rx);
931impl_channel!(DMA_CH15, USART5, Tx);
932impl_channel!(DMA_CH16, USART6, Rx);
933impl_channel!(DMA_CH17, USART6, Tx);
934impl_channel!(DMA_CH18, USART7, Rx);
935impl_channel!(DMA_CH19, USART7, Tx);
diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md
index d1265ffc4..e932bcaa3 100644
--- a/embassy-rp/CHANGELOG.md
+++ b/embassy-rp/CHANGELOG.md
@@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
12- Add PIO I2S input 12- Add PIO I2S input
13- Add PIO onewire parasite power strong pullup 13- Add PIO onewire parasite power strong pullup
14- add `wait_for_alarm` and `alarm_scheduled` methods to rtc module ([#4216](https://github.com/embassy-rs/embassy/pull/4216)) 14- add `wait_for_alarm` and `alarm_scheduled` methods to rtc module ([#4216](https://github.com/embassy-rs/embassy/pull/4216))
15- rp235x: use msplim for stack guard instead of MPU
16- Add reset_to_usb_boot for rp235x ([#4705](https://github.com/embassy-rs/embassy/pull/4705))
15 17
16## 0.8.0 - 2025-08-26 18## 0.8.0 - 2025-08-26
17 19
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index 101914a36..f6b0900f2 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -45,6 +45,10 @@ rt = [ "rp-pac/rt" ]
45 45
46## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers. 46## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers.
47defmt = ["dep:defmt", "embassy-usb-driver/defmt", "embassy-hal-internal/defmt"] 47defmt = ["dep:defmt", "embassy-usb-driver/defmt", "embassy-hal-internal/defmt"]
48## Enable log support
49log = ["dep:log"]
50## Enable chrono support
51chrono = ["dep:chrono"]
48 52
49## Configure the [`critical-section`](https://docs.rs/critical-section) crate to use an implementation that is safe for multicore use on rp2040. 53## Configure the [`critical-section`](https://docs.rs/critical-section) crate to use an implementation that is safe for multicore use on rp2040.
50critical-section-impl = ["critical-section/restore-state-u8"] 54critical-section-impl = ["critical-section/restore-state-u8"]
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index 6fb680b34..d03ba1fef 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -565,18 +565,10 @@ unsafe fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> {
565#[cfg(all(feature = "_rp235x", not(feature = "_test")))] 565#[cfg(all(feature = "_rp235x", not(feature = "_test")))]
566#[inline(always)] 566#[inline(always)]
567unsafe fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> { 567unsafe fn install_stack_guard(stack_bottom: *mut usize) -> Result<(), ()> {
568 let core = unsafe { cortex_m::Peripherals::steal() }; 568 // The RP2350 arm cores are cortex-m33 and can use the MSPLIM register to guard the end of stack.
569 // We'll need to do something else for the riscv cores.
570 cortex_m::register::msplim::write(stack_bottom.addr() as u32);
569 571
570 // Fail if MPU is already configured
571 if core.MPU.ctrl.read() != 0 {
572 return Err(());
573 }
574
575 unsafe {
576 core.MPU.ctrl.write(5); // enable mpu with background default map
577 core.MPU.rbar.write(stack_bottom as u32 & !0xff); // set address
578 core.MPU.rlar.write(((stack_bottom as usize + 255) as u32) | 1);
579 }
580 Ok(()) 572 Ok(())
581} 573}
582 574
diff --git a/embassy-rp/src/rom_data/rp235x.rs b/embassy-rp/src/rom_data/rp235x.rs
index b16fee8f7..c0a1ed6fb 100644
--- a/embassy-rp/src/rom_data/rp235x.rs
+++ b/embassy-rp/src/rom_data/rp235x.rs
@@ -750,3 +750,35 @@ pub fn is_secure_mode() -> bool {
750pub fn is_secure_mode() -> bool { 750pub fn is_secure_mode() -> bool {
751 false 751 false
752} 752}
753
754// These and the reset_to_usb_boot function are found from https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/pico_bootrom/bootrom.c#L35-L51
755// The following has just been translated to rust from the original c++
756const BOOTSEL_FLAG_GPIO_PIN_SPECIFIED: u32 = 0x20;
757const REBOOT2_FLAG_REBOOT_TYPE_BOOTSEL: u32 = 0x2;
758const REBOOT2_FLAG_NO_RETURN_ON_SUCCESS: u32 = 0x100;
759
760/// Resets the RP235x and uses the watchdog facility to re-start in BOOTSEL mode:
761/// * gpio_activity_pin_mask is provided to enable an 'activity light' via GPIO attached LED
762/// for the USB Mass Storage Device:
763/// * 0 No pins are used as per cold boot.
764/// * Otherwise a single bit set indicating which GPIO pin should be set to output and
765/// raised whenever there is mass storage activity from the host.
766/// * disable_interface_mask may be used to control the exposed USB interfaces:
767/// * 0 To enable both interfaces (as per cold boot).
768/// * 1 To disable the USB Mass Storage Interface.
769/// * 2 to Disable the USB PICOBOOT Interface.
770pub fn reset_to_usb_boot(mut usb_activity_gpio_pin_mask: u32, disable_interface_mask: u32) {
771 let mut flags = disable_interface_mask;
772
773 if usb_activity_gpio_pin_mask != 0 {
774 flags = flags | BOOTSEL_FLAG_GPIO_PIN_SPECIFIED;
775 usb_activity_gpio_pin_mask = usb_activity_gpio_pin_mask.trailing_zeros()
776 }
777
778 reboot(
779 REBOOT2_FLAG_REBOOT_TYPE_BOOTSEL | REBOOT2_FLAG_NO_RETURN_ON_SUCCESS,
780 10,
781 flags,
782 usb_activity_gpio_pin_mask,
783 );
784}
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
index 190e68d6d..a6ee5c4b8 100644
--- a/embassy-stm32/CHANGELOG.md
+++ b/embassy-stm32/CHANGELOG.md
@@ -22,6 +22,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
22- fix: handle address and data-length errors in OSPI 22- fix: handle address and data-length errors in OSPI
23- feat: Allow OSPI DMA writes larger than 64kB using chunking 23- feat: Allow OSPI DMA writes larger than 64kB using chunking
24- feat: More ADC enums for g0 PAC, API change for oversampling, allow separate sample times 24- feat: More ADC enums for g0 PAC, API change for oversampling, allow separate sample times
25- feat: Add USB CRS sync support for STM32C071
26- fix: RTC register definition for STM32L4P5 and L4Q5 as they use v3 register map.
27- fix: Cut down the capabilities of the STM32L412 and L422 RTC as those are missing binary timer mode and underflow interrupt.
28- fix: Allow configuration of the internal pull up/down resistors on the pins for the Qei peripheral, as well as the Qei decoder mode.
29- feat: stm32/rcc/mco: Added support for IO driver strength when using Master Clock Out IO. This changes signature on Mco::new taking a McoConfig struct ([#4679](https://github.com/embassy-rs/embassy/pull/4679))
30- feat: derive Clone, Copy and defmt::Format for all SPI-related configs
31- feat: stm32/usart: add `eager_reads` option to control if buffered readers return as soon as possible or after more data is available ([#4668](https://github.com/embassy-rs/embassy/pull/4668))
32- feat: stm32/usart: add `de_assertion_time` and `de_deassertion_time` config options
33- change: stm32/uart: BufferedUartRx now returns all available bytes from the internal buffer
25 34
26## 0.4.0 - 2025-08-26 35## 0.4.0 - 2025-08-26
27 36
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 6cd8ed262..82bc73708 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -66,6 +66,10 @@ build = [
66 {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l431cb", "time", "time-driver-any"]}, 66 {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l431cb", "time", "time-driver-any"]},
67 {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l476vg", "time", "time-driver-any"]}, 67 {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l476vg", "time", "time-driver-any"]},
68 {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l422cb", "time", "time-driver-any"]}, 68 {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l422cb", "time", "time-driver-any"]},
69 {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l4p5ae", "time", "time-driver-any", "single-bank"]},
70 {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l4q5zg", "time", "time-driver-any", "single-bank"]},
71 {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l4r9vi", "time", "time-driver-any", "dual-bank"]},
72 {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32l4s7vi", "time", "time-driver-any", "dual-bank"]},
69 {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32wb15cc", "time", "time-driver-any"]}, 73 {target = "thumbv7em-none-eabi", features = ["defmt", "exti", "stm32wb15cc", "time", "time-driver-any"]},
70 {target = "thumbv6m-none-eabi", features = ["defmt", "exti", "stm32l072cz", "time", "time-driver-any"]}, 74 {target = "thumbv6m-none-eabi", features = ["defmt", "exti", "stm32l072cz", "time", "time-driver-any"]},
71 {target = "thumbv6m-none-eabi", features = ["defmt", "exti", "stm32l041f6", "time", "time-driver-any"]}, 75 {target = "thumbv6m-none-eabi", features = ["defmt", "exti", "stm32l041f6", "time", "time-driver-any"]},
@@ -174,7 +178,7 @@ futures-util = { version = "0.3.30", default-features = false }
174sdio-host = "0.9.0" 178sdio-host = "0.9.0"
175critical-section = "1.1" 179critical-section = "1.1"
176#stm32-metapac = { version = "18" } 180#stm32-metapac = { version = "18" }
177stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-3cf72eac610259fd78ef16f1c63be69a144d75f7" } 181stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-b9f6b0c542d85ee695d71c35ced195e0cef51ac0" }
178 182
179vcell = "0.1.3" 183vcell = "0.1.3"
180nb = "1.0.0" 184nb = "1.0.0"
@@ -204,7 +208,7 @@ proc-macro2 = "1.0.36"
204quote = "1.0.15" 208quote = "1.0.15"
205 209
206#stm32-metapac = { version = "18", default-features = false, features = ["metadata"]} 210#stm32-metapac = { version = "18", default-features = false, features = ["metadata"]}
207stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-3cf72eac610259fd78ef16f1c63be69a144d75f7", default-features = false, features = ["metadata"] } 211stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-b9f6b0c542d85ee695d71c35ced195e0cef51ac0", default-features = false, features = ["metadata"] }
208 212
209[features] 213[features]
210default = ["rt"] 214default = ["rt"]
@@ -225,6 +229,10 @@ defmt = [
225 "embassy-usb-synopsys-otg/defmt", 229 "embassy-usb-synopsys-otg/defmt",
226 "stm32-metapac/defmt" 230 "stm32-metapac/defmt"
227] 231]
232## Use log for logging
233log = ["dep:log"]
234## Enable chrono support
235chrono = ["dep:chrono"]
228 236
229exti = [] 237exti = []
230low-power = [ "dep:embassy-executor", "embassy-executor?/arch-cortex-m", "time" ] 238low-power = [ "dep:embassy-executor", "embassy-executor?/arch-cortex-m", "time" ]
diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs
index e2c704405..63fc195dd 100644
--- a/embassy-stm32/src/rcc/bd.rs
+++ b/embassy-stm32/src/rcc/bd.rs
@@ -52,9 +52,9 @@ impl From<LseDrive> for crate::pac::rcc::vals::Lsedrv {
52 } 52 }
53} 53}
54 54
55#[cfg(not(any(rtc_v2l0, rtc_v2l1, stm32c0)))] 55#[cfg(not(any(rtc_v2_l0, rtc_v2_l1, stm32c0)))]
56type Bdcr = crate::pac::rcc::regs::Bdcr; 56type Bdcr = crate::pac::rcc::regs::Bdcr;
57#[cfg(any(rtc_v2l0, rtc_v2l1))] 57#[cfg(any(rtc_v2_l0, rtc_v2_l1))]
58type Bdcr = crate::pac::rcc::regs::Csr; 58type Bdcr = crate::pac::rcc::regs::Csr;
59#[cfg(any(stm32c0))] 59#[cfg(any(stm32c0))]
60type Bdcr = crate::pac::rcc::regs::Csr1; 60type Bdcr = crate::pac::rcc::regs::Csr1;
@@ -76,9 +76,9 @@ fn unlock() {
76} 76}
77 77
78fn bdcr() -> Reg<Bdcr, RW> { 78fn bdcr() -> Reg<Bdcr, RW> {
79 #[cfg(any(rtc_v2l0, rtc_v2l1))] 79 #[cfg(any(rtc_v2_l0, rtc_v2_l1))]
80 return crate::pac::RCC.csr(); 80 return crate::pac::RCC.csr();
81 #[cfg(not(any(rtc_v2l0, rtc_v2l1, stm32c0)))] 81 #[cfg(not(any(rtc_v2_l0, rtc_v2_l1, stm32c0)))]
82 return crate::pac::RCC.bdcr(); 82 return crate::pac::RCC.bdcr();
83 #[cfg(any(stm32c0))] 83 #[cfg(any(stm32c0))]
84 return crate::pac::RCC.csr1(); 84 return crate::pac::RCC.csr1();
@@ -273,7 +273,7 @@ impl LsConfig {
273 273
274 if self.rtc != RtcClockSource::DISABLE { 274 if self.rtc != RtcClockSource::DISABLE {
275 bdcr().modify(|w| { 275 bdcr().modify(|w| {
276 #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] 276 #[cfg(any(rtc_v2_h7, rtc_v2_l4, rtc_v2_wb, rtc_v3_base, rtc_v3_u5))]
277 assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet."); 277 assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
278 278
279 #[cfg(not(rcc_wba))] 279 #[cfg(not(rcc_wba))]
diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs
index c2295bab6..99f22273d 100644
--- a/embassy-stm32/src/rcc/c0.rs
+++ b/embassy-stm32/src/rcc/c0.rs
@@ -49,6 +49,10 @@ pub struct Config {
49 /// System Clock Configuration 49 /// System Clock Configuration
50 pub sys: Sysclk, 50 pub sys: Sysclk,
51 51
52 /// HSI48 Configuration
53 #[cfg(crs)]
54 pub hsi48: Option<super::Hsi48Config>,
55
52 pub ahb_pre: AHBPrescaler, 56 pub ahb_pre: AHBPrescaler,
53 pub apb1_pre: APBPrescaler, 57 pub apb1_pre: APBPrescaler,
54 58
@@ -68,6 +72,8 @@ impl Config {
68 }), 72 }),
69 hse: None, 73 hse: None,
70 sys: Sysclk::HSISYS, 74 sys: Sysclk::HSISYS,
75 #[cfg(crs)]
76 hsi48: Some(crate::rcc::Hsi48Config::new()),
71 ahb_pre: AHBPrescaler::DIV1, 77 ahb_pre: AHBPrescaler::DIV1,
72 apb1_pre: APBPrescaler::DIV1, 78 apb1_pre: APBPrescaler::DIV1,
73 ls: crate::rcc::LsConfig::new(), 79 ls: crate::rcc::LsConfig::new(),
@@ -127,6 +133,10 @@ pub(crate) unsafe fn init(config: Config) {
127 } 133 }
128 }; 134 };
129 135
136 // Configure HSI48 if required
137 #[cfg(crs)]
138 let hsi48 = config.hsi48.map(super::init_hsi48);
139
130 let rtc = config.ls.init(); 140 let rtc = config.ls.init();
131 141
132 let sys = match config.sys { 142 let sys = match config.sys {
@@ -185,13 +195,13 @@ pub(crate) unsafe fn init(config: Config) {
185 hsi: hsi, 195 hsi: hsi,
186 hsiker: hsiker, 196 hsiker: hsiker,
187 hse: hse, 197 hse: hse,
198 #[cfg(crs)]
199 hsi48: hsi48,
188 rtc: rtc, 200 rtc: rtc,
189 201
190 // TODO 202 // TODO
191 lsi: None, 203 lsi: None,
192 lse: None, 204 lse: None,
193 #[cfg(crs)]
194 hsi48: None,
195 ); 205 );
196 206
197 RCC.ccipr() 207 RCC.ccipr()
diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs
index 59ccc8cb5..fa4b45a20 100644
--- a/embassy-stm32/src/rcc/mco.rs
+++ b/embassy-stm32/src/rcc/mco.rs
@@ -91,12 +91,29 @@ pub struct Mco<'d, T: McoInstance> {
91 91
92impl<'d, T: McoInstance> Mco<'d, T> { 92impl<'d, T: McoInstance> Mco<'d, T> {
93 /// Create a new MCO instance. 93 /// Create a new MCO instance.
94 pub fn new(_peri: Peri<'d, T>, pin: Peri<'d, impl McoPin<T>>, source: T::Source, prescaler: McoPrescaler) -> Self { 94 pub fn new(_peri: Peri<'d, T>, pin: Peri<'d, impl McoPin<T>>, source: T::Source, config: McoConfig) -> Self {
95 critical_section::with(|_| unsafe { 95 critical_section::with(|_| unsafe {
96 T::_apply_clock_settings(source, prescaler); 96 T::_apply_clock_settings(source, config.prescaler);
97 set_as_af!(pin, AfType::output(OutputType::PushPull, Speed::VeryHigh)); 97 set_as_af!(pin, AfType::output(OutputType::PushPull, config.speed));
98 }); 98 });
99 99
100 Self { phantom: PhantomData } 100 Self { phantom: PhantomData }
101 } 101 }
102} 102}
103
104#[non_exhaustive]
105pub struct McoConfig {
106 /// Master Clock Out prescaler
107 pub prescaler: McoPrescaler,
108 /// IO Drive Strength
109 pub speed: Speed,
110}
111
112impl Default for McoConfig {
113 fn default() -> Self {
114 Self {
115 prescaler: McoPrescaler::DIV1,
116 speed: Speed::VeryHigh,
117 }
118 }
119}
diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs
index 78ccd3e6c..a81ac6746 100644
--- a/embassy-stm32/src/rtc/low_power.rs
+++ b/embassy-stm32/src/rtc/low_power.rs
@@ -1,4 +1,8 @@
1#[cfg(feature = "time")]
2use embassy_time::{Duration, TICK_HZ};
3
1use super::{bcd2_to_byte, DateTimeError, Rtc, RtcError}; 4use super::{bcd2_to_byte, DateTimeError, Rtc, RtcError};
5use crate::interrupt::typelevel::Interrupt;
2use crate::peripherals::RTC; 6use crate::peripherals::RTC;
3use crate::rtc::SealedInstance; 7use crate::rtc::SealedInstance;
4 8
@@ -11,7 +15,7 @@ pub(super) struct RtcInstant {
11} 15}
12 16
13impl RtcInstant { 17impl RtcInstant {
14 #[cfg(not(rtc_v2f2))] 18 #[cfg(not(rtc_v2_f2))]
15 const fn from(second: u8, subsecond: u16) -> Result<Self, DateTimeError> { 19 const fn from(second: u8, subsecond: u16) -> Result<Self, DateTimeError> {
16 if second > 59 { 20 if second > 59 {
17 Err(DateTimeError::InvalidSecond) 21 Err(DateTimeError::InvalidSecond)
@@ -38,8 +42,6 @@ impl core::ops::Sub for RtcInstant {
38 type Output = embassy_time::Duration; 42 type Output = embassy_time::Duration;
39 43
40 fn sub(self, rhs: Self) -> Self::Output { 44 fn sub(self, rhs: Self) -> Self::Output {
41 use embassy_time::{Duration, TICK_HZ};
42
43 let second = if self.second < rhs.second { 45 let second = if self.second < rhs.second {
44 self.second + 60 46 self.second + 60
45 } else { 47 } else {
@@ -129,11 +131,6 @@ impl Rtc {
129 requested_duration: embassy_time::Duration, 131 requested_duration: embassy_time::Duration,
130 cs: critical_section::CriticalSection, 132 cs: critical_section::CriticalSection,
131 ) { 133 ) {
132 use embassy_time::{Duration, TICK_HZ};
133
134 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
135 use crate::pac::rtc::vals::Calrf;
136
137 // Panic if the rcc mod knows we're not using low-power rtc 134 // Panic if the rcc mod knows we're not using low-power rtc
138 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] 135 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
139 unsafe { crate::rcc::get_freqs() }.rtc.to_hertz().unwrap(); 136 unsafe { crate::rcc::get_freqs() }.rtc.to_hertz().unwrap();
@@ -150,17 +147,15 @@ impl Rtc {
150 self.write(false, |regs| { 147 self.write(false, |regs| {
151 regs.cr().modify(|w| w.set_wute(false)); 148 regs.cr().modify(|w| w.set_wute(false));
152 149
153 #[cfg(any( 150 #[cfg(rtc_v2)]
154 rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb
155 ))]
156 { 151 {
157 regs.isr().modify(|w| w.set_wutf(false)); 152 regs.isr().modify(|w| w.set_wutf(false));
158 while !regs.isr().read().wutwf() {} 153 while !regs.isr().read().wutwf() {}
159 } 154 }
160 155
161 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] 156 #[cfg(rtc_v3)]
162 { 157 {
163 regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR)); 158 regs.scr().write(|w| w.set_cwutf(crate::pac::rtc::vals::Calrf::CLEAR));
164 while !regs.icsr().read().wutwf() {} 159 while !regs.icsr().read().wutwf() {}
165 } 160 }
166 161
@@ -185,10 +180,6 @@ impl Rtc {
185 /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm` 180 /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm`
186 /// was called, otherwise none 181 /// was called, otherwise none
187 pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> { 182 pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> {
188 use crate::interrupt::typelevel::Interrupt;
189 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
190 use crate::pac::rtc::vals::Calrf;
191
192 let instant = self.instant().unwrap(); 183 let instant = self.instant().unwrap();
193 if RTC::regs().cr().read().wute() { 184 if RTC::regs().cr().read().wute() {
194 trace!("rtc: stop wakeup alarm at {}", instant); 185 trace!("rtc: stop wakeup alarm at {}", instant);
@@ -197,13 +188,10 @@ impl Rtc {
197 regs.cr().modify(|w| w.set_wutie(false)); 188 regs.cr().modify(|w| w.set_wutie(false));
198 regs.cr().modify(|w| w.set_wute(false)); 189 regs.cr().modify(|w| w.set_wute(false));
199 190
200 #[cfg(any( 191 #[cfg(rtc_v2)]
201 rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb
202 ))]
203 regs.isr().modify(|w| w.set_wutf(false)); 192 regs.isr().modify(|w| w.set_wutf(false));
204 193 #[cfg(rtc_v3)]
205 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))] 194 regs.scr().write(|w| w.set_cwutf(crate::pac::rtc::vals::Calrf::CLEAR));
206 regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR));
207 195
208 // Check RM for EXTI and/or NVIC section, "Event event input mapping" or "EXTI interrupt/event mapping" or something similar, 196 // Check RM for EXTI and/or NVIC section, "Event event input mapping" or "EXTI interrupt/event mapping" or something similar,
209 // there is a table for every "Event input" / "EXTI Line". 197 // there is a table for every "Event input" / "EXTI Line".
@@ -222,8 +210,6 @@ impl Rtc {
222 } 210 }
223 211
224 pub(crate) fn enable_wakeup_line(&self) { 212 pub(crate) fn enable_wakeup_line(&self) {
225 use crate::interrupt::typelevel::Interrupt;
226
227 <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend(); 213 <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend();
228 unsafe { <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::enable() }; 214 unsafe { <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::enable() };
229 215
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs
index 449f3008a..92dec0960 100644
--- a/embassy-stm32/src/rtc/mod.rs
+++ b/embassy-stm32/src/rtc/mod.rs
@@ -18,14 +18,9 @@ use crate::pac::rtc::regs::{Dr, Tr};
18use crate::time::Hertz; 18use crate::time::Hertz;
19 19
20/// refer to AN4759 to compare features of RTC2 and RTC3 20/// refer to AN4759 to compare features of RTC2 and RTC3
21#[cfg_attr(any(rtc_v1), path = "v1.rs")] 21#[cfg_attr(rtc_v1, path = "v1.rs")]
22#[cfg_attr( 22#[cfg_attr(rtc_v2, path = "v2.rs")]
23 any( 23#[cfg_attr(rtc_v3, path = "v3.rs")]
24 rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb
25 ),
26 path = "v2.rs"
27)]
28#[cfg_attr(any(rtc_v3, rtc_v3u5, rtc_v3l5, rtc_v3h7rs, rtc_v3c0), path = "v3.rs")]
29mod _version; 24mod _version;
30#[allow(unused_imports)] 25#[allow(unused_imports)]
31pub use _version::*; 26pub use _version::*;
@@ -72,12 +67,12 @@ impl RtcTimeProvider {
72 67
73 // Calculate second fraction and multiply to microseconds 68 // Calculate second fraction and multiply to microseconds
74 // Formula from RM0410 69 // Formula from RM0410
75 #[cfg(not(rtc_v2f2))] 70 #[cfg(not(rtc_v2_f2))]
76 let us = { 71 let us = {
77 let prediv = RTC::regs().prer().read().prediv_s() as f32; 72 let prediv = RTC::regs().prer().read().prediv_s() as f32;
78 (((prediv - _ss as f32) / (prediv + 1.0)) * 1e6).min(999_999.0) as u32 73 (((prediv - _ss as f32) / (prediv + 1.0)) * 1e6).min(999_999.0) as u32
79 }; 74 };
80 #[cfg(rtc_v2f2)] 75 #[cfg(rtc_v2_f2)]
81 let us = 0; 76 let us = 0;
82 77
83 DateTime::from(year, month, day, weekday, hour, minute, second, us).map_err(RtcError::InvalidDateTime) 78 DateTime::from(year, month, day, weekday, hour, minute, second, us).map_err(RtcError::InvalidDateTime)
@@ -87,9 +82,9 @@ impl RtcTimeProvider {
87 fn read<R>(&self, mut f: impl FnMut(Dr, Tr, u16) -> Result<R, RtcError>) -> Result<R, RtcError> { 82 fn read<R>(&self, mut f: impl FnMut(Dr, Tr, u16) -> Result<R, RtcError>) -> Result<R, RtcError> {
88 let r = RTC::regs(); 83 let r = RTC::regs();
89 84
90 #[cfg(not(rtc_v2f2))] 85 #[cfg(not(rtc_v2_f2))]
91 let read_ss = || r.ssr().read().ss(); 86 let read_ss = || r.ssr().read().ss();
92 #[cfg(rtc_v2f2)] 87 #[cfg(rtc_v2_f2)]
93 let read_ss = || 0; 88 let read_ss = || 0;
94 89
95 let mut ss = read_ss(); 90 let mut ss = read_ss();
@@ -168,7 +163,7 @@ impl Rtc {
168 this.configure(async_psc, sync_psc); 163 this.configure(async_psc, sync_psc);
169 164
170 // Wait for the clock to update after initialization 165 // Wait for the clock to update after initialization
171 #[cfg(not(rtc_v2f2))] 166 #[cfg(not(rtc_v2_f2))]
172 { 167 {
173 let now = this.time_provider().read(|_, _, ss| Ok(ss)).unwrap(); 168 let now = this.time_provider().read(|_, _, ss| Ok(ss)).unwrap();
174 while now == this.time_provider().read(|_, _, ss| Ok(ss)).unwrap() {} 169 while now == this.time_provider().read(|_, _, ss| Ok(ss)).unwrap() {}
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs
index 28380a3c0..23f6ccb0c 100644
--- a/embassy-stm32/src/rtc/v2.rs
+++ b/embassy-stm32/src/rtc/v2.rs
@@ -11,11 +11,11 @@ impl super::Rtc {
11 pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) { 11 pub(super) fn configure(&mut self, async_psc: u8, sync_psc: u16) {
12 self.write(true, |rtc| { 12 self.write(true, |rtc| {
13 rtc.cr().modify(|w| { 13 rtc.cr().modify(|w| {
14 #[cfg(not(rtc_v2f2))] 14 #[cfg(not(rtc_v2_f2))]
15 w.set_bypshad(true); 15 w.set_bypshad(true);
16 #[cfg(rtc_v2f2)] 16 #[cfg(rtc_v2_f2)]
17 w.set_fmt(false); 17 w.set_fmt(false);
18 #[cfg(not(rtc_v2f2))] 18 #[cfg(not(rtc_v2_f2))]
19 w.set_fmt(stm32_metapac::rtc::vals::Fmt::TWENTY_FOUR_HOUR); 19 w.set_fmt(stm32_metapac::rtc::vals::Fmt::TWENTY_FOUR_HOUR);
20 w.set_osel(Osel::DISABLED); 20 w.set_osel(Osel::DISABLED);
21 w.set_pol(Pol::HIGH); 21 w.set_pol(Pol::HIGH);
@@ -36,7 +36,7 @@ impl super::Rtc {
36 /// 36 ///
37 /// To perform a calibration when `async_prescaler` is less then 3, `sync_prescaler` 37 /// To perform a calibration when `async_prescaler` is less then 3, `sync_prescaler`
38 /// has to be reduced accordingly (see RM0351 Rev 9, sec 38.3.12). 38 /// has to be reduced accordingly (see RM0351 Rev 9, sec 38.3.12).
39 #[cfg(not(rtc_v2f2))] 39 #[cfg(not(rtc_v2_f2))]
40 pub fn calibrate(&mut self, mut clock_drift: f32, period: super::RtcCalibrationCyclePeriod) { 40 pub fn calibrate(&mut self, mut clock_drift: f32, period: super::RtcCalibrationCyclePeriod) {
41 const RTC_CALR_MIN_PPM: f32 = -487.1; 41 const RTC_CALR_MIN_PPM: f32 = -487.1;
42 const RTC_CALR_MAX_PPM: f32 = 488.5; 42 const RTC_CALR_MAX_PPM: f32 = 488.5;
diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs
index 82b5968b0..bb152731c 100644
--- a/embassy-stm32/src/timer/qei.rs
+++ b/embassy-stm32/src/timer/qei.rs
@@ -1,8 +1,6 @@
1//! Quadrature decoder using a timer. 1//! Quadrature decoder using a timer.
2 2
3use core::marker::PhantomData; 3use stm32_metapac::timer::vals::{self, Sms};
4
5use stm32_metapac::timer::vals;
6 4
7use super::low_level::Timer; 5use super::low_level::Timer;
8pub use super::{Ch1, Ch2}; 6pub use super::{Ch1, Ch2};
@@ -11,35 +9,59 @@ use crate::gpio::{AfType, AnyPin, Pull};
11use crate::timer::TimerChannel; 9use crate::timer::TimerChannel;
12use crate::Peri; 10use crate::Peri;
13 11
14/// Counting direction 12/// Qei driver config.
15pub enum Direction { 13#[cfg_attr(feature = "defmt", derive(defmt::Format))]
16 /// Counting up. 14#[derive(Clone, Copy)]
17 Upcounting, 15pub struct Config {
18 /// Counting down. 16 /// Configures the internal pull up/down resistor for Qei's channel 1 pin.
19 Downcounting, 17 pub ch1_pull: Pull,
18 /// Configures the internal pull up/down resistor for Qei's channel 2 pin.
19 pub ch2_pull: Pull,
20 /// Specifies the encoder mode to use for the Qei peripheral.
21 pub mode: QeiMode,
20} 22}
21 23
22/// Wrapper for using a pin with QEI. 24impl Default for Config {
23pub struct QeiPin<'d, T, Channel, #[cfg(afio)] A> { 25 /// Arbitrary defaults to preserve backwards compatibility
24 #[allow(unused)] 26 fn default() -> Self {
25 pin: Peri<'d, AnyPin>, 27 Self {
26 phantom: PhantomData<if_afio!((T, Channel, A))>, 28 ch1_pull: Pull::None,
29 ch2_pull: Pull::None,
30 mode: QeiMode::Mode3,
31 }
32 }
27} 33}
28 34
29impl<'d, T: GeneralInstance4Channel, C: QeiChannel, #[cfg(afio)] A> if_afio!(QeiPin<'d, T, C, A>) { 35/// See STMicro AN4013 for §2.3 for more information
30 /// Create a new QEI pin instance. 36#[cfg_attr(feature = "defmt", derive(defmt::Format))]
31 pub fn new(pin: Peri<'d, if_afio!(impl TimerPin<T, C, A>)>) -> Self { 37#[derive(Clone, Copy)]
32 critical_section::with(|_| { 38pub enum QeiMode {
33 pin.set_low(); 39 /// Direct alias for [`Sms::ENCODER_MODE_1`]
34 set_as_af!(pin, AfType::input(Pull::None)); 40 Mode1,
35 }); 41 /// Direct alias for [`Sms::ENCODER_MODE_2`]
36 QeiPin { 42 Mode2,
37 pin: pin.into(), 43 /// Direct alias for [`Sms::ENCODER_MODE_3`]
38 phantom: PhantomData, 44 Mode3,
45}
46
47impl From<QeiMode> for Sms {
48 fn from(mode: QeiMode) -> Self {
49 match mode {
50 QeiMode::Mode1 => Sms::ENCODER_MODE_1,
51 QeiMode::Mode2 => Sms::ENCODER_MODE_2,
52 QeiMode::Mode3 => Sms::ENCODER_MODE_3,
39 } 53 }
40 } 54 }
41} 55}
42 56
57/// Counting direction
58pub enum Direction {
59 /// Counting up.
60 Upcounting,
61 /// Counting down.
62 Downcounting,
63}
64
43trait SealedQeiChannel: TimerChannel {} 65trait SealedQeiChannel: TimerChannel {}
44 66
45/// Marker trait for a timer channel eligible for use with QEI. 67/// Marker trait for a timer channel eligible for use with QEI.
@@ -55,20 +77,28 @@ impl SealedQeiChannel for Ch2 {}
55/// Quadrature decoder driver. 77/// Quadrature decoder driver.
56pub struct Qei<'d, T: GeneralInstance4Channel> { 78pub struct Qei<'d, T: GeneralInstance4Channel> {
57 inner: Timer<'d, T>, 79 inner: Timer<'d, T>,
80 _ch1: Peri<'d, AnyPin>,
81 _ch2: Peri<'d, AnyPin>,
58} 82}
59 83
60impl<'d, T: GeneralInstance4Channel> Qei<'d, T> { 84impl<'d, T: GeneralInstance4Channel> Qei<'d, T> {
61 /// Create a new quadrature decoder driver. 85 /// Create a new quadrature decoder driver, with a given [`Config`].
62 #[allow(unused)] 86 #[allow(unused)]
63 pub fn new<#[cfg(afio)] A>( 87 pub fn new<CH1: QeiChannel, CH2: QeiChannel, #[cfg(afio)] A>(
64 tim: Peri<'d, T>, 88 tim: Peri<'d, T>,
65 ch1: if_afio!(QeiPin<'d, T, Ch1, A>), 89 ch1: Peri<'d, if_afio!(impl TimerPin<T, CH1, A>)>,
66 ch2: if_afio!(QeiPin<'d, T, Ch2, A>), 90 ch2: Peri<'d, if_afio!(impl TimerPin<T, CH2, A>)>,
91 config: Config,
67 ) -> Self { 92 ) -> Self {
68 Self::new_inner(tim) 93 // Configure the pins to be used for the QEI peripheral.
69 } 94 critical_section::with(|_| {
95 ch1.set_low();
96 set_as_af!(ch1, AfType::input(config.ch1_pull));
97
98 ch2.set_low();
99 set_as_af!(ch2, AfType::input(config.ch2_pull));
100 });
70 101
71 fn new_inner(tim: Peri<'d, T>) -> Self {
72 let inner = Timer::new(tim); 102 let inner = Timer::new(tim);
73 let r = inner.regs_gp16(); 103 let r = inner.regs_gp16();
74 104
@@ -88,13 +118,17 @@ impl<'d, T: GeneralInstance4Channel> Qei<'d, T> {
88 }); 118 });
89 119
90 r.smcr().modify(|w| { 120 r.smcr().modify(|w| {
91 w.set_sms(vals::Sms::ENCODER_MODE_3); 121 w.set_sms(config.mode.into());
92 }); 122 });
93 123
94 r.arr().modify(|w| w.set_arr(u16::MAX)); 124 r.arr().modify(|w| w.set_arr(u16::MAX));
95 r.cr1().modify(|w| w.set_cen(true)); 125 r.cr1().modify(|w| w.set_cen(true));
96 126
97 Self { inner } 127 Self {
128 inner,
129 _ch1: ch1.into(),
130 _ch2: ch2.into(),
131 }
98 } 132 }
99 133
100 /// Get direction. 134 /// Get direction.
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index c734eed49..10dc02334 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -1,7 +1,7 @@
1use core::future::poll_fn; 1use core::future::poll_fn;
2use core::marker::PhantomData; 2use core::marker::PhantomData;
3use core::slice; 3use core::slice;
4use core::sync::atomic::{AtomicBool, AtomicU8, Ordering}; 4use core::sync::atomic::{AtomicBool, AtomicU8, AtomicUsize, Ordering};
5use core::task::Poll; 5use core::task::Poll;
6 6
7use embassy_embedded_hal::SetConfig; 7use embassy_embedded_hal::SetConfig;
@@ -68,8 +68,15 @@ unsafe fn on_interrupt(r: Regs, state: &'static State) {
68 // FIXME: Should we disable any further RX interrupts when the buffer becomes full. 68 // FIXME: Should we disable any further RX interrupts when the buffer becomes full.
69 } 69 }
70 70
71 if !state.rx_buf.is_empty() { 71 let eager = state.eager_reads.load(Ordering::Relaxed);
72 state.rx_waker.wake(); 72 if eager > 0 {
73 if state.rx_buf.available() >= eager {
74 state.rx_waker.wake();
75 }
76 } else {
77 if state.rx_buf.is_half_full() {
78 state.rx_waker.wake();
79 }
73 } 80 }
74 } 81 }
75 82
@@ -132,6 +139,7 @@ pub(super) struct State {
132 tx_done: AtomicBool, 139 tx_done: AtomicBool,
133 tx_rx_refcount: AtomicU8, 140 tx_rx_refcount: AtomicU8,
134 half_duplex_readback: AtomicBool, 141 half_duplex_readback: AtomicBool,
142 eager_reads: AtomicUsize,
135} 143}
136 144
137impl State { 145impl State {
@@ -144,6 +152,7 @@ impl State {
144 tx_done: AtomicBool::new(true), 152 tx_done: AtomicBool::new(true),
145 tx_rx_refcount: AtomicU8::new(0), 153 tx_rx_refcount: AtomicU8::new(0),
146 half_duplex_readback: AtomicBool::new(false), 154 half_duplex_readback: AtomicBool::new(false),
155 eager_reads: AtomicUsize::new(0),
147 } 156 }
148 } 157 }
149} 158}
@@ -419,6 +428,9 @@ impl<'d> BufferedUart<'d> {
419 let state = T::buffered_state(); 428 let state = T::buffered_state();
420 let kernel_clock = T::frequency(); 429 let kernel_clock = T::frequency();
421 430
431 state
432 .eager_reads
433 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
422 state.half_duplex_readback.store( 434 state.half_duplex_readback.store(
423 config.duplex == Duplex::Half(HalfDuplexReadback::Readback), 435 config.duplex == Duplex::Half(HalfDuplexReadback::Readback),
424 Ordering::Relaxed, 436 Ordering::Relaxed,
@@ -456,6 +468,9 @@ impl<'d> BufferedUart<'d> {
456 let info = self.rx.info; 468 let info = self.rx.info;
457 let state = self.rx.state; 469 let state = self.rx.state;
458 state.tx_rx_refcount.store(2, Ordering::Relaxed); 470 state.tx_rx_refcount.store(2, Ordering::Relaxed);
471 state
472 .eager_reads
473 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
459 474
460 info.rcc.enable_and_reset(); 475 info.rcc.enable_and_reset();
461 476
@@ -527,6 +542,11 @@ impl<'d> BufferedUart<'d> {
527 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 542 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
528 reconfigure(self.rx.info, self.rx.kernel_clock, config)?; 543 reconfigure(self.rx.info, self.rx.kernel_clock, config)?;
529 544
545 self.rx
546 .state
547 .eager_reads
548 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
549
530 self.rx.info.regs.cr1().modify(|w| { 550 self.rx.info.regs.cr1().modify(|w| {
531 w.set_rxneie(true); 551 w.set_rxneie(true);
532 w.set_idleie(true); 552 w.set_idleie(true);
@@ -553,24 +573,30 @@ impl<'d> BufferedUartRx<'d> {
553 poll_fn(move |cx| { 573 poll_fn(move |cx| {
554 let state = self.state; 574 let state = self.state;
555 let mut rx_reader = unsafe { state.rx_buf.reader() }; 575 let mut rx_reader = unsafe { state.rx_buf.reader() };
556 let data = rx_reader.pop_slice(); 576 let mut buf_len = 0;
577 let mut data = rx_reader.pop_slice();
557 578
558 if !data.is_empty() { 579 while !data.is_empty() && buf_len < buf.len() {
559 let len = data.len().min(buf.len()); 580 let data_len = data.len().min(buf.len() - buf_len);
560 buf[..len].copy_from_slice(&data[..len]); 581 buf[buf_len..buf_len + data_len].copy_from_slice(&data[..data_len]);
582 buf_len += data_len;
561 583
562 let do_pend = state.rx_buf.is_full(); 584 let do_pend = state.rx_buf.is_full();
563 rx_reader.pop_done(len); 585 rx_reader.pop_done(data_len);
564 586
565 if do_pend { 587 if do_pend {
566 self.info.interrupt.pend(); 588 self.info.interrupt.pend();
567 } 589 }
568 590
569 return Poll::Ready(Ok(len)); 591 data = rx_reader.pop_slice();
570 } 592 }
571 593
572 state.rx_waker.register(cx.waker()); 594 if buf_len != 0 {
573 Poll::Pending 595 Poll::Ready(Ok(buf_len))
596 } else {
597 state.rx_waker.register(cx.waker());
598 Poll::Pending
599 }
574 }) 600 })
575 .await 601 .await
576 } 602 }
@@ -579,21 +605,24 @@ impl<'d> BufferedUartRx<'d> {
579 loop { 605 loop {
580 let state = self.state; 606 let state = self.state;
581 let mut rx_reader = unsafe { state.rx_buf.reader() }; 607 let mut rx_reader = unsafe { state.rx_buf.reader() };
582 let data = rx_reader.pop_slice(); 608 let mut buf_len = 0;
609 let mut data = rx_reader.pop_slice();
583 610
584 if !data.is_empty() { 611 while !data.is_empty() && buf_len < buf.len() {
585 let len = data.len().min(buf.len()); 612 let data_len = data.len().min(buf.len() - buf_len);
586 buf[..len].copy_from_slice(&data[..len]); 613 buf[buf_len..buf_len + data_len].copy_from_slice(&data[..data_len]);
614 buf_len += data_len;
587 615
588 let do_pend = state.rx_buf.is_full(); 616 let do_pend = state.rx_buf.is_full();
589 rx_reader.pop_done(len); 617 rx_reader.pop_done(data_len);
590 618
591 if do_pend { 619 if do_pend {
592 self.info.interrupt.pend(); 620 self.info.interrupt.pend();
593 } 621 }
594 622
595 return Ok(len); 623 data = rx_reader.pop_slice();
596 } 624 }
625 return Ok(buf_len);
597 } 626 }
598 } 627 }
599 628
@@ -633,6 +662,10 @@ impl<'d> BufferedUartRx<'d> {
633 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 662 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
634 reconfigure(self.info, self.kernel_clock, config)?; 663 reconfigure(self.info, self.kernel_clock, config)?;
635 664
665 self.state
666 .eager_reads
667 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
668
636 self.info.regs.cr1().modify(|w| { 669 self.info.regs.cr1().modify(|w| {
637 w.set_rxneie(true); 670 w.set_rxneie(true);
638 w.set_idleie(true); 671 w.set_idleie(true);
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index ff211e0c9..0d2d86aca 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -4,7 +4,7 @@
4 4
5use core::future::poll_fn; 5use core::future::poll_fn;
6use core::marker::PhantomData; 6use core::marker::PhantomData;
7use core::sync::atomic::{compiler_fence, AtomicU8, Ordering}; 7use core::sync::atomic::{compiler_fence, AtomicU8, AtomicUsize, Ordering};
8use core::task::Poll; 8use core::task::Poll;
9 9
10use embassy_embedded_hal::SetConfig; 10use embassy_embedded_hal::SetConfig;
@@ -185,6 +185,12 @@ pub enum ConfigError {
185 RxOrTxNotEnabled, 185 RxOrTxNotEnabled,
186 /// Data bits and parity combination not supported 186 /// Data bits and parity combination not supported
187 DataParityNotSupported, 187 DataParityNotSupported,
188 /// DE assertion time too high
189 #[cfg(not(any(usart_v1, usart_v2)))]
190 DeAssertionTimeTooHigh,
191 /// DE deassertion time too high
192 #[cfg(not(any(usart_v1, usart_v2)))]
193 DeDeassertionTimeTooHigh,
188} 194}
189 195
190#[non_exhaustive] 196#[non_exhaustive]
@@ -206,6 +212,21 @@ pub struct Config {
206 /// If false: the error is ignored and cleared 212 /// If false: the error is ignored and cleared
207 pub detect_previous_overrun: bool, 213 pub detect_previous_overrun: bool,
208 214
215 /// If `None` (the default) then read-like calls on `BufferedUartRx` and `RingBufferedUartRx`
216 /// typically only wake/return after line idle or after the buffer is at least half full
217 /// (for `BufferedUartRx`) or the DMA buffer is written at the half or full positions
218 /// (for `RingBufferedUartRx`), though it may also wake/return earlier in some circumstances.
219 ///
220 /// If `Some(n)` then such reads are also woken/return as soon as at least `n` words are
221 /// available in the buffer, in addition to waking/returning when the conditions described
222 /// above are met. `Some(0)` is treated as `None`. Setting this for `RingBufferedUartRx`
223 /// will trigger an interrupt for every received word to check the buffer level, which may
224 /// impact performance at high data rates.
225 ///
226 /// Has no effect on plain `Uart` or `UartRx` reads, which are specified to either
227 /// return a single word, a full buffer, or after line idle.
228 pub eager_reads: Option<usize>,
229
209 /// Set this to true if the line is considered noise free. 230 /// Set this to true if the line is considered noise free.
210 /// This will increase the receiver’s tolerance to clock deviations, 231 /// This will increase the receiver’s tolerance to clock deviations,
211 /// but will effectively disable noise detection. 232 /// but will effectively disable noise detection.
@@ -239,6 +260,14 @@ pub struct Config {
239 /// Set the pin configuration for the DE pin. 260 /// Set the pin configuration for the DE pin.
240 pub de_config: OutputConfig, 261 pub de_config: OutputConfig,
241 262
263 /// Set DE assertion time before the first start bit, 0-31 16ths of a bit period.
264 #[cfg(not(any(usart_v1, usart_v2)))]
265 pub de_assertion_time: u8,
266
267 /// Set DE deassertion time after the last stop bit, 0-31 16ths of a bit period.
268 #[cfg(not(any(usart_v1, usart_v2)))]
269 pub de_deassertion_time: u8,
270
242 // private: set by new_half_duplex, not by the user. 271 // private: set by new_half_duplex, not by the user.
243 duplex: Duplex, 272 duplex: Duplex,
244} 273}
@@ -270,6 +299,7 @@ impl Default for Config {
270 parity: Parity::ParityNone, 299 parity: Parity::ParityNone,
271 // historical behavior 300 // historical behavior
272 detect_previous_overrun: false, 301 detect_previous_overrun: false,
302 eager_reads: None,
273 #[cfg(not(usart_v1))] 303 #[cfg(not(usart_v1))]
274 assume_noise_free: false, 304 assume_noise_free: false,
275 #[cfg(any(usart_v3, usart_v4))] 305 #[cfg(any(usart_v3, usart_v4))]
@@ -283,6 +313,10 @@ impl Default for Config {
283 tx_config: OutputConfig::PushPull, 313 tx_config: OutputConfig::PushPull,
284 rts_config: OutputConfig::PushPull, 314 rts_config: OutputConfig::PushPull,
285 de_config: OutputConfig::PushPull, 315 de_config: OutputConfig::PushPull,
316 #[cfg(not(any(usart_v1, usart_v2)))]
317 de_assertion_time: 0,
318 #[cfg(not(any(usart_v1, usart_v2)))]
319 de_deassertion_time: 0,
286 duplex: Duplex::Full, 320 duplex: Duplex::Full,
287 } 321 }
288 } 322 }
@@ -966,6 +1000,9 @@ impl<'d, M: Mode> UartRx<'d, M> {
966 let info = self.info; 1000 let info = self.info;
967 let state = self.state; 1001 let state = self.state;
968 state.tx_rx_refcount.store(1, Ordering::Relaxed); 1002 state.tx_rx_refcount.store(1, Ordering::Relaxed);
1003 state
1004 .eager_reads
1005 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
969 1006
970 info.rcc.enable_and_reset(); 1007 info.rcc.enable_and_reset();
971 1008
@@ -982,6 +1019,9 @@ impl<'d, M: Mode> UartRx<'d, M> {
982 1019
983 /// Reconfigure the driver 1020 /// Reconfigure the driver
984 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 1021 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
1022 self.state
1023 .eager_reads
1024 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
985 reconfigure(self.info, self.kernel_clock, config) 1025 reconfigure(self.info, self.kernel_clock, config)
986 } 1026 }
987 1027
@@ -1462,6 +1502,9 @@ impl<'d, M: Mode> Uart<'d, M> {
1462 let info = self.rx.info; 1502 let info = self.rx.info;
1463 let state = self.rx.state; 1503 let state = self.rx.state;
1464 state.tx_rx_refcount.store(2, Ordering::Relaxed); 1504 state.tx_rx_refcount.store(2, Ordering::Relaxed);
1505 state
1506 .eager_reads
1507 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
1465 1508
1466 info.rcc.enable_and_reset(); 1509 info.rcc.enable_and_reset();
1467 1510
@@ -1690,6 +1733,16 @@ fn configure(
1690 return Err(ConfigError::RxOrTxNotEnabled); 1733 return Err(ConfigError::RxOrTxNotEnabled);
1691 } 1734 }
1692 1735
1736 #[cfg(not(any(usart_v1, usart_v2)))]
1737 let dem = r.cr3().read().dem();
1738
1739 #[cfg(not(any(usart_v1, usart_v2)))]
1740 if config.de_assertion_time > 31 {
1741 return Err(ConfigError::DeAssertionTimeTooHigh);
1742 } else if config.de_deassertion_time > 31 {
1743 return Err(ConfigError::DeDeassertionTimeTooHigh);
1744 }
1745
1693 // UART must be disabled during configuration. 1746 // UART must be disabled during configuration.
1694 r.cr1().modify(|w| { 1747 r.cr1().modify(|w| {
1695 w.set_ue(false); 1748 w.set_ue(false);
@@ -1738,6 +1791,20 @@ fn configure(
1738 w.set_re(enable_rx); 1791 w.set_re(enable_rx);
1739 } 1792 }
1740 1793
1794 #[cfg(not(any(usart_v1, usart_v2)))]
1795 if dem {
1796 w.set_deat(if over8 {
1797 config.de_assertion_time / 2
1798 } else {
1799 config.de_assertion_time
1800 });
1801 w.set_dedt(if over8 {
1802 config.de_assertion_time / 2
1803 } else {
1804 config.de_assertion_time
1805 });
1806 }
1807
1741 // configure word size and parity, since the parity bit is inserted into the MSB position, 1808 // configure word size and parity, since the parity bit is inserted into the MSB position,
1742 // it increases the effective word size 1809 // it increases the effective word size
1743 match (config.parity, config.data_bits) { 1810 match (config.parity, config.data_bits) {
@@ -2022,6 +2089,7 @@ struct State {
2022 rx_waker: AtomicWaker, 2089 rx_waker: AtomicWaker,
2023 tx_waker: AtomicWaker, 2090 tx_waker: AtomicWaker,
2024 tx_rx_refcount: AtomicU8, 2091 tx_rx_refcount: AtomicU8,
2092 eager_reads: AtomicUsize,
2025} 2093}
2026 2094
2027impl State { 2095impl State {
@@ -2030,6 +2098,7 @@ impl State {
2030 rx_waker: AtomicWaker::new(), 2098 rx_waker: AtomicWaker::new(),
2031 tx_waker: AtomicWaker::new(), 2099 tx_waker: AtomicWaker::new(),
2032 tx_rx_refcount: AtomicU8::new(0), 2100 tx_rx_refcount: AtomicU8::new(0),
2101 eager_reads: AtomicUsize::new(0),
2033 } 2102 }
2034 } 2103 }
2035} 2104}
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index 5f4e87834..27071fb31 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -26,9 +26,9 @@ use crate::Peri;
26/// contain enough bytes to fill the buffer passed by the caller of 26/// contain enough bytes to fill the buffer passed by the caller of
27/// the function, or is empty. 27/// the function, or is empty.
28/// 28///
29/// Waiting for bytes operates in one of two modes, depending on 29/// Waiting for bytes operates in one of three modes, depending on
30/// the behavior of the sender and the size of the buffer passed 30/// the behavior of the sender, the size of the buffer passed
31/// to the function: 31/// to the function, and the configuration:
32/// 32///
33/// - If the sender sends intermittently, the 'idle line' 33/// - If the sender sends intermittently, the 'idle line'
34/// condition will be detected when the sender stops, and any 34/// condition will be detected when the sender stops, and any
@@ -47,7 +47,11 @@ use crate::Peri;
47/// interrupt when those specific buffer addresses have been 47/// interrupt when those specific buffer addresses have been
48/// written. 48/// written.
49/// 49///
50/// In both cases this will result in variable latency due to the 50/// - If `eager_reads` is enabled in `config`, the UART interrupt
51/// is enabled on all data reception and the call will only wait
52/// for at least one byte to be available before returning.
53///
54/// In the first two cases this will result in variable latency due to the
51/// buffering effect. For example, if the baudrate is 2400 bps, and 55/// buffering effect. For example, if the baudrate is 2400 bps, and
52/// the configuration is 8 data bits, no parity bit, and one stop bit, 56/// the configuration is 8 data bits, no parity bit, and one stop bit,
53/// then a byte will be received every ~4.16ms. If the ring buffer is 57/// then a byte will be received every ~4.16ms. If the ring buffer is
@@ -68,15 +72,10 @@ use crate::Peri;
68/// sending, but would be falsely triggered in the worst-case 72/// sending, but would be falsely triggered in the worst-case
69/// buffer delay scenario. 73/// buffer delay scenario.
70/// 74///
71/// Note: This latency is caused by the limited capabilities of the 75/// Note: Enabling `eager_reads` with `RingBufferedUartRx` will enable
72/// STM32 DMA controller; since it cannot generate an interrupt when 76/// an UART RXNE interrupt, which will cause an interrupt to occur on
73/// it stores a byte into an empty ring buffer, or in any other 77/// every received data byte. The data is still copied using DMA, but
74/// configurable conditions, it is not possible to take notice of the 78/// there is nevertheless additional processing overhead for each byte.
75/// contents of the ring buffer more quickly without introducing
76/// polling. As a result the latency can be reduced by calling the
77/// read functions repeatedly with smaller buffers to receive the
78/// available bytes, as each call to a read function will explicitly
79/// check the ring buffer for available bytes.
80pub struct RingBufferedUartRx<'d> { 79pub struct RingBufferedUartRx<'d> {
81 info: &'static Info, 80 info: &'static Info,
82 state: &'static State, 81 state: &'static State,
@@ -133,6 +132,9 @@ impl<'d> UartRx<'d, Async> {
133impl<'d> RingBufferedUartRx<'d> { 132impl<'d> RingBufferedUartRx<'d> {
134 /// Reconfigure the driver 133 /// Reconfigure the driver
135 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { 134 pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
135 self.state
136 .eager_reads
137 .store(config.eager_reads.unwrap_or(0), Ordering::Relaxed);
136 reconfigure(self.info, self.kernel_clock, config) 138 reconfigure(self.info, self.kernel_clock, config)
137 } 139 }
138 140
@@ -148,8 +150,8 @@ impl<'d> RingBufferedUartRx<'d> {
148 let r = self.info.regs; 150 let r = self.info.regs;
149 // clear all interrupts and DMA Rx Request 151 // clear all interrupts and DMA Rx Request
150 r.cr1().modify(|w| { 152 r.cr1().modify(|w| {
151 // disable RXNE interrupt 153 // use RXNE only when returning reads early
152 w.set_rxneie(false); 154 w.set_rxneie(self.state.eager_reads.load(Ordering::Relaxed) > 0);
153 // enable parity interrupt if not ParityNone 155 // enable parity interrupt if not ParityNone
154 w.set_peie(w.pce()); 156 w.set_peie(w.pce());
155 // enable idle line interrupt 157 // enable idle line interrupt
@@ -248,39 +250,67 @@ impl<'d> RingBufferedUartRx<'d> {
248 async fn wait_for_data_or_idle(&mut self) -> Result<(), Error> { 250 async fn wait_for_data_or_idle(&mut self) -> Result<(), Error> {
249 compiler_fence(Ordering::SeqCst); 251 compiler_fence(Ordering::SeqCst);
250 252
251 // Future which completes when idle line is detected 253 loop {
252 let s = self.state; 254 // Future which completes when idle line is detected
253 let uart = poll_fn(|cx| { 255 let s = self.state;
254 s.rx_waker.register(cx.waker()); 256 let mut uart_init = false;
255 257 let uart = poll_fn(|cx| {
256 compiler_fence(Ordering::SeqCst); 258 s.rx_waker.register(cx.waker());
257 259
258 if check_idle_and_errors(self.info.regs)? { 260 compiler_fence(Ordering::SeqCst);
259 // Idle line is detected 261
260 Poll::Ready(Ok(())) 262 // We may have been woken by IDLE or, if eager_reads is set, by RXNE.
261 } else { 263 // However, DMA will clear RXNE, so we can't check directly, and because
262 Poll::Pending 264 // the other future borrows `ring_buf`, we can't check `len()` here either.
263 } 265 // Instead, return from this future and we'll check the length afterwards.
264 }); 266 let eager = s.eager_reads.load(Ordering::Relaxed) > 0;
267
268 let idle = check_idle_and_errors(self.info.regs)?;
269 if idle || (eager && uart_init) {
270 // Idle line is detected, or eager reads is set and some data is available.
271 Poll::Ready(Ok(idle))
272 } else {
273 uart_init = true;
274 Poll::Pending
275 }
276 });
265 277
266 let mut dma_init = false; 278 let mut dma_init = false;
267 // Future which completes when the DMA controller indicates it 279 // Future which completes when the DMA controller indicates it
268 // has written to the ring buffer's middle byte, or last byte 280 // has written to the ring buffer's middle byte, or last byte
269 let dma = poll_fn(|cx| { 281 let dma = poll_fn(|cx| {
270 self.ring_buf.set_waker(cx.waker()); 282 self.ring_buf.set_waker(cx.waker());
271 283
272 let status = match dma_init { 284 let status = match dma_init {
273 false => Poll::Pending, 285 false => Poll::Pending,
274 true => Poll::Ready(()), 286 true => Poll::Ready(()),
275 }; 287 };
276 288
277 dma_init = true; 289 dma_init = true;
278 status 290 status
279 }); 291 });
280 292
281 match select(uart, dma).await { 293 match select(uart, dma).await {
282 Either::Left((result, _)) => result, 294 // UART woke with line idle
283 Either::Right(((), _)) => Ok(()), 295 Either::Left((Ok(true), _)) => {
296 return Ok(());
297 }
298 // UART woke without idle or error: word received
299 Either::Left((Ok(false), _)) => {
300 let eager = self.state.eager_reads.load(Ordering::Relaxed);
301 if eager > 0 && self.ring_buf.len().unwrap_or(0) >= eager {
302 return Ok(());
303 } else {
304 continue;
305 }
306 }
307 // UART woke with error
308 Either::Left((Err(e), _)) => {
309 return Err(e);
310 }
311 // DMA woke
312 Either::Right(((), _)) => return Ok(()),
313 }
284 } 314 }
285 } 315 }
286 316
diff --git a/embassy-sync/Cargo.toml b/embassy-sync/Cargo.toml
index 6494da727..64d76baba 100644
--- a/embassy-sync/Cargo.toml
+++ b/embassy-sync/Cargo.toml
@@ -27,6 +27,8 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-sync/
27target = "thumbv7em-none-eabi" 27target = "thumbv7em-none-eabi"
28 28
29[features] 29[features]
30defmt = ["dep:defmt"]
31log = ["dep:log"]
30std = [] 32std = []
31turbowakers = [] 33turbowakers = []
32 34
diff --git a/embassy-sync/src/blocking_mutex/mod.rs b/embassy-sync/src/blocking_mutex/mod.rs
index 11809c763..62bfc26fb 100644
--- a/embassy-sync/src/blocking_mutex/mod.rs
+++ b/embassy-sync/src/blocking_mutex/mod.rs
@@ -135,9 +135,9 @@ impl<T> Mutex<raw::NoopRawMutex, T> {
135// There's still a ThreadModeRawMutex for use with the generic Mutex (handy with Channel, for example), 135// There's still a ThreadModeRawMutex for use with the generic Mutex (handy with Channel, for example),
136// but that will require T: Send even though it shouldn't be needed. 136// but that will require T: Send even though it shouldn't be needed.
137 137
138#[cfg(any(cortex_m, feature = "std"))] 138#[cfg(any(cortex_m, doc, feature = "std"))]
139pub use thread_mode_mutex::*; 139pub use thread_mode_mutex::*;
140#[cfg(any(cortex_m, feature = "std"))] 140#[cfg(any(cortex_m, doc, feature = "std"))]
141mod thread_mode_mutex { 141mod thread_mode_mutex {
142 use super::*; 142 use super::*;
143 143
diff --git a/embassy-sync/src/blocking_mutex/raw.rs b/embassy-sync/src/blocking_mutex/raw.rs
index 50f965e00..fbb9ece15 100644
--- a/embassy-sync/src/blocking_mutex/raw.rs
+++ b/embassy-sync/src/blocking_mutex/raw.rs
@@ -89,7 +89,7 @@ unsafe impl RawMutex for NoopRawMutex {
89 89
90// ================ 90// ================
91 91
92#[cfg(any(cortex_m, feature = "std"))] 92#[cfg(any(cortex_m, doc, feature = "std"))]
93mod thread_mode { 93mod thread_mode {
94 use super::*; 94 use super::*;
95 95
@@ -147,5 +147,5 @@ mod thread_mode {
147 return unsafe { (0xE000ED04 as *const u32).read_volatile() } & 0x1FF == 0; 147 return unsafe { (0xE000ED04 as *const u32).read_volatile() } & 0x1FF == 0;
148 } 148 }
149} 149}
150#[cfg(any(cortex_m, feature = "std"))] 150#[cfg(any(cortex_m, doc, feature = "std"))]
151pub use thread_mode::*; 151pub use thread_mode::*;
diff --git a/embassy-sync/src/rwlock.rs b/embassy-sync/src/rwlock.rs
index 0d784a7dc..e43388c4d 100644
--- a/embassy-sync/src/rwlock.rs
+++ b/embassy-sync/src/rwlock.rs
@@ -37,8 +37,6 @@ struct State {
37/// Use [`NoopRawMutex`](crate::blocking_mutex::raw::NoopRawMutex) when data is only shared between tasks running on the same executor. 37/// Use [`NoopRawMutex`](crate::blocking_mutex::raw::NoopRawMutex) when data is only shared between tasks running on the same executor.
38/// 38///
39/// Use [`ThreadModeRawMutex`](crate::blocking_mutex::raw::ThreadModeRawMutex) when data is shared between tasks running on the same executor but you want a singleton. 39/// Use [`ThreadModeRawMutex`](crate::blocking_mutex::raw::ThreadModeRawMutex) when data is shared between tasks running on the same executor but you want a singleton.
40///
41
42pub struct RwLock<M, T> 40pub struct RwLock<M, T>
43where 41where
44 M: RawMutex, 42 M: RawMutex,
diff --git a/embassy-sync/tests/ui/sync_impl/lazy_lock_function.stderr b/embassy-sync/tests/ui/sync_impl/lazy_lock_function.stderr
index daf79ad28..417fb8e31 100644
--- a/embassy-sync/tests/ui/sync_impl/lazy_lock_function.stderr
+++ b/embassy-sync/tests/ui/sync_impl/lazy_lock_function.stderr
@@ -1,10 +1,10 @@
1error[E0277]: `*const u8` cannot be shared between threads safely 1error[E0277]: `*const u8` cannot be shared between threads safely
2 --> tests/ui/sync_impl/lazy_lock_function.rs:8:16 2 --> tests/ui/sync_impl/lazy_lock_function.rs:8:16
3 | 3 |
46 | let closure_capturing_non_sync_variable = || unsafe { core::ptr::read(x_ptr) }; 4 6 | let closure_capturing_non_sync_variable = || unsafe { core::ptr::read(x_ptr) };
5 | -- within this `{closure@$DIR/tests/ui/sync_impl/lazy_lock_function.rs:6:47: 6:49}` 5 | -- within this `{closure@$DIR/tests/ui/sync_impl/lazy_lock_function.rs:6:47: 6:49}`
67 | 6 7 |
78 | check_sync(LazyLock::new(closure_capturing_non_sync_variable)); 7 8 | check_sync(LazyLock::new(closure_capturing_non_sync_variable));
8 | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const u8` cannot be shared between threads safely 8 | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const u8` cannot be shared between threads safely
9 | | 9 | |
10 | required by a bound introduced by this call 10 | required by a bound introduced by this call
@@ -14,7 +14,7 @@ error[E0277]: `*const u8` cannot be shared between threads safely
14note: required because it's used within this closure 14note: required because it's used within this closure
15 --> tests/ui/sync_impl/lazy_lock_function.rs:6:47 15 --> tests/ui/sync_impl/lazy_lock_function.rs:6:47
16 | 16 |
176 | let closure_capturing_non_sync_variable = || unsafe { core::ptr::read(x_ptr) }; 17 6 | let closure_capturing_non_sync_variable = || unsafe { core::ptr::read(x_ptr) };
18 | ^^ 18 | ^^
19 = note: required for `embassy_sync::lazy_lock::LazyLock<u8, {closure@$DIR/tests/ui/sync_impl/lazy_lock_function.rs:6:47: 6:49}>` to implement `Sync` 19 = note: required for `embassy_sync::lazy_lock::LazyLock<u8, {closure@$DIR/tests/ui/sync_impl/lazy_lock_function.rs:6:47: 6:49}>` to implement `Sync`
20note: required by a bound in `check_sync` 20note: required by a bound in `check_sync`
diff --git a/embassy-time-driver/src/lib.rs b/embassy-time-driver/src/lib.rs
index 32cb68296..44d9a156a 100644
--- a/embassy-time-driver/src/lib.rs
+++ b/embassy-time-driver/src/lib.rs
@@ -6,7 +6,7 @@
6//! 6//!
7//! - Define a struct `MyDriver` 7//! - Define a struct `MyDriver`
8//! - Implement [`Driver`] for it 8//! - Implement [`Driver`] for it
9//! - Register it as the global driver with [`time_driver_impl`](crate::time_driver_impl). 9//! - Register it as the global driver with [`time_driver_impl`].
10//! 10//!
11//! If your driver has a single set tick rate, enable the corresponding [`tick-hz-*`](crate#tick-rate) feature, 11//! If your driver has a single set tick rate, enable the corresponding [`tick-hz-*`](crate#tick-rate) feature,
12//! which will prevent users from needing to configure it themselves (or selecting an incorrect configuration). 12//! which will prevent users from needing to configure it themselves (or selecting an incorrect configuration).
diff --git a/embassy-time/CHANGELOG.md b/embassy-time/CHANGELOG.md
index 572571215..4a50da8ef 100644
--- a/embassy-time/CHANGELOG.md
+++ b/embassy-time/CHANGELOG.md
@@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8<!-- next-header --> 8<!-- next-header -->
9## Unreleased - ReleaseDate 9## Unreleased - ReleaseDate
10 10
11- Add as_nanos and from_nanos where missing
12
11## 0.5.0 - 2025-08-26 13## 0.5.0 - 2025-08-26
12 14
13- Allow inlining on time driver boundary 15- Allow inlining on time driver boundary
diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml
index 2d7c3c1fa..bad6ecf97 100644
--- a/embassy-time/Cargo.toml
+++ b/embassy-time/Cargo.toml
@@ -31,6 +31,11 @@ target = "x86_64-unknown-linux-gnu"
31features = ["defmt", "std"] 31features = ["defmt", "std"]
32 32
33[features] 33[features]
34## Enable defmt
35defmt = ["dep:defmt"]
36## Enable log
37log = ["dep:log"]
38
34## Display the time since startup next to defmt log messages. 39## Display the time since startup next to defmt log messages.
35## At most 1 `defmt-timestamp-uptime-*` feature can be used. 40## At most 1 `defmt-timestamp-uptime-*` feature can be used.
36## `defmt-timestamp-uptime` is provided for backwards compatibility (provides the same format as `uptime-us`). 41## `defmt-timestamp-uptime` is provided for backwards compatibility (provides the same format as `uptime-us`).
diff --git a/embassy-time/src/duration.rs b/embassy-time/src/duration.rs
index 5b140eeff..b3ea0468d 100644
--- a/embassy-time/src/duration.rs
+++ b/embassy-time/src/duration.rs
@@ -37,6 +37,11 @@ impl Duration {
37 self.ticks * (1_000_000 / GCD_1M) / (TICK_HZ / GCD_1M) 37 self.ticks * (1_000_000 / GCD_1M) / (TICK_HZ / GCD_1M)
38 } 38 }
39 39
40 /// Convert the `Duration` to nanoseconds, rounding down.
41 pub const fn as_nanos(&self) -> u64 {
42 self.ticks * (1_000_000_000 / GCD_1G) / (TICK_HZ / GCD_1G)
43 }
44
40 /// Creates a duration from the specified number of clock ticks 45 /// Creates a duration from the specified number of clock ticks
41 pub const fn from_ticks(ticks: u64) -> Duration { 46 pub const fn from_ticks(ticks: u64) -> Duration {
42 Duration { ticks } 47 Duration { ticks }
diff --git a/embassy-time/src/instant.rs b/embassy-time/src/instant.rs
index 6571bea62..de5ebebf8 100644
--- a/embassy-time/src/instant.rs
+++ b/embassy-time/src/instant.rs
@@ -1,7 +1,7 @@
1use core::fmt; 1use core::fmt;
2use core::ops::{Add, AddAssign, Sub, SubAssign}; 2use core::ops::{Add, AddAssign, Sub, SubAssign};
3 3
4use super::{Duration, GCD_1K, GCD_1M, TICK_HZ}; 4use super::{Duration, GCD_1G, GCD_1K, GCD_1M, TICK_HZ};
5 5
6#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] 6#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
7#[cfg_attr(feature = "defmt", derive(defmt::Format))] 7#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -29,6 +29,13 @@ impl Instant {
29 Self { ticks } 29 Self { ticks }
30 } 30 }
31 31
32 /// Create an Instant from a nanosecond count since system boot.
33 pub const fn from_nanos(nanos: u64) -> Self {
34 Self {
35 ticks: nanos * (TICK_HZ / GCD_1G) / (1_000_000_000 / GCD_1G),
36 }
37 }
38
32 /// Create an Instant from a microsecond count since system boot. 39 /// Create an Instant from a microsecond count since system boot.
33 pub const fn from_micros(micros: u64) -> Self { 40 pub const fn from_micros(micros: u64) -> Self {
34 Self { 41 Self {
@@ -50,6 +57,17 @@ impl Instant {
50 } 57 }
51 } 58 }
52 59
60 /// Try to create an Instant from a nanosecond count since system boot.
61 /// Fails if the number of nanoseconds is too large.
62 pub const fn try_from_nanos(nanos: u64) -> Option<Self> {
63 let Some(value) = nanos.checked_mul(TICK_HZ / GCD_1G) else {
64 return None;
65 };
66 Some(Self {
67 ticks: value / (1_000_000_000 / GCD_1G),
68 })
69 }
70
53 /// Try to create an Instant from a microsecond count since system boot. 71 /// Try to create an Instant from a microsecond count since system boot.
54 /// Fails if the number of microseconds is too large. 72 /// Fails if the number of microseconds is too large.
55 pub const fn try_from_micros(micros: u64) -> Option<Self> { 73 pub const fn try_from_micros(micros: u64) -> Option<Self> {
@@ -101,6 +119,11 @@ impl Instant {
101 self.ticks * (1_000_000 / GCD_1M) / (TICK_HZ / GCD_1M) 119 self.ticks * (1_000_000 / GCD_1M) / (TICK_HZ / GCD_1M)
102 } 120 }
103 121
122 /// Nanoseconds since system boot.
123 pub const fn as_nanos(&self) -> u64 {
124 self.ticks * (1_000_000_000 / GCD_1G) / (TICK_HZ / GCD_1G)
125 }
126
104 /// Duration between this Instant and another Instant 127 /// Duration between this Instant and another Instant
105 /// Panics on over/underflow. 128 /// Panics on over/underflow.
106 pub fn duration_since(&self, earlier: Instant) -> Duration { 129 pub fn duration_since(&self, earlier: Instant) -> Duration {
diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml
index 4a65c6895..e70ab970e 100644
--- a/embassy-usb-dfu/Cargo.toml
+++ b/embassy-usb-dfu/Cargo.toml
@@ -49,6 +49,9 @@ esp32c3-hal = { version = "0.13.0", optional = true, default-features = false }
49dfu = [] 49dfu = []
50application = [] 50application = []
51defmt = ["dep:defmt", "embassy-boot/defmt", "embassy-usb/defmt"] 51defmt = ["dep:defmt", "embassy-boot/defmt", "embassy-usb/defmt"]
52log = ["dep:log"]
53cortex-m = ["dep:cortex-m"]
54esp32c3-hal = ["dep:esp32c3-hal"]
52ed25519-dalek = ["embassy-boot/ed25519-dalek", "_verify"] 55ed25519-dalek = ["embassy-boot/ed25519-dalek", "_verify"]
53ed25519-salty = ["embassy-boot/ed25519-salty", "_verify"] 56ed25519-salty = ["embassy-boot/ed25519-salty", "_verify"]
54 57
diff --git a/embassy-usb-driver/Cargo.toml b/embassy-usb-driver/Cargo.toml
index de69bf694..6e4c31273 100644
--- a/embassy-usb-driver/Cargo.toml
+++ b/embassy-usb-driver/Cargo.toml
@@ -21,3 +21,6 @@ features = ["defmt"]
21[dependencies] 21[dependencies]
22embedded-io-async = "0.6.1" 22embedded-io-async = "0.6.1"
23defmt = { version = "1", optional = true } 23defmt = { version = "1", optional = true }
24
25[features]
26defmt = ["dep:defmt"]
diff --git a/embassy-usb-driver/src/lib.rs b/embassy-usb-driver/src/lib.rs
index 3ad96c61d..59845a268 100644
--- a/embassy-usb-driver/src/lib.rs
+++ b/embassy-usb-driver/src/lib.rs
@@ -205,7 +205,7 @@ pub trait Bus {
205 /// 205 ///
206 /// # Errors 206 /// # Errors
207 /// 207 ///
208 /// * [`Unsupported`](crate::Unsupported) - This UsbBus implementation doesn't support 208 /// * [`Unsupported`] - This UsbBus implementation doesn't support
209 /// simulating a disconnect or it has not been enabled at creation time. 209 /// simulating a disconnect or it has not been enabled at creation time.
210 fn force_reset(&mut self) -> Result<(), Unsupported> { 210 fn force_reset(&mut self) -> Result<(), Unsupported> {
211 Err(Unsupported) 211 Err(Unsupported)
@@ -215,7 +215,7 @@ pub trait Bus {
215 /// 215 ///
216 /// # Errors 216 /// # Errors
217 /// 217 ///
218 /// * [`Unsupported`](crate::Unsupported) - This UsbBus implementation doesn't support 218 /// * [`Unsupported`] - This UsbBus implementation doesn't support
219 /// remote wakeup or it has not been enabled at creation time. 219 /// remote wakeup or it has not been enabled at creation time.
220 async fn remote_wakeup(&mut self) -> Result<(), Unsupported>; 220 async fn remote_wakeup(&mut self) -> Result<(), Unsupported>;
221} 221}
diff --git a/embassy-usb-synopsys-otg/Cargo.toml b/embassy-usb-synopsys-otg/Cargo.toml
index ec518ac93..61b14a215 100644
--- a/embassy-usb-synopsys-otg/Cargo.toml
+++ b/embassy-usb-synopsys-otg/Cargo.toml
@@ -23,3 +23,7 @@ embassy-usb-driver = { version = "0.2.0", path = "../embassy-usb-driver" }
23 23
24defmt = { version = "1.0.1", optional = true } 24defmt = { version = "1.0.1", optional = true }
25log = { version = "0.4.14", optional = true } 25log = { version = "0.4.14", optional = true }
26
27[features]
28defmt = ["dep:defmt", "embassy-usb-driver/defmt"]
29log = ["dep:log"]
diff --git a/embassy-usb/Cargo.toml b/embassy-usb/Cargo.toml
index e309eec93..bff48c4a6 100644
--- a/embassy-usb/Cargo.toml
+++ b/embassy-usb/Cargo.toml
@@ -31,6 +31,7 @@ features = ["defmt", "usbd-hid"]
31 31
32[features] 32[features]
33defmt = ["dep:defmt", "embassy-usb-driver/defmt"] 33defmt = ["dep:defmt", "embassy-usb-driver/defmt"]
34log = ["dep:log"]
34usbd-hid = ["dep:usbd-hid", "dep:ssmarshal"] 35usbd-hid = ["dep:usbd-hid", "dep:ssmarshal"]
35default = ["usbd-hid"] 36default = ["usbd-hid"]
36 37
diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml
index b0cc63a6c..f5f89ecb5 100644
--- a/examples/boot/application/nrf/Cargo.toml
+++ b/examples/boot/application/nrf/Cargo.toml
@@ -9,9 +9,9 @@ publish = false
9embassy-sync = { version = "0.7.2", path = "../../../../embassy-sync" } 9embassy-sync = { version = "0.7.2", path = "../../../../embassy-sync" }
10embassy-executor = { version = "0.9.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } 10embassy-executor = { version = "0.9.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] }
11embassy-time = { version = "0.5.0", path = "../../../../embassy-time", features = [] } 11embassy-time = { version = "0.5.0", path = "../../../../embassy-time", features = [] }
12embassy-nrf = { version = "0.7.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } 12embassy-nrf = { version = "0.8.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] }
13embassy-boot = { version = "0.6.1", path = "../../../../embassy-boot", features = [] } 13embassy-boot = { version = "0.6.1", path = "../../../../embassy-boot", features = [] }
14embassy-boot-nrf = { version = "0.8.0", path = "../../../../embassy-boot-nrf", features = [] } 14embassy-boot-nrf = { version = "0.9.0", path = "../../../../embassy-boot-nrf", features = [] }
15embassy-embedded-hal = { version = "0.5.0", path = "../../../../embassy-embedded-hal" } 15embassy-embedded-hal = { version = "0.5.0", path = "../../../../embassy-embedded-hal" }
16 16
17defmt = { version = "1.0.1", optional = true } 17defmt = { version = "1.0.1", optional = true }
diff --git a/examples/lpc55s69/src/bin/usart_async.rs b/examples/lpc55s69/src/bin/usart_async.rs
new file mode 100644
index 000000000..b06abd477
--- /dev/null
+++ b/examples/lpc55s69/src/bin/usart_async.rs
@@ -0,0 +1,70 @@
1#![no_std]
2#![no_main]
3
4use core::str::from_utf8_mut;
5
6use defmt::*;
7use embassy_executor::Spawner;
8use embassy_nxp::bind_interrupts;
9use embassy_nxp::gpio::{Level, Output};
10use embassy_nxp::peripherals::USART2;
11use embassy_nxp::usart::{Config, InterruptHandler, Usart};
12use embassy_time::Timer;
13use {defmt_rtt as _, panic_halt as _};
14
15bind_interrupts!(struct Irqs {
16 FLEXCOMM2 => InterruptHandler<USART2>;
17 }
18);
19
20#[embassy_executor::task]
21async fn blinky_task(mut led: Output<'static>) {
22 loop {
23 info!("[TASK] led off!");
24 led.set_high();
25 Timer::after_millis(500).await;
26
27 info!("[TASK] led on!");
28 led.set_low();
29 Timer::after_millis(500).await;
30 }
31}
32
33#[embassy_executor::main]
34async fn main(spawner: Spawner) {
35 let p = embassy_nxp::init(Default::default());
36 let mut usart = Usart::new(
37 p.USART2,
38 p.PIO0_27,
39 p.PIO1_24,
40 Irqs,
41 p.DMA_CH11,
42 p.DMA_CH10,
43 Config::default(),
44 );
45 let led = Output::new(p.PIO1_6, Level::Low);
46 spawner.spawn(blinky_task(led).unwrap());
47 info!("[MAIN] Entering main loop");
48 loop {
49 let tx_buf = b"Hello, Ferris!";
50 let mut rx_buf = [0u8; 14];
51 info!("[MAIN] Write a message");
52 usart.write(tx_buf).await.unwrap();
53 Timer::after_millis(500).await;
54
55 info!("[MAIN] Read a message");
56 match usart.read(&mut rx_buf).await {
57 Ok(_) => match from_utf8_mut(&mut rx_buf) {
58 Ok(str) => {
59 info!("[MAIN] The message is: {}", str);
60 }
61 Err(_) => {
62 error!("[MAIN] Error in converting to UTF8");
63 }
64 },
65 Err(e) => warn!("[MAIN] Error: {}", e),
66 }
67
68 Timer::after_millis(500).await;
69 }
70}
diff --git a/examples/mimxrt1011/Cargo.toml b/examples/mimxrt1011/Cargo.toml
index 488f3167b..3038f5d4d 100644
--- a/examples/mimxrt1011/Cargo.toml
+++ b/examples/mimxrt1011/Cargo.toml
@@ -2,7 +2,7 @@
2name = "embassy-imxrt1011-examples" 2name = "embassy-imxrt1011-examples"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "2021"
5license = "MIT or Apache-2.0" 5license = "MIT OR Apache-2.0"
6publish = false 6publish = false
7 7
8[dependencies] 8[dependencies]
diff --git a/examples/mimxrt1062-evk/Cargo.toml b/examples/mimxrt1062-evk/Cargo.toml
index ec6c5c872..82a24490d 100644
--- a/examples/mimxrt1062-evk/Cargo.toml
+++ b/examples/mimxrt1062-evk/Cargo.toml
@@ -2,7 +2,7 @@
2name = "embassy-imxrt1062-evk-examples" 2name = "embassy-imxrt1062-evk-examples"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "2021"
5license = "MIT or Apache-2.0" 5license = "MIT OR Apache-2.0"
6publish = false 6publish = false
7 7
8[dependencies] 8[dependencies]
diff --git a/examples/mimxrt6/Cargo.toml b/examples/mimxrt6/Cargo.toml
index 28de9d273..3f7ad8485 100644
--- a/examples/mimxrt6/Cargo.toml
+++ b/examples/mimxrt6/Cargo.toml
@@ -2,7 +2,7 @@
2name = "embassy-imxrt-examples" 2name = "embassy-imxrt-examples"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "2021"
5license = "MIT or Apache-2.0" 5license = "MIT OR Apache-2.0"
6publish = false 6publish = false
7 7
8[dependencies] 8[dependencies]
diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml
index c9eeaaac7..d2d0ae093 100644
--- a/examples/nrf-rtos-trace/Cargo.toml
+++ b/examples/nrf-rtos-trace/Cargo.toml
@@ -19,7 +19,7 @@ log = [
19embassy-sync = { version = "0.7.2", path = "../../embassy-sync" } 19embassy-sync = { version = "0.7.2", path = "../../embassy-sync" }
20embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace"] } 20embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace"] }
21embassy-time = { version = "0.5.0", path = "../../embassy-time" } 21embassy-time = { version = "0.5.0", path = "../../embassy-time" }
22embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } 22embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
23 23
24cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } 24cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
25cortex-m-rt = "0.7.0" 25cortex-m-rt = "0.7.0"
diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml
index dded6de59..082d85e5b 100644
--- a/examples/nrf51/Cargo.toml
+++ b/examples/nrf51/Cargo.toml
@@ -8,7 +8,7 @@ publish = false
8[dependencies] 8[dependencies]
9embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } 9embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
10embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 10embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
11embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } 11embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] }
12 12
13defmt = "1.0.1" 13defmt = "1.0.1"
14defmt-rtt = "1.0.0" 14defmt-rtt = "1.0.0"
diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml
index aa1a4bf73..7835320e5 100644
--- a/examples/nrf52810/Cargo.toml
+++ b/examples/nrf52810/Cargo.toml
@@ -10,7 +10,7 @@ embassy-futures = { version = "0.1.2", path = "../../embassy-futures" }
10embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } 11embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
12embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 12embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
13embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 13embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
14 14
15defmt = "1.0.1" 15defmt = "1.0.1"
16defmt-rtt = "1.0.0" 16defmt-rtt = "1.0.0"
diff --git a/examples/nrf52810/src/bin/saadc_lowpower.rs b/examples/nrf52810/src/bin/saadc_lowpower.rs
new file mode 100644
index 000000000..d7e7f09a4
--- /dev/null
+++ b/examples/nrf52810/src/bin/saadc_lowpower.rs
@@ -0,0 +1,62 @@
1//! Run SAADC on multiple pins only every 3rd time, to show anomaly 241 workaround.
2//!
3//! To correctly measure the MCU current on the NRF52DK follow the instructions
4//! <https://docs.nordicsemi.com/bundle/ug_nrf52832_dk/page/UG/dk/prepare_board.html>
5//! otherwise you will measure the whole board, including the segger j-link chip for example
6
7#![no_std]
8#![no_main]
9
10use defmt::info;
11use embassy_executor::Spawner;
12use embassy_nrf::gpio::{Level, Output, OutputDrive};
13use embassy_nrf::saadc::{Oversample, Saadc};
14use embassy_nrf::{bind_interrupts, saadc};
15use embassy_time::Timer;
16use {defmt_rtt as _, panic_probe as _};
17
18bind_interrupts!(struct Irqs {
19 SAADC => saadc::InterruptHandler;
20});
21
22#[embassy_executor::main]
23async fn main(_p: Spawner) {
24 let mut p = embassy_nrf::init(Default::default());
25
26 // For PPK2 digital channel plot to track when SAADC is on/off.
27 let mut ppk2_d0 = Output::new(p.P0_27, Level::Low, OutputDrive::Standard);
28 let mut num_loops: usize = 0;
29 loop {
30 num_loops += 1;
31 if num_loops.is_multiple_of(3) {
32 ppk2_d0.set_high();
33 let battery_pin = p.P0_02.reborrow();
34 let sensor1_pin = p.P0_03.reborrow();
35 let mut adc_config = saadc::Config::default();
36 adc_config.oversample = Oversample::OVER4X;
37 let battery = saadc::ChannelConfig::single_ended(battery_pin);
38 let sensor1 = saadc::ChannelConfig::single_ended(sensor1_pin);
39 let mut saadc = Saadc::new(p.SAADC.reborrow(), Irqs, adc_config, [battery, sensor1]);
40 // Indicated: wait for ADC calibration.
41 saadc.calibrate().await;
42 let mut buf = [0; 2];
43 info!("sampling...");
44 saadc.sample(&mut buf).await;
45 info!("data: {:x}", buf);
46
47 // Sleep to show the high power usage on the plot, even though sampling is done.
48 Timer::after_millis(100).await;
49 ppk2_d0.set_low();
50 // disable the following line to show the anomaly on the power profiler plot.
51 core::mem::drop(saadc);
52 // Sleep to show the power usage when drop did not happen.
53 Timer::after_millis(100).await;
54 // worst case drop happens here
55 } else {
56 info!("waiting");
57 }
58 // Sleep for 1 second. The executor ensures the core sleeps with a WFE when it has nothing to do.
59 // During this sleep, the nRF chip should only use ~3uA
60 Timer::after_secs(1).await;
61 }
62}
diff --git a/examples/nrf52840-edf/Cargo.toml b/examples/nrf52840-edf/Cargo.toml
index 1e8803233..67a624d6d 100644
--- a/examples/nrf52840-edf/Cargo.toml
+++ b/examples/nrf52840-edf/Cargo.toml
@@ -9,7 +9,7 @@ publish = false
9# NOTE: "scheduler-deadline" and "embassy-time-driver" features are enabled 9# NOTE: "scheduler-deadline" and "embassy-time-driver" features are enabled
10embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "scheduler-deadline", "embassy-time-driver"] } 10embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "scheduler-deadline", "embassy-time-driver"] }
11embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 11embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
12embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 12embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
13 13
14defmt = "1.0.1" 14defmt = "1.0.1"
15defmt-rtt = "1.0.0" 15defmt-rtt = "1.0.0"
diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml
index f6937c263..d860626a1 100644
--- a/examples/nrf52840-rtic/Cargo.toml
+++ b/examples/nrf52840-rtic/Cargo.toml
@@ -12,7 +12,7 @@ embassy-futures = { version = "0.1.2", path = "../../embassy-futures" }
12embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } 12embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] }
13embassy-time = { version = "0.5.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime"] } 13embassy-time = { version = "0.5.0", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime"] }
14embassy-time-queue-utils = { version = "0.3.0", path = "../../embassy-time-queue-utils", features = ["generic-queue-8"] } 14embassy-time-queue-utils = { version = "0.3.0", path = "../../embassy-time-queue-utils", features = ["generic-queue-8"] }
15embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 15embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
16 16
17defmt = "1.0.1" 17defmt = "1.0.1"
18defmt-rtt = "1.0.0" 18defmt-rtt = "1.0.0"
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml
index 452e83b7e..5b3e176c0 100644
--- a/examples/nrf52840/Cargo.toml
+++ b/examples/nrf52840/Cargo.toml
@@ -10,7 +10,7 @@ embassy-futures = { version = "0.1.2", path = "../../embassy-futures" }
10embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } 11embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
12embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 12embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
13embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time", "net-driver"] } 13embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time", "net-driver"] }
14embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet","udp", "medium-ieee802154", "proto-ipv6"] } 14embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet","udp", "medium-ieee802154", "proto-ipv6"] }
15embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] } 15embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] }
16embedded-io = { version = "0.6.0", features = ["defmt-03"] } 16embedded-io = { version = "0.6.0", features = ["defmt-03"] }
@@ -35,6 +35,7 @@ embedded-hal-async = { version = "1.0" }
35embedded-hal-bus = { version = "0.1", features = ["async"] } 35embedded-hal-bus = { version = "0.1", features = ["async"] }
36num-integer = { version = "0.1.45", default-features = false } 36num-integer = { version = "0.1.45", default-features = false }
37microfft = "0.5.0" 37microfft = "0.5.0"
38portable-atomic = "1"
38 39
39[profile.release] 40[profile.release]
40debug = 2 41debug = 2
diff --git a/examples/nrf52840/src/bin/ethernet_enc28j60.rs b/examples/nrf52840/src/bin/ethernet_enc28j60.rs
index 3bb255a72..e59afd37f 100644
--- a/examples/nrf52840/src/bin/ethernet_enc28j60.rs
+++ b/examples/nrf52840/src/bin/ethernet_enc28j60.rs
@@ -25,7 +25,7 @@ bind_interrupts!(struct Irqs {
25async fn net_task( 25async fn net_task(
26 mut runner: embassy_net::Runner< 26 mut runner: embassy_net::Runner<
27 'static, 27 'static,
28 Enc28j60<ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>, Output<'static>>, 28 Enc28j60<ExclusiveDevice<Spim<'static>, Output<'static>, Delay>, Output<'static>>,
29 >, 29 >,
30) -> ! { 30) -> ! {
31 runner.run().await 31 runner.run().await
diff --git a/examples/nrf52840/src/bin/rtc.rs b/examples/nrf52840/src/bin/rtc.rs
new file mode 100644
index 000000000..9d475df7f
--- /dev/null
+++ b/examples/nrf52840/src/bin/rtc.rs
@@ -0,0 +1,56 @@
1#![no_std]
2#![no_main]
3
4use core::cell::RefCell;
5
6use embassy_executor::Spawner;
7use embassy_nrf::gpio::{Level, Output, OutputDrive};
8use embassy_nrf::interrupt;
9use embassy_nrf::rtc::Rtc;
10use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
11use embassy_sync::blocking_mutex::Mutex;
12use portable_atomic::AtomicU64;
13use {defmt_rtt as _, panic_probe as _};
14
15// 64 bit counter which will never overflow.
16static TICK_COUNTER: AtomicU64 = AtomicU64::new(0);
17static RTC: Mutex<CriticalSectionRawMutex, RefCell<Option<Rtc<'static>>>> = Mutex::new(RefCell::new(None));
18
19#[embassy_executor::main]
20async fn main(_spawner: Spawner) {
21 defmt::println!("nRF52840 RTC example");
22 let p = embassy_nrf::init(Default::default());
23 let mut led = Output::new(p.P0_13, Level::High, OutputDrive::Standard);
24 // Counter resolution is 125 ms.
25 let mut rtc = Rtc::new(p.RTC0, (1 << 12) - 1).unwrap();
26 rtc.enable_interrupt(embassy_nrf::rtc::Interrupt::Tick, true);
27 rtc.enable_event(embassy_nrf::rtc::Interrupt::Tick);
28 rtc.enable();
29 RTC.lock(|r| {
30 let mut rtc_borrow = r.borrow_mut();
31 *rtc_borrow = Some(rtc);
32 });
33
34 let mut last_counter_val = 0;
35 loop {
36 let current = TICK_COUNTER.load(core::sync::atomic::Ordering::Relaxed);
37 if current != last_counter_val {
38 led.toggle();
39 last_counter_val = current;
40 }
41 }
42}
43
44#[interrupt]
45fn RTC0() {
46 // For 64-bit, we do not need to worry about overflowing, at least not for realistic program
47 // lifetimes.
48 TICK_COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
49 RTC.lock(|r| {
50 let mut rtc_borrow = r.borrow_mut();
51 rtc_borrow
52 .as_mut()
53 .unwrap()
54 .reset_event(embassy_nrf::rtc::Interrupt::Tick);
55 });
56}
diff --git a/examples/nrf52840/src/bin/sixlowpan.rs b/examples/nrf52840/src/bin/sixlowpan.rs
index 00a597366..12e385e01 100644
--- a/examples/nrf52840/src/bin/sixlowpan.rs
+++ b/examples/nrf52840/src/bin/sixlowpan.rs
@@ -21,7 +21,7 @@ bind_interrupts!(struct Irqs {
21}); 21});
22 22
23#[embassy_executor::task] 23#[embassy_executor::task]
24async fn ieee802154_task(runner: net::Runner<'static, peripherals::RADIO>) -> ! { 24async fn ieee802154_task(runner: net::Runner<'static>) -> ! {
25 runner.run().await 25 runner.run().await
26} 26}
27 27
diff --git a/examples/nrf52840/src/bin/uart_split.rs b/examples/nrf52840/src/bin/uart_split.rs
index 51af90727..d75143126 100644
--- a/examples/nrf52840/src/bin/uart_split.rs
+++ b/examples/nrf52840/src/bin/uart_split.rs
@@ -52,7 +52,7 @@ async fn main(spawner: Spawner) {
52} 52}
53 53
54#[embassy_executor::task] 54#[embassy_executor::task]
55async fn reader(mut rx: UarteRx<'static, UARTE0>) { 55async fn reader(mut rx: UarteRx<'static>) {
56 let mut buf = [0; 8]; 56 let mut buf = [0; 8];
57 loop { 57 loop {
58 info!("reading..."); 58 info!("reading...");
diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs
index 87aa4c6c5..a75b967b4 100644
--- a/examples/nrf52840/src/bin/usb_ethernet.rs
+++ b/examples/nrf52840/src/bin/usb_ethernet.rs
@@ -22,7 +22,7 @@ bind_interrupts!(struct Irqs {
22 RNG => rng::InterruptHandler<peripherals::RNG>; 22 RNG => rng::InterruptHandler<peripherals::RNG>;
23}); 23});
24 24
25type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>; 25type MyDriver = Driver<'static, HardwareVbusDetect>;
26 26
27const MTU: usize = 1514; 27const MTU: usize = 1514;
28 28
diff --git a/examples/nrf52840/src/bin/usb_serial.rs b/examples/nrf52840/src/bin/usb_serial.rs
index 8d05df791..e7c2d0854 100644
--- a/examples/nrf52840/src/bin/usb_serial.rs
+++ b/examples/nrf52840/src/bin/usb_serial.rs
@@ -5,7 +5,7 @@ use defmt::{info, panic};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_futures::join::join; 6use embassy_futures::join::join;
7use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect}; 7use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect};
8use embassy_nrf::usb::{Driver, Instance}; 8use embassy_nrf::usb::Driver;
9use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; 9use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 10use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
11use embassy_usb::driver::EndpointError; 11use embassy_usb::driver::EndpointError;
@@ -89,9 +89,7 @@ impl From<EndpointError> for Disconnected {
89 } 89 }
90} 90}
91 91
92async fn echo<'d, T: Instance + 'd, P: VbusDetect + 'd>( 92async fn echo<'d, V: VbusDetect + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, V>>) -> Result<(), Disconnected> {
93 class: &mut CdcAcmClass<'d, Driver<'d, T, P>>,
94) -> Result<(), Disconnected> {
95 let mut buf = [0; 64]; 93 let mut buf = [0; 64];
96 loop { 94 loop {
97 let n = class.read_packet(&mut buf).await?; 95 let n = class.read_packet(&mut buf).await?;
diff --git a/examples/nrf52840/src/bin/usb_serial_multitask.rs b/examples/nrf52840/src/bin/usb_serial_multitask.rs
index 00a91a233..b6a983854 100644
--- a/examples/nrf52840/src/bin/usb_serial_multitask.rs
+++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs
@@ -17,7 +17,7 @@ bind_interrupts!(struct Irqs {
17 CLOCK_POWER => usb::vbus_detect::InterruptHandler; 17 CLOCK_POWER => usb::vbus_detect::InterruptHandler;
18}); 18});
19 19
20type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>; 20type MyDriver = Driver<'static, HardwareVbusDetect>;
21 21
22#[embassy_executor::task] 22#[embassy_executor::task]
23async fn usb_task(mut device: UsbDevice<'static, MyDriver>) { 23async fn usb_task(mut device: UsbDevice<'static, MyDriver>) {
diff --git a/examples/nrf52840/src/bin/usb_serial_winusb.rs b/examples/nrf52840/src/bin/usb_serial_winusb.rs
index 8a20ce673..e30e08a01 100644
--- a/examples/nrf52840/src/bin/usb_serial_winusb.rs
+++ b/examples/nrf52840/src/bin/usb_serial_winusb.rs
@@ -5,7 +5,7 @@ use defmt::{info, panic};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_futures::join::join; 6use embassy_futures::join::join;
7use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect}; 7use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect};
8use embassy_nrf::usb::{Driver, Instance}; 8use embassy_nrf::usb::Driver;
9use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; 9use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
10use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 10use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
11use embassy_usb::driver::EndpointError; 11use embassy_usb::driver::EndpointError;
@@ -108,9 +108,7 @@ impl From<EndpointError> for Disconnected {
108 } 108 }
109} 109}
110 110
111async fn echo<'d, T: Instance + 'd, P: VbusDetect + 'd>( 111async fn echo<'d, V: VbusDetect + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, V>>) -> Result<(), Disconnected> {
112 class: &mut CdcAcmClass<'d, Driver<'d, T, P>>,
113) -> Result<(), Disconnected> {
114 let mut buf = [0; 64]; 112 let mut buf = [0; 64];
115 loop { 113 loop {
116 let n = class.read_packet(&mut buf).await?; 114 let n = class.read_packet(&mut buf).await?;
diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
index 2dd9abfaa..1bc35746a 100644
--- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs
+++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
@@ -27,7 +27,7 @@ bind_interrupts!(struct Irqs {
27async fn wifi_task( 27async fn wifi_task(
28 runner: hosted::Runner< 28 runner: hosted::Runner<
29 'static, 29 'static,
30 ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>, 30 ExclusiveDevice<Spim<'static>, Output<'static>, Delay>,
31 Input<'static>, 31 Input<'static>,
32 Output<'static>, 32 Output<'static>,
33 >, 33 >,
diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml
index 425015667..256fee08d 100644
--- a/examples/nrf5340/Cargo.toml
+++ b/examples/nrf5340/Cargo.toml
@@ -10,7 +10,7 @@ embassy-futures = { version = "0.1.2", path = "../../embassy-futures" }
10embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } 11embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 12embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
13embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } 13embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] }
14embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } 14embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }
15embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] } 15embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] }
16embedded-io-async = { version = "0.6.1" } 16embedded-io-async = { version = "0.6.1" }
diff --git a/examples/nrf54l15/Cargo.toml b/examples/nrf54l15/Cargo.toml
index 7f67b41f6..9c24cdab4 100644
--- a/examples/nrf54l15/Cargo.toml
+++ b/examples/nrf54l15/Cargo.toml
@@ -8,7 +8,7 @@ publish = false
8[dependencies] 8[dependencies]
9embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } 9embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
10embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 10embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
11embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 11embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
12 12
13defmt = "1.0.1" 13defmt = "1.0.1"
14defmt-rtt = "1.0.0" 14defmt-rtt = "1.0.0"
diff --git a/examples/nrf9151/ns/Cargo.toml b/examples/nrf9151/ns/Cargo.toml
index 8e420477f..89a6c7c94 100644
--- a/examples/nrf9151/ns/Cargo.toml
+++ b/examples/nrf9151/ns/Cargo.toml
@@ -8,7 +8,7 @@ publish = false
8[dependencies] 8[dependencies]
9embassy-executor = { version = "0.9.0", path = "../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } 9embassy-executor = { version = "0.9.0", path = "../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
10embassy-time = { version = "0.5.0", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 10embassy-time = { version = "0.5.0", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
11embassy-nrf = { version = "0.7.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 11embassy-nrf = { version = "0.8.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
12 12
13defmt = "1.0.1" 13defmt = "1.0.1"
14defmt-rtt = "1.0.0" 14defmt-rtt = "1.0.0"
diff --git a/examples/nrf9151/s/Cargo.toml b/examples/nrf9151/s/Cargo.toml
index e4ca85553..870311c5d 100644
--- a/examples/nrf9151/s/Cargo.toml
+++ b/examples/nrf9151/s/Cargo.toml
@@ -8,7 +8,7 @@ publish = false
8[dependencies] 8[dependencies]
9embassy-executor = { version = "0.9.0", path = "../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } 9embassy-executor = { version = "0.9.0", path = "../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
10embassy-time = { version = "0.5.0", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 10embassy-time = { version = "0.5.0", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
11embassy-nrf = { version = "0.7.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 11embassy-nrf = { version = "0.8.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
12 12
13defmt = "1.0.1" 13defmt = "1.0.1"
14defmt-rtt = "1.0.0" 14defmt-rtt = "1.0.0"
diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml
index d7b63a7ac..274e26dd6 100644
--- a/examples/nrf9160/Cargo.toml
+++ b/examples/nrf9160/Cargo.toml
@@ -8,7 +8,7 @@ publish = false
8[dependencies] 8[dependencies]
9embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } 9embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
10embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 10embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
11embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 11embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
12embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] } 12embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] }
13embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "proto-ipv4", "medium-ip"] } 13embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "proto-ipv4", "medium-ip"] }
14 14
diff --git a/examples/nrf9160/src/bin/modem_tcp_client.rs b/examples/nrf9160/src/bin/modem_tcp_client.rs
index 7d4815699..460a4cfae 100644
--- a/examples/nrf9160/src/bin/modem_tcp_client.rs
+++ b/examples/nrf9160/src/bin/modem_tcp_client.rs
@@ -32,7 +32,7 @@ bind_interrupts!(struct Irqs {
32}); 32});
33 33
34#[embassy_executor::task] 34#[embassy_executor::task]
35async fn trace_task(mut uart: BufferedUarteTx<'static, peripherals::SERIAL0>, reader: TraceReader<'static>) -> ! { 35async fn trace_task(mut uart: BufferedUarteTx<'static>, reader: TraceReader<'static>) -> ! {
36 let mut rx = [0u8; 1024]; 36 let mut rx = [0u8; 1024];
37 loop { 37 loop {
38 let n = reader.read(&mut rx[..]).await; 38 let n = reader.read(&mut rx[..]).await;
diff --git a/examples/rp235x/src/bin/multicore_stack_overflow.rs b/examples/rp235x/src/bin/multicore_stack_overflow.rs
new file mode 100644
index 000000000..dba44aa23
--- /dev/null
+++ b/examples/rp235x/src/bin/multicore_stack_overflow.rs
@@ -0,0 +1,72 @@
1//! This example tests stack overflow handling on core1 of the RP235x chip.
2
3#![no_std]
4#![no_main]
5
6use defmt::*;
7use embassy_executor::Executor;
8use embassy_rp::gpio::{Level, Output};
9use embassy_rp::multicore::{spawn_core1, Stack};
10use embassy_time::Timer;
11use static_cell::StaticCell;
12use {defmt_rtt as _, panic_probe as _};
13
14const CORE1_STACK_LENGTH: usize = 4096;
15
16static mut CORE1_STACK: Stack<CORE1_STACK_LENGTH> = Stack::new();
17static EXECUTOR0: StaticCell<Executor> = StaticCell::new();
18static EXECUTOR1: StaticCell<Executor> = StaticCell::new();
19
20#[cortex_m_rt::entry]
21fn main() -> ! {
22 let p = embassy_rp::init(Default::default());
23 let led = Output::new(p.PIN_25, Level::Low);
24
25 spawn_core1(
26 p.CORE1,
27 unsafe { &mut *core::ptr::addr_of_mut!(CORE1_STACK) },
28 move || {
29 let executor1 = EXECUTOR1.init(Executor::new());
30 executor1.run(|spawner| spawner.spawn(unwrap!(core1_task())));
31 },
32 );
33
34 let executor0 = EXECUTOR0.init(Executor::new());
35 executor0.run(|spawner| spawner.spawn(unwrap!(core0_task(led))));
36}
37
38#[embassy_executor::task]
39async fn core0_task(mut led: Output<'static>) {
40 info!("Hello from core 0");
41 loop {
42 info!("core 0 still alive");
43 led.set_high();
44 Timer::after_millis(500).await;
45 led.set_low();
46 Timer::after_millis(500).await;
47 }
48}
49
50fn blow_my_stack() {
51 // Allocating an array a little larger than our stack should ensure a stack overflow when it is used.
52 let t = [0u8; CORE1_STACK_LENGTH + 64];
53
54 info!("Array initialised without error");
55 // We need to use black_box to otherwise the compiler is too smart and will optimise all of this away.
56 // We shouldn't get to this code - the initialisation above will touch the stack guard.
57 for ref i in t {
58 let _data = core::hint::black_box(*i) + 1;
59 }
60}
61
62#[embassy_executor::task]
63async fn core1_task() {
64 info!("Hello from core 1");
65
66 blow_my_stack();
67
68 loop {
69 info!("core 1 still alive");
70 Timer::after_millis(1000).await;
71 }
72}
diff --git a/examples/stm32f4/src/bin/mco.rs b/examples/stm32f4/src/bin/mco.rs
index eb7bb6261..a2e229770 100644
--- a/examples/stm32f4/src/bin/mco.rs
+++ b/examples/stm32f4/src/bin/mco.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Speed}; 6use embassy_stm32::gpio::{Level, Output, Speed};
7use embassy_stm32::rcc::{Mco, Mco1Source, Mco2Source, McoPrescaler}; 7use embassy_stm32::rcc::{Mco, Mco1Source, Mco2Source, McoConfig, McoPrescaler};
8use embassy_time::Timer; 8use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
@@ -13,8 +13,20 @@ async fn main(_spawner: Spawner) {
13 let p = embassy_stm32::init(Default::default()); 13 let p = embassy_stm32::init(Default::default());
14 info!("Hello World!"); 14 info!("Hello World!");
15 15
16 let _mco1 = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, McoPrescaler::DIV1); 16 let config_mco1 = {
17 let _mco2 = Mco::new(p.MCO2, p.PC9, Mco2Source::PLL, McoPrescaler::DIV4); 17 let mut config = McoConfig::default();
18 config.prescaler = McoPrescaler::DIV1;
19 config
20 };
21
22 let config_mco2 = {
23 let mut config = McoConfig::default();
24 config.prescaler = McoPrescaler::DIV4;
25 config
26 };
27
28 let _mco1 = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, config_mco1);
29 let _mco2 = Mco::new(p.MCO2, p.PC9, Mco2Source::PLL, config_mco2);
18 let mut led = Output::new(p.PB7, Level::High, Speed::Low); 30 let mut led = Output::new(p.PB7, Level::High, Speed::Low);
19 31
20 loop { 32 loop {
diff --git a/examples/stm32h5/src/bin/mco.rs b/examples/stm32h5/src/bin/mco.rs
new file mode 100644
index 000000000..1137ba25c
--- /dev/null
+++ b/examples/stm32h5/src/bin/mco.rs
@@ -0,0 +1,29 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::gpio::Speed;
7use embassy_stm32::rcc::{Mco, Mco2Source, McoConfig};
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) {
12 let p = embassy_stm32::init(Default::default());
13
14 /* Default "VeryHigh" drive strength and prescaler DIV1 */
15 // let _mco = Mco::new(p.MCO2, p.PC9, Mco2Source::SYS, McoConfig::default());
16
17 /* Choose Speed::Low drive strength */
18 let config = {
19 let mut config = McoConfig::default();
20 config.speed = Speed::Low;
21 config
22 };
23
24 let _mco = Mco::new(p.MCO2, p.PC9, Mco2Source::SYS, config);
25
26 info!("Clock out with low drive strength set on Master Clock Out 2 pin as AF on PC9");
27
28 loop {}
29}
diff --git a/examples/stm32h7/src/bin/camera.rs b/examples/stm32h7/src/bin/camera.rs
index 8f2e265d6..039008d17 100644
--- a/examples/stm32h7/src/bin/camera.rs
+++ b/examples/stm32h7/src/bin/camera.rs
@@ -5,7 +5,7 @@ use embassy_executor::Spawner;
5use embassy_stm32::dcmi::{self, *}; 5use embassy_stm32::dcmi::{self, *};
6use embassy_stm32::gpio::{Level, Output, Speed}; 6use embassy_stm32::gpio::{Level, Output, Speed};
7use embassy_stm32::i2c::I2c; 7use embassy_stm32::i2c::I2c;
8use embassy_stm32::rcc::{Mco, Mco1Source, McoPrescaler}; 8use embassy_stm32::rcc::{Mco, Mco1Source, McoConfig, McoPrescaler};
9use embassy_stm32::{bind_interrupts, i2c, peripherals, Config}; 9use embassy_stm32::{bind_interrupts, i2c, peripherals, Config};
10use embassy_time::Timer; 10use embassy_time::Timer;
11use ov7725::*; 11use ov7725::*;
@@ -48,7 +48,14 @@ async fn main(_spawner: Spawner) {
48 let p = embassy_stm32::init(config); 48 let p = embassy_stm32::init(config);
49 49
50 defmt::info!("Hello World!"); 50 defmt::info!("Hello World!");
51 let mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, McoPrescaler::DIV3); 51
52 let mco_config = {
53 let mut config = McoConfig::default();
54 config.prescaler = McoPrescaler::DIV3;
55 config
56 };
57
58 let mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, mco_config);
52 59
53 let mut led = Output::new(p.PE3, Level::High, Speed::Low); 60 let mut led = Output::new(p.PE3, Level::High, Speed::Low);
54 let cam_i2c = I2c::new(p.I2C1, p.PB8, p.PB9, Irqs, p.DMA1_CH1, p.DMA1_CH2, Default::default()); 61 let cam_i2c = I2c::new(p.I2C1, p.PB8, p.PB9, Irqs, p.DMA1_CH1, p.DMA1_CH2, Default::default());
diff --git a/examples/stm32h7/src/bin/mco.rs b/examples/stm32h7/src/bin/mco.rs
index a6ee27625..cafcb90f6 100644
--- a/examples/stm32h7/src/bin/mco.rs
+++ b/examples/stm32h7/src/bin/mco.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Speed}; 6use embassy_stm32::gpio::{Level, Output, Speed};
7use embassy_stm32::rcc::{Mco, Mco1Source, McoPrescaler}; 7use embassy_stm32::rcc::{Mco, Mco1Source, McoConfig, McoPrescaler};
8use embassy_time::Timer; 8use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
@@ -15,7 +15,13 @@ async fn main(_spawner: Spawner) {
15 15
16 let mut led = Output::new(p.PB14, Level::High, Speed::Low); 16 let mut led = Output::new(p.PB14, Level::High, Speed::Low);
17 17
18 let _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, McoPrescaler::DIV8); 18 let config = {
19 let mut config = McoConfig::default();
20 config.prescaler = McoPrescaler::DIV8;
21 config
22 };
23
24 let _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, config);
19 25
20 loop { 26 loop {
21 info!("high"); 27 info!("high");
diff --git a/examples/stm32h7rs/src/bin/mco.rs b/examples/stm32h7rs/src/bin/mco.rs
index a6ee27625..cafcb90f6 100644
--- a/examples/stm32h7rs/src/bin/mco.rs
+++ b/examples/stm32h7rs/src/bin/mco.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Speed}; 6use embassy_stm32::gpio::{Level, Output, Speed};
7use embassy_stm32::rcc::{Mco, Mco1Source, McoPrescaler}; 7use embassy_stm32::rcc::{Mco, Mco1Source, McoConfig, McoPrescaler};
8use embassy_time::Timer; 8use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
@@ -15,7 +15,13 @@ async fn main(_spawner: Spawner) {
15 15
16 let mut led = Output::new(p.PB14, Level::High, Speed::Low); 16 let mut led = Output::new(p.PB14, Level::High, Speed::Low);
17 17
18 let _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, McoPrescaler::DIV8); 18 let config = {
19 let mut config = McoConfig::default();
20 config.prescaler = McoPrescaler::DIV8;
21 config
22 };
23
24 let _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, config);
19 25
20 loop { 26 loop {
21 info!("high"); 27 info!("high");
diff --git a/examples/stm32l4/src/bin/mco.rs b/examples/stm32l4/src/bin/mco.rs
index 36c002952..4cdeaa440 100644
--- a/examples/stm32l4/src/bin/mco.rs
+++ b/examples/stm32l4/src/bin/mco.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Speed}; 6use embassy_stm32::gpio::{Level, Output, Speed};
7use embassy_stm32::rcc::{Mco, McoPrescaler, McoSource}; 7use embassy_stm32::rcc::{Mco, McoConfig, McoPrescaler, McoSource};
8use embassy_time::Timer; 8use embassy_time::Timer;
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
@@ -13,7 +13,13 @@ async fn main(_spawner: Spawner) {
13 let p = embassy_stm32::init(Default::default()); 13 let p = embassy_stm32::init(Default::default());
14 info!("Hello World!"); 14 info!("Hello World!");
15 15
16 let _mco = Mco::new(p.MCO, p.PA8, McoSource::HSI, McoPrescaler::DIV1); 16 let config = {
17 let mut config = McoConfig::default();
18 config.prescaler = McoPrescaler::DIV1;
19 config
20 };
21
22 let _mco = Mco::new(p.MCO, p.PA8, McoSource::HSI, config);
17 23
18 let mut led = Output::new(p.PB14, Level::High, Speed::Low); 24 let mut led = Output::new(p.PB14, Level::High, Speed::Low);
19 25
diff --git a/rust-toolchain-nightly.toml b/rust-toolchain-nightly.toml
index 411cc6946..dde431bba 100644
--- a/rust-toolchain-nightly.toml
+++ b/rust-toolchain-nightly.toml
@@ -1,5 +1,5 @@
1[toolchain] 1[toolchain]
2channel = "nightly-2025-06-29" 2channel = "nightly-2025-09-26"
3components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] 3components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ]
4targets = [ 4targets = [
5 "thumbv7em-none-eabi", 5 "thumbv7em-none-eabi",
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
index e24864037..5d925c934 100644
--- a/rust-toolchain.toml
+++ b/rust-toolchain.toml
@@ -1,5 +1,5 @@
1[toolchain] 1[toolchain]
2channel = "1.88" 2channel = "1.90"
3components = [ "rust-src", "rustfmt", "llvm-tools" ] 3components = [ "rust-src", "rustfmt", "llvm-tools" ]
4targets = [ 4targets = [
5 "thumbv7em-none-eabi", 5 "thumbv7em-none-eabi",
diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml
index efc297ccf..8acf27ce7 100644
--- a/tests/nrf/Cargo.toml
+++ b/tests/nrf/Cargo.toml
@@ -12,7 +12,7 @@ embassy-futures = { version = "0.1.2", path = "../../embassy-futures" }
12embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt", ] } 12embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt", ] }
13embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } 13embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
14embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 14embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
15embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } 15embassy-nrf = { version = "0.8.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] }
16embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } 16embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
17embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } 17embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] }
18embassy-net-esp-hosted = { version = "0.2.1", path = "../../embassy-net-esp-hosted", features = ["defmt"] } 18embassy-net-esp-hosted = { version = "0.2.1", path = "../../embassy-net-esp-hosted", features = ["defmt"] }
diff --git a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs
index 5f3fa1fd3..bd6a2effd 100644
--- a/tests/nrf/src/bin/ethernet_enc28j60_perf.rs
+++ b/tests/nrf/src/bin/ethernet_enc28j60_perf.rs
@@ -22,7 +22,7 @@ bind_interrupts!(struct Irqs {
22 RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>; 22 RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>;
23}); 23});
24 24
25type MyDriver = Enc28j60<ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>, Output<'static>>; 25type MyDriver = Enc28j60<ExclusiveDevice<Spim<'static>, Output<'static>, Delay>, Output<'static>>;
26 26
27#[embassy_executor::task] 27#[embassy_executor::task]
28async fn net_task(mut runner: embassy_net::Runner<'static, MyDriver>) -> ! { 28async fn net_task(mut runner: embassy_net::Runner<'static, MyDriver>) -> ! {
diff --git a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
index 34c33a4ad..091a70ce9 100644
--- a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
+++ b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
@@ -29,7 +29,7 @@ const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud";
29async fn wifi_task( 29async fn wifi_task(
30 runner: hosted::Runner< 30 runner: hosted::Runner<
31 'static, 31 'static,
32 ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>, 32 ExclusiveDevice<Spim<'static>, Output<'static>, Delay>,
33 Input<'static>, 33 Input<'static>,
34 Output<'static>, 34 Output<'static>,
35 >, 35 >,
diff --git a/tests/perf-client/Cargo.toml b/tests/perf-client/Cargo.toml
index 581b60d6f..c426fdd74 100644
--- a/tests/perf-client/Cargo.toml
+++ b/tests/perf-client/Cargo.toml
@@ -2,6 +2,7 @@
2name = "perf-client" 2name = "perf-client"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0"
5publish = false 6publish = false
6 7
7[dependencies] 8[dependencies]
diff --git a/tests/perf-server/Cargo.toml b/tests/perf-server/Cargo.toml
index 22614a33a..f048eade2 100644
--- a/tests/perf-server/Cargo.toml
+++ b/tests/perf-server/Cargo.toml
@@ -2,6 +2,7 @@
2name = "perf-server" 2name = "perf-server"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0"
5publish = false 6publish = false
6 7
7[dependencies] 8[dependencies]
diff --git a/tests/stm32/src/bin/afio.rs b/tests/stm32/src/bin/afio.rs
index cc44dc59c..81d50874b 100644
--- a/tests/stm32/src/bin/afio.rs
+++ b/tests/stm32/src/bin/afio.rs
@@ -12,8 +12,9 @@ use embassy_stm32::time::khz;
12use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}; 12use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin};
13use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; 13use embassy_stm32::timer::input_capture::{CapturePin, InputCapture};
14use embassy_stm32::timer::pwm_input::PwmInput; 14use embassy_stm32::timer::pwm_input::PwmInput;
15use embassy_stm32::timer::qei::{Qei, QeiPin}; 15use embassy_stm32::timer::qei::Qei;
16use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; 16use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm};
17use embassy_stm32::timer::{Ch1, Ch2};
17use embassy_stm32::usart::{Uart, UartRx, UartTx}; 18use embassy_stm32::usart::{Uart, UartRx, UartTx};
18use embassy_stm32::{bind_interrupts, Peripherals}; 19use embassy_stm32::{bind_interrupts, Peripherals};
19 20
@@ -258,10 +259,11 @@ async fn main(_spawner: Spawner) {
258 { 259 {
259 // partial remap 260 // partial remap
260 reset_afio_registers(); 261 reset_afio_registers();
261 Qei::new::<AfioRemap<1>>( 262 Qei::new::<Ch1, Ch2, AfioRemap<1>>(
262 p.TIM1.reborrow(), 263 p.TIM1.reborrow(),
263 QeiPin::new(p.PA8.reborrow()), 264 p.PA8.reborrow(),
264 QeiPin::new(p.PA9.reborrow()), 265 p.PA9.reborrow(),
266 Default::default(),
265 ); 267 );
266 defmt::assert_eq!(AFIO.mapr().read().tim1_remap(), 1); 268 defmt::assert_eq!(AFIO.mapr().read().tim1_remap(), 1);
267 } 269 }
diff --git a/tests/utils/Cargo.toml b/tests/utils/Cargo.toml
index f76feaa20..ddb990e0f 100644
--- a/tests/utils/Cargo.toml
+++ b/tests/utils/Cargo.toml
@@ -2,6 +2,7 @@
2name = "test-utils" 2name = "test-utils"
3version = "0.1.0" 3version = "0.1.0"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0"
5publish = false 6publish = false
6 7
7[dependencies] 8[dependencies]