aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.github/ci/build-nightly.sh3
-rwxr-xr-x.github/ci/build-xtensa.sh11
-rwxr-xr-x.github/ci/build.sh3
-rwxr-xr-x.github/ci/doc.sh68
-rwxr-xr-xci-nightly.sh17
-rwxr-xr-xci-xtensa.sh28
-rwxr-xr-xci.sh352
-rw-r--r--docs/pages/embassy_in_the_wild.adoc4
-rw-r--r--embassy-executor/CHANGELOG.md2
-rw-r--r--embassy-executor/Cargo.toml55
-rw-r--r--embassy-executor/src/metadata.rs93
-rw-r--r--embassy-executor/src/raw/deadline.rs44
-rw-r--r--embassy-executor/src/raw/mod.rs8
-rw-r--r--embassy-executor/src/raw/run_queue.rs213
-rw-r--r--embassy-executor/src/raw/run_queue_atomics.rs88
-rw-r--r--embassy-executor/src/raw/run_queue_critical_section.rs74
-rw-r--r--embassy-net-wiznet/CHANGELOG.md3
-rw-r--r--embassy-net-wiznet/src/chip/mod.rs4
-rw-r--r--embassy-net-wiznet/src/chip/w5100s.rs1
-rw-r--r--embassy-net-wiznet/src/chip/w5500.rs1
-rw-r--r--embassy-net-wiznet/src/chip/w6100.rs83
-rw-r--r--embassy-net-wiznet/src/device.rs2
-rw-r--r--embassy-net/Cargo.toml13
-rw-r--r--embassy-net/README.md1
-rw-r--r--embassy-nrf/CHANGELOG.md1
-rw-r--r--embassy-nrf/Cargo.toml7
-rw-r--r--embassy-nrf/README.md4
-rw-r--r--embassy-nrf/src/embassy_net_802154_driver.rs96
-rw-r--r--embassy-nrf/src/lib.rs11
-rw-r--r--embassy-nxp/CHANGELOG.md2
-rw-r--r--embassy-nxp/Cargo.toml13
-rw-r--r--embassy-nxp/src/chips/lpc55.rs2
-rw-r--r--embassy-nxp/src/gpio.rs2
-rw-r--r--embassy-nxp/src/gpio/lpc55.rs360
-rw-r--r--embassy-nxp/src/lib.rs10
-rw-r--r--embassy-nxp/src/pint.rs97
-rw-r--r--embassy-nxp/src/time_driver/rtc.rs76
-rw-r--r--embassy-nxp/src/usart.rs3
-rw-r--r--embassy-nxp/src/usart/lpc55.rs884
-rw-r--r--embassy-rp/CHANGELOG.md1
-rw-r--r--embassy-rp/src/pio_programs/onewire.rs45
-rw-r--r--embassy-stm32/CHANGELOG.md6
-rw-r--r--embassy-stm32/src/adc/adc4.rs3
-rw-r--r--embassy-stm32/src/adc/c0.rs3
-rw-r--r--embassy-stm32/src/adc/v3.rs2
-rw-r--r--embassy-stm32/src/adc/v4.rs3
-rw-r--r--embassy-stm32/src/hspi/mod.rs19
-rw-r--r--embassy-stm32/src/ospi/enums.rs8
-rw-r--r--embassy-stm32/src/ospi/mod.rs81
-rw-r--r--embassy-stm32/src/qspi/enums.rs7
-rw-r--r--embassy-stm32/src/qspi/mod.rs54
-rw-r--r--embassy-stm32/src/usart/buffered.rs4
-rw-r--r--embassy-stm32/src/xspi/enums.rs8
-rw-r--r--embassy-stm32/src/xspi/mod.rs20
-rw-r--r--embassy-sync/CHANGELOG.md1
-rw-r--r--embassy-sync/Cargo.toml2
-rw-r--r--embassy-sync/src/mutex.rs4
-rw-r--r--embassy-time-queue-utils/Cargo.toml3
-rw-r--r--embassy-time/Cargo.toml2
-rw-r--r--embassy-usb-dfu/CHANGELOG.md2
-rw-r--r--embassy-usb-dfu/src/application.rs1
-rw-r--r--embassy-usb-dfu/src/dfu.rs1
-rw-r--r--embassy-usb-dfu/src/lib.rs14
-rw-r--r--examples/lpc55s69/Cargo.toml2
-rw-r--r--examples/mspm0c1104/Cargo.toml3
-rw-r--r--examples/nrf52840-edf/.cargo/config.toml9
-rw-r--r--examples/nrf52840-edf/Cargo.toml27
-rw-r--r--examples/nrf52840-edf/build.rs35
-rw-r--r--examples/nrf52840-edf/memory.x12
-rw-r--r--examples/nrf52840-edf/src/bin/basic.rs194
-rw-r--r--examples/nrf52840-rtic/src/bin/blinky.rs1
-rw-r--r--examples/nrf52840/Cargo.toml4
-rw-r--r--examples/nrf52840/src/bin/sixlowpan.rs120
-rw-r--r--examples/rp/src/bin/ethernet_w55rp20_tcp_server.rs155
-rw-r--r--examples/rp/src/bin/pio_onewire.rs1
-rw-r--r--examples/rp/src/bin/pio_onewire_parasite.rs89
-rw-r--r--examples/rp235x/src/bin/pio_onewire.rs103
-rw-r--r--examples/rp235x/src/bin/pio_onewire_parasite.rs89
-rw-r--r--examples/stm32f7/src/bin/qspi.rs16
-rw-r--r--examples/stm32h742/src/bin/qspi.rs16
-rw-r--r--examples/stm32l432/src/bin/qspi_mmap.rs16
81 files changed, 2172 insertions, 1753 deletions
diff --git a/.github/ci/build-nightly.sh b/.github/ci/build-nightly.sh
index 95cb4100c..2d7c4db3f 100755
--- a/.github/ci/build-nightly.sh
+++ b/.github/ci/build-nightly.sh
@@ -7,6 +7,7 @@ set -euo pipefail
7export RUSTUP_HOME=/ci/cache/rustup 7export RUSTUP_HOME=/ci/cache/rustup
8export CARGO_HOME=/ci/cache/cargo 8export CARGO_HOME=/ci/cache/cargo
9export CARGO_TARGET_DIR=/ci/cache/target 9export CARGO_TARGET_DIR=/ci/cache/target
10export PATH=$CARGO_HOME/bin:$PATH
10mv rust-toolchain-nightly.toml rust-toolchain.toml 11mv rust-toolchain-nightly.toml rust-toolchain.toml
11 12
12# needed for "dumb HTTP" transport support 13# needed for "dumb HTTP" transport support
@@ -22,6 +23,8 @@ fi
22hashtime restore /ci/cache/filetime.json || true 23hashtime restore /ci/cache/filetime.json || true
23hashtime save /ci/cache/filetime.json 24hashtime save /ci/cache/filetime.json
24 25
26cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 280829ad163f1444999468a57d28fb7c412babbe
27
25./ci-nightly.sh 28./ci-nightly.sh
26 29
27# Save lockfiles 30# Save lockfiles
diff --git a/.github/ci/build-xtensa.sh b/.github/ci/build-xtensa.sh
index 103575bc9..b6626639d 100755
--- a/.github/ci/build-xtensa.sh
+++ b/.github/ci/build-xtensa.sh
@@ -7,13 +7,14 @@ set -euo pipefail
7export RUSTUP_HOME=/ci/cache/rustup 7export RUSTUP_HOME=/ci/cache/rustup
8export CARGO_HOME=/ci/cache/cargo 8export CARGO_HOME=/ci/cache/cargo
9export CARGO_TARGET_DIR=/ci/cache/target 9export CARGO_TARGET_DIR=/ci/cache/target
10export PATH=$CARGO_HOME/bin:$PATH
10 11
11# needed for "dumb HTTP" transport support 12# needed for "dumb HTTP" transport support
12# used when pointing stm32-metapac to a CI-built one. 13# used when pointing stm32-metapac to a CI-built one.
13export CARGO_NET_GIT_FETCH_WITH_CLI=true 14export CARGO_NET_GIT_FETCH_WITH_CLI=true
14 15
15cargo install espup 16cargo install espup --locked
16/ci/cache/cargo/bin/espup install --toolchain-version 1.84.0.0 17espup install --toolchain-version 1.88.0.0
17 18
18# Restore lockfiles 19# Restore lockfiles
19if [ -f /ci/cache/lockfiles.tar ]; then 20if [ -f /ci/cache/lockfiles.tar ]; then
@@ -24,11 +25,7 @@ fi
24hashtime restore /ci/cache/filetime.json || true 25hashtime restore /ci/cache/filetime.json || true
25hashtime save /ci/cache/filetime.json 26hashtime save /ci/cache/filetime.json
26 27
27mkdir .cargo 28cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 280829ad163f1444999468a57d28fb7c412babbe
28cat > .cargo/config.toml<< EOF
29[unstable]
30build-std = ["alloc", "core"]
31EOF
32 29
33./ci-xtensa.sh 30./ci-xtensa.sh
34 31
diff --git a/.github/ci/build.sh b/.github/ci/build.sh
index 68a7c0c34..59bcefed6 100755
--- a/.github/ci/build.sh
+++ b/.github/ci/build.sh
@@ -7,6 +7,7 @@ set -euo pipefail
7export RUSTUP_HOME=/ci/cache/rustup 7export RUSTUP_HOME=/ci/cache/rustup
8export CARGO_HOME=/ci/cache/cargo 8export CARGO_HOME=/ci/cache/cargo
9export CARGO_TARGET_DIR=/ci/cache/target 9export CARGO_TARGET_DIR=/ci/cache/target
10export PATH=$CARGO_HOME/bin:$PATH
10if [ -f /ci/secrets/teleprobe-token.txt ]; then 11if [ -f /ci/secrets/teleprobe-token.txt ]; then
11 echo Got teleprobe token! 12 echo Got teleprobe token!
12 export TELEPROBE_HOST=https://teleprobe.embassy.dev 13 export TELEPROBE_HOST=https://teleprobe.embassy.dev
@@ -27,6 +28,8 @@ fi
27hashtime restore /ci/cache/filetime.json || true 28hashtime restore /ci/cache/filetime.json || true
28hashtime save /ci/cache/filetime.json 29hashtime save /ci/cache/filetime.json
29 30
31cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked --rev 280829ad163f1444999468a57d28fb7c412babbe
32
30./ci.sh 33./ci.sh
31 34
32# Save lockfiles 35# Save lockfiles
diff --git a/.github/ci/doc.sh b/.github/ci/doc.sh
index ac96008d8..876c261a1 100755
--- a/.github/ci/doc.sh
+++ b/.github/ci/doc.sh
@@ -19,42 +19,42 @@ mv rust-toolchain-nightly.toml rust-toolchain.toml
19# which makes rustup very sad 19# which makes rustup very sad
20rustc --version > /dev/null 20rustc --version > /dev/null
21 21
22docserver-builder -i ./embassy-boot -o webroot/crates/embassy-boot/git.zup 22docserver build -i ./embassy-boot -o webroot/crates/embassy-boot/git.zup
23docserver-builder -i ./embassy-boot-nrf -o webroot/crates/embassy-boot-nrf/git.zup 23docserver build -i ./embassy-boot-nrf -o webroot/crates/embassy-boot-nrf/git.zup
24docserver-builder -i ./embassy-boot-rp -o webroot/crates/embassy-boot-rp/git.zup 24docserver build -i ./embassy-boot-rp -o webroot/crates/embassy-boot-rp/git.zup
25docserver-builder -i ./embassy-boot-stm32 -o webroot/crates/embassy-boot-stm32/git.zup 25docserver build -i ./embassy-boot-stm32 -o webroot/crates/embassy-boot-stm32/git.zup
26docserver-builder -i ./embassy-embedded-hal -o webroot/crates/embassy-embedded-hal/git.zup 26docserver build -i ./embassy-embedded-hal -o webroot/crates/embassy-embedded-hal/git.zup
27docserver-builder -i ./embassy-executor -o webroot/crates/embassy-executor/git.zup 27docserver build -i ./embassy-executor -o webroot/crates/embassy-executor/git.zup
28docserver-builder -i ./embassy-futures -o webroot/crates/embassy-futures/git.zup 28docserver build -i ./embassy-futures -o webroot/crates/embassy-futures/git.zup
29docserver-builder -i ./embassy-nrf -o webroot/crates/embassy-nrf/git.zup 29docserver build -i ./embassy-nrf -o webroot/crates/embassy-nrf/git.zup
30docserver-builder -i ./embassy-rp -o webroot/crates/embassy-rp/git.zup 30docserver build -i ./embassy-rp -o webroot/crates/embassy-rp/git.zup
31docserver-builder -i ./embassy-mspm0 -o webroot/crates/embassy-mspm0/git.zup 31docserver build -i ./embassy-mspm0 -o webroot/crates/embassy-mspm0/git.zup
32docserver-builder -i ./embassy-nxp -o webroot/crates/embassy-nxp/git.zup 32docserver build -i ./embassy-nxp -o webroot/crates/embassy-nxp/git.zup
33docserver-builder -i ./embassy-sync -o webroot/crates/embassy-sync/git.zup 33docserver build -i ./embassy-sync -o webroot/crates/embassy-sync/git.zup
34docserver-builder -i ./cyw43 -o webroot/crates/cyw43/git.zup 34docserver build -i ./cyw43 -o webroot/crates/cyw43/git.zup
35docserver-builder -i ./cyw43-pio -o webroot/crates/cyw43-pio/git.zup 35docserver build -i ./cyw43-pio -o webroot/crates/cyw43-pio/git.zup
36docserver-builder -i ./embassy-stm32-wpan -o webroot/crates/embassy-stm32-wpan/git.zup --output-static webroot/static 36docserver build -i ./embassy-stm32-wpan -o webroot/crates/embassy-stm32-wpan/git.zup --output-static webroot/static
37 37
38docserver-builder -i ./embassy-time -o webroot/crates/embassy-time/git.zup 38docserver build -i ./embassy-time -o webroot/crates/embassy-time/git.zup
39docserver-builder -i ./embassy-time-driver -o webroot/crates/embassy-time-driver/git.zup 39docserver build -i ./embassy-time-driver -o webroot/crates/embassy-time-driver/git.zup
40docserver-builder -i ./embassy-time-queue-utils -o webroot/crates/embassy-time-queue-utils/git.zup 40docserver build -i ./embassy-time-queue-utils -o webroot/crates/embassy-time-queue-utils/git.zup
41 41
42docserver-builder -i ./embassy-usb -o webroot/crates/embassy-usb/git.zup 42docserver build -i ./embassy-usb -o webroot/crates/embassy-usb/git.zup
43docserver-builder -i ./embassy-usb-dfu -o webroot/crates/embassy-usb-dfu/git.zup 43docserver build -i ./embassy-usb-dfu -o webroot/crates/embassy-usb-dfu/git.zup
44docserver-builder -i ./embassy-usb-driver -o webroot/crates/embassy-usb-driver/git.zup 44docserver build -i ./embassy-usb-driver -o webroot/crates/embassy-usb-driver/git.zup
45docserver-builder -i ./embassy-usb-logger -o webroot/crates/embassy-usb-logger/git.zup 45docserver build -i ./embassy-usb-logger -o webroot/crates/embassy-usb-logger/git.zup
46docserver-builder -i ./embassy-usb-synopsys-otg -o webroot/crates/embassy-usb-synopsys-otg/git.zup 46docserver build -i ./embassy-usb-synopsys-otg -o webroot/crates/embassy-usb-synopsys-otg/git.zup
47 47
48docserver-builder -i ./embassy-net -o webroot/crates/embassy-net/git.zup 48docserver build -i ./embassy-net -o webroot/crates/embassy-net/git.zup
49docserver-builder -i ./embassy-net-nrf91 -o webroot/crates/embassy-net-nrf91/git.zup 49docserver build -i ./embassy-net-nrf91 -o webroot/crates/embassy-net-nrf91/git.zup
50docserver-builder -i ./embassy-net-driver -o webroot/crates/embassy-net-driver/git.zup 50docserver build -i ./embassy-net-driver -o webroot/crates/embassy-net-driver/git.zup
51docserver-builder -i ./embassy-net-driver-channel -o webroot/crates/embassy-net-driver-channel/git.zup 51docserver build -i ./embassy-net-driver-channel -o webroot/crates/embassy-net-driver-channel/git.zup
52docserver-builder -i ./embassy-net-wiznet -o webroot/crates/embassy-net-wiznet/git.zup 52docserver build -i ./embassy-net-wiznet -o webroot/crates/embassy-net-wiznet/git.zup
53docserver-builder -i ./embassy-net-ppp -o webroot/crates/embassy-net-ppp/git.zup 53docserver build -i ./embassy-net-ppp -o webroot/crates/embassy-net-ppp/git.zup
54docserver-builder -i ./embassy-net-tuntap -o webroot/crates/embassy-net-tuntap/git.zup 54docserver build -i ./embassy-net-tuntap -o webroot/crates/embassy-net-tuntap/git.zup
55docserver-builder -i ./embassy-net-enc28j60 -o webroot/crates/embassy-net-enc28j60/git.zup 55docserver build -i ./embassy-net-enc28j60 -o webroot/crates/embassy-net-enc28j60/git.zup
56docserver-builder -i ./embassy-net-esp-hosted -o webroot/crates/embassy-net-esp-hosted/git.zup 56docserver build -i ./embassy-net-esp-hosted -o webroot/crates/embassy-net-esp-hosted/git.zup
57docserver-builder -i ./embassy-net-adin1110 -o webroot/crates/embassy-net-adin1110/git.zup 57docserver build -i ./embassy-net-adin1110 -o webroot/crates/embassy-net-adin1110/git.zup
58 58
59export KUBECONFIG=/ci/secrets/kubeconfig.yml 59export KUBECONFIG=/ci/secrets/kubeconfig.yml
60POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name}) 60POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name})
@@ -65,6 +65,6 @@ kubectl cp webroot/static $POD:/data
65# so that it doesn't prevent other crates from getting docs updates when it breaks. 65# so that it doesn't prevent other crates from getting docs updates when it breaks.
66 66
67rm -rf webroot 67rm -rf webroot
68docserver-builder -i ./embassy-stm32 -o webroot/crates/embassy-stm32/git.zup 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}) 69POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name})
70kubectl cp webroot/crates $POD:/data 70kubectl cp webroot/crates $POD:/data
diff --git a/ci-nightly.sh b/ci-nightly.sh
index d486d442c..afe9f534c 100755
--- a/ci-nightly.sh
+++ b/ci-nightly.sh
@@ -8,19 +8,4 @@ if [[ -z "${CARGO_TARGET_DIR}" ]]; then
8 export CARGO_TARGET_DIR=target_ci 8 export CARGO_TARGET_DIR=target_ci
9fi 9fi
10 10
11cargo batch \ 11cargo embassy-devtool build --group nightly
12 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly \
13 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,log \
14 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,defmt \
15 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
16 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt,arch-cortex-m,executor-thread,executor-interrupt \
17 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m \
18 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread \
19 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt \
20 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt \
21 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32 \
22 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread \
23 --- build --release --manifest-path examples/nrf52840-rtic/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/nrf52840-rtic \
24 --- build --release --manifest-path embassy-executor/Cargo.toml --target armv7a-none-eabi --features nightly,arch-cortex-ar,executor-thread \
25
26RUSTFLAGS="$RUSTFLAGS -C target-cpu=atmega328p" cargo build --release --manifest-path embassy-executor/Cargo.toml --target avr-none -Z build-std=core,alloc --features nightly,arch-avr,avr-device/atmega328p
diff --git a/ci-xtensa.sh b/ci-xtensa.sh
index 6c9807e98..0dd41a9ce 100755
--- a/ci-xtensa.sh
+++ b/ci-xtensa.sh
@@ -9,30 +9,4 @@ if [[ -z "${CARGO_TARGET_DIR}" ]]; then
9 export CARGO_TARGET_DIR=target_ci 9 export CARGO_TARGET_DIR=target_ci
10fi 10fi
11 11
12cargo batch \ 12cargo embassy-devtool build --group xtensa
13 --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf \
14 --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features log \
15 --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features defmt \
16 --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt \
17 --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features defmt,arch-spin,executor-thread \
18 --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt,arch-spin,executor-thread \
19 --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32s3-none-elf --features defmt,arch-spin,executor-thread \
20 --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin \
21 --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin,rtos-trace \
22 --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin,executor-thread \
23 --- build --release --manifest-path embassy-sync/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt \
24 --- build --release --manifest-path embassy-time/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt,defmt-timestamp-uptime,mock-driver \
25 --- build --release --manifest-path embassy-time-queue-utils/Cargo.toml --target xtensa-esp32s2-none-elf \
26 --- build --release --manifest-path embassy-time-queue-utils/Cargo.toml --target xtensa-esp32s2-none-elf --features generic-queue-8 \
27 --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet,packet-trace \
28 --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,multicast,medium-ethernet \
29 --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \
30 --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,dhcpv4-hostname \
31 --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \
32 --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv6,medium-ieee802154 \
33 --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,medium-ieee802154 \
34 --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \
35 --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet \
36 --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip \
37 --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet \
38 --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet,medium-ieee802154 \
diff --git a/ci.sh b/ci.sh
index 50fb3e13d..6cc2a031d 100755
--- a/ci.sh
+++ b/ci.sh
@@ -10,355 +10,21 @@ if ! command -v cargo-batch &> /dev/null; then
10 exit 1 10 exit 1
11fi 11fi
12 12
13if ! command -v cargo-embassy-devtool &> /dev/null; then
14 echo "cargo-embassy-devtool could not be found. Install it with the following command:"
15 echo ""
16 echo " cargo install --git https://github.com/embassy-rs/cargo-embassy-devtool --locked"
17 echo ""
18 exit 1
19fi
20
13export RUSTFLAGS=-Dwarnings 21export RUSTFLAGS=-Dwarnings
14export DEFMT_LOG=trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info 22export DEFMT_LOG=trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info
15if [[ -z "${CARGO_TARGET_DIR}" ]]; then 23if [[ -z "${CARGO_TARGET_DIR}" ]]; then
16 export CARGO_TARGET_DIR=target_ci 24 export CARGO_TARGET_DIR=target_ci
17fi 25fi
18 26
19TARGET=$(rustc -vV | sed -n 's|host: ||p') 27cargo embassy-devtool build
20
21BUILD_EXTRA=""
22if [ $TARGET = "x86_64-unknown-linux-gnu" ] || [ $TARGET = "aarch64-unknown-linux-gnu" ]; then
23 BUILD_EXTRA="--- build --release --manifest-path examples/std/Cargo.toml --target $TARGET --artifact-dir out/examples/std"
24fi
25
26# CI intentionally does not use -eabihf on thumbv7em to minimize dep compile time.
27cargo batch \
28 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi \
29 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features log \
30 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features defmt \
31 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt \
32 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt,arch-cortex-m,executor-thread,executor-interrupt \
33 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m \
34 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,metadata-name \
35 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,trace \
36 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,rtos-trace \
37 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,trace,rtos-trace \
38 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread \
39 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-interrupt \
40 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread,executor-interrupt \
41 --- build --release --manifest-path embassy-executor/Cargo.toml --target armv7a-none-eabi --features arch-cortex-ar,executor-thread \
42 --- build --release --manifest-path embassy-executor/Cargo.toml --target armv7r-none-eabi --features arch-cortex-ar,executor-thread \
43 --- build --release --manifest-path embassy-executor/Cargo.toml --target armv7r-none-eabihf --features arch-cortex-ar,executor-thread \
44 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32 \
45 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,executor-thread \
46 --- build --release --manifest-path embassy-embedded-hal/Cargo.toml --target thumbv7em-none-eabi \
47 --- build --release --manifest-path embassy-embedded-hal/Cargo.toml --target thumbv7em-none-eabi --features time \
48 --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features defmt \
49 --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features defmt,defmt-timestamp-uptime,mock-driver \
50 --- build --release --manifest-path embassy-time/Cargo.toml --features defmt,std \
51 --- build --release --manifest-path embassy-time-queue-utils/Cargo.toml --target thumbv6m-none-eabi \
52 --- build --release --manifest-path embassy-time-queue-utils/Cargo.toml --target thumbv6m-none-eabi --features generic-queue-8 \
53 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet,packet-trace \
54 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,multicast,medium-ethernet \
55 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \
56 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,dhcpv4-hostname \
57 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \
58 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ieee802154 \
59 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,medium-ieee802154 \
60 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \
61 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet \
62 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip \
63 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet \
64 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet,medium-ieee802154 \
65 --- build --release --manifest-path embassy-imxrt/Cargo.toml --target thumbv8m.main-none-eabihf --features mimxrt633s,defmt,unstable-pac,time,time-driver-rtc \
66 --- build --release --manifest-path embassy-imxrt/Cargo.toml --target thumbv8m.main-none-eabihf --features mimxrt685s,defmt,unstable-pac,time,time-driver-rtc \
67 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,gpiote,time,time-driver-rtc1 \
68 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52805,gpiote,time,time-driver-rtc1 \
69 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52810,gpiote,time,time-driver-rtc1 \
70 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52811,gpiote,time,time-driver-rtc1 \
71 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52820,gpiote,time,time-driver-rtc1 \
72 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52832,gpiote,time,time-driver-rtc1,reset-pin-as-gpio \
73 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52833,gpiote,time,time-driver-rtc1,nfc-pins-as-gpio \
74 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf9160-s,gpiote,time,time-driver-rtc1 \
75 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf9160-ns,gpiote,time,time-driver-rtc1 \
76 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-app-s,gpiote,time,time-driver-rtc1 \
77 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-app-ns,gpiote,time,time-driver-rtc1 \
78 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-net,gpiote,time,time-driver-rtc1 \
79 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf54l15-app-s,gpiote,time,time-driver-rtc1 \
80 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf54l15-app-ns,gpiote,time,time-driver-rtc1 \
81 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,time \
82 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,time-driver-rtc1 \
83 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,time,time-driver-rtc1 \
84 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,log,time \
85 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,log,time-driver-rtc1 \
86 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,log,time,time-driver-rtc1 \
87 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time \
88 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time-driver-rtc1 \
89 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time,time-driver-rtc1 \
90 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,defmt,time,time-driver-rtc1 \
91 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,defmt,time \
92 --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,time \
93 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,defmt,rp2040 \
94 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,log,rp2040 \
95 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,intrinsics,rp2040 \
96 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,qspi-as-gpio,rp2040 \
97 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,defmt,rp235xa \
98 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,log,rp235xa \
99 --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv8m.main-none-eabihf --features time-driver,rp235xa,binary-info \
100 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,exti,time-driver-any,time \
101 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,time-driver-any,time \
102 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,exti,time \
103 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,time \
104 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,exti,time-driver-any,time \
105 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,time-driver-any,time \
106 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,exti,time \
107 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,time \
108 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,exti \
109 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt \
110 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,single-bank,defmt \
111 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32c071rb,defmt,exti,time-driver-any,time \
112 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32c051f6,defmt,exti,time-driver-any,time \
113 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32c091gb,defmt,exti,time-driver-any,time \
114 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32c092rc,defmt,exti,time-driver-any,time \
115 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f038f6,defmt,exti,time-driver-any,time \
116 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f030c6,defmt,exti,time-driver-any,time \
117 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f058t8,defmt,exti,time-driver-any,time \
118 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f030r8,defmt,exti,time-driver-any,time \
119 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f031k6,defmt,exti,time-driver-any,time \
120 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f030rc,defmt,exti,time-driver-any,time \
121 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f070f6,defmt,exti,time-driver-any,time \
122 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f078vb,defmt,exti,time-driver-any,time \
123 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f042g4,defmt,exti,time-driver-any,time \
124 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f072c8,defmt,exti,time-driver-any,time \
125 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f401ve,defmt,exti,time-driver-any \
126 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f405zg,defmt,exti,time-driver-any \
127 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f407zg,defmt,exti,time-driver-any \
128 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f401ve,defmt,exti,time-driver-any,time \
129 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f405zg,defmt,exti,time-driver-any,time \
130 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f407zg,defmt,exti,time-driver-any,time \
131 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any,time \
132 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,exti,time-driver-any,time \
133 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f412zg,defmt,exti,time-driver-any,time \
134 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f413vh,defmt,exti,time-driver-any,time \
135 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f415zg,defmt,exti,time-driver-any,time \
136 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f417zg,defmt,exti,time-driver-any,time \
137 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f423zh,defmt,exti,time-driver-any,time \
138 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f427zi,defmt,exti,time-driver-any,time \
139 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,time \
140 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f437zi,log,exti,time-driver-any,time \
141 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f439zi,defmt,exti,time-driver-any,time \
142 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f446ze,defmt,exti,time-driver-any,time \
143 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f469zi,defmt,exti,time-driver-any,time \
144 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f479zi,defmt,exti,time-driver-any,time \
145 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f730i8,defmt,exti,time-driver-any,time \
146 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h753zi,defmt,exti,time-driver-any,time \
147 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h735zg,defmt,exti,time-driver-any,time \
148 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,time,split-pc2,split-pc3 \
149 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h725re,defmt,exti,time-driver-any,time \
150 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7b3ai,defmt,exti,time-driver-any,time \
151 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7b3ai,defmt,exti,time-driver-tim1,time \
152 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7r3z8,defmt,exti,time-driver-tim1,time \
153 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7r7a8,defmt,exti,time-driver-tim1,time \
154 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7s3a8,defmt,exti,time-driver-tim1,time \
155 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7s7z8,defmt,exti,time-driver-tim1,time \
156 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l431cb,defmt,exti,time-driver-any,time \
157 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,time \
158 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l422cb,defmt,exti,time-driver-any,time \
159 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb15cc,defmt,exti,time-driver-any,time \
160 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any,time \
161 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l041f6,defmt,exti,time-driver-any,time \
162 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l051k8,defmt,exti,time-driver-any,time \
163 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l073cz,defmt,exti,time-driver-any,low-power,time \
164 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,time \
165 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303c8,defmt,exti,time-driver-any,time \
166 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f398ve,defmt,exti,time-driver-any,time \
167 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f378cc,defmt,exti,time-driver-any,time \
168 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g0b0ce,defmt,exti,time-driver-any,time \
169 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g0c1ve,defmt,exti,time-driver-any,time \
170 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,time \
171 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,dual-bank,defmt,exti,time-driver-any,low-power,time \
172 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32wl54jc-cm0p,defmt,exti,time-driver-any,time \
173 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wle5jb,defmt,exti,time-driver-any,time \
174 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g431kb,defmt,exti,time-driver-any,time \
175 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g474pe,dual-bank,defmt,exti,time-driver-any,time \
176 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f107vc,defmt,exti,time-driver-any,time \
177 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103re,defmt,exti,time-driver-any,time \
178 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f100c4,defmt,exti,time-driver-any,time \
179 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h503rb,defmt,exti,time-driver-any,time \
180 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h523cc,defmt,exti,time-driver-any,time \
181 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h562ag,defmt,exti,time-driver-any,time \
182 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32wba50ke,defmt,exti,time-driver-any,time \
183 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32wba55ug,defmt,exti,time-driver-any,time \
184 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32wba62cg,defmt,exti,time-driver-any,time \
185 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32wba65ri,defmt,exti,time-driver-any,low-power,time \
186 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32u5f9zj,defmt,exti,time-driver-any,time \
187 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32u5g9nj,defmt,exti,time-driver-any,time \
188 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb35ce,defmt,exti,time-driver-any,time \
189 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg,defmt,exti,time-driver-any,low-power,time \
190 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u031r8,defmt,exti,time-driver-any,time \
191 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u073mb,defmt,exti,time-driver-any,time \
192 --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u083rc,defmt,exti,time-driver-any,time \
193 --- build --release --manifest-path embassy-nxp/Cargo.toml --target thumbv8m.main-none-eabihf --features lpc55,defmt \
194 --- build --release --manifest-path embassy-nxp/Cargo.toml --target thumbv7em-none-eabihf --features mimxrt1011,rt,defmt,time-driver-pit \
195 --- build --release --manifest-path embassy-nxp/Cargo.toml --target thumbv7em-none-eabihf --features mimxrt1062,rt,defmt,time-driver-pit \
196 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0c1104dgs20,rt,defmt,time-driver-any \
197 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0c1106rgz,rt,defmt,time-driver-any \
198 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g3507pm,rt,defmt,time-driver-any \
199 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g3519pz,rt,defmt,time-driver-any \
200 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l1306rhb,rt,defmt,time-driver-any \
201 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l2228pn,rt,defmt,time-driver-any \
202 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l1345dgs28,rt,defmt,time-driver-any \
203 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l1106dgs28,rt,defmt,time-driver-any \
204 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l1228pm,rt,defmt,time-driver-any \
205 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g1107ycj,rt,defmt,time-driver-any \
206 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g3105rhb,rt,defmt,time-driver-any \
207 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g1505pt,rt,defmt,time-driver-any \
208 --- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g1519rhb,rt,defmt,time-driver-any \
209 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features ''\
210 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log' \
211 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \
212 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log,firmware-logs' \
213 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt,firmware-logs' \
214 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log,firmware-logs,bluetooth' \
215 --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt,firmware-logs,bluetooth' \
216 --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'embassy-rp/rp2040' \
217 --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'embassy-rp/rp2040' \
218 --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
219 --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf5340-app-s \
220 --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \
221 --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns \
222 --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9151-ns \
223 --- build --release --manifest-path embassy-boot-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9161-ns \
224 --- build --release --manifest-path embassy-boot-rp/Cargo.toml --target thumbv6m-none-eabi --features embassy-rp/rp2040 \
225 --- build --release --manifest-path embassy-boot-stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32l496zg \
226 --- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi --no-default-features \
227 --- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi \
228 --- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi --features log \
229 --- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi --features defmt \
230 --- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi --features usbd-hid \
231 --- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi --features max-interface-count-1 \
232 --- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi --features max-interface-count-8 \
233 --- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi --features max-handler-count-8 \
234 --- build --release --manifest-path embassy-usb/Cargo.toml --target thumbv6m-none-eabi --features max-handler-count-8 \
235 --- build --release --manifest-path docs/examples/basic/Cargo.toml --target thumbv7em-none-eabi \
236 --- build --release --manifest-path docs/examples/layer-by-layer/blinky-pac/Cargo.toml --target thumbv7em-none-eabi \
237 --- build --release --manifest-path docs/examples/layer-by-layer/blinky-hal/Cargo.toml --target thumbv7em-none-eabi \
238 --- build --release --manifest-path docs/examples/layer-by-layer/blinky-irq/Cargo.toml --target thumbv7em-none-eabi \
239 --- build --release --manifest-path docs/examples/layer-by-layer/blinky-async/Cargo.toml --target thumbv7em-none-eabi \
240 --- build --release --manifest-path examples/nrf52810/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/nrf52810 \
241 --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/nrf52840 \
242 --- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/nrf5340 \
243 --- build --release --manifest-path examples/nrf54l15/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/nrf54l15 \
244 --- build --release --manifest-path examples/nrf9160/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/nrf9160 \
245 --- build --release --manifest-path examples/nrf9151/s/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/nrf9151/s \
246 --- build --release --manifest-path examples/nrf9151/ns/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/nrf9151/ns \
247 --- build --release --manifest-path examples/nrf51/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/nrf51 \
248 --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/rp \
249 --- build --release --manifest-path examples/rp235x/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/rp235x \
250 --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/stm32f0 \
251 --- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --artifact-dir out/examples/stm32f1 \
252 --- build --release --manifest-path examples/stm32f2/Cargo.toml --target thumbv7m-none-eabi --artifact-dir out/examples/stm32f2 \
253 --- build --release --manifest-path examples/stm32f3/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32f3 \
254 --- build --release --manifest-path examples/stm32f334/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32f334 \
255 --- build --release --manifest-path examples/stm32f4/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32f4 \
256 --- build --release --manifest-path examples/stm32f469/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32f469 \
257 --- build --release --manifest-path examples/stm32f7/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32f7 \
258 --- build --release --manifest-path examples/stm32c0/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/stm32c0 \
259 --- build --release --manifest-path examples/stm32g0/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/stm32g0 \
260 --- build --release --manifest-path examples/stm32g4/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32g4 \
261 --- build --release --manifest-path examples/stm32h5/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/stm32h5 \
262 --- build --release --manifest-path examples/stm32h7/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32h7 \
263 --- build --release --manifest-path examples/stm32h7b0/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32h7b0 \
264 --- build --release --manifest-path examples/stm32h723/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32h723 \
265 --- build --release --manifest-path examples/stm32h735/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32h735 \
266 --- build --release --manifest-path examples/stm32h755cm4/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32h755cm4 \
267 --- build --release --manifest-path examples/stm32h755cm7/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32h755cm7 \
268 --- build --release --manifest-path examples/stm32h7rs/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32h7rs \
269 --- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/stm32l0 \
270 --- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --artifact-dir out/examples/stm32l1 \
271 --- build --release --manifest-path examples/stm32l4/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32l4 \
272 --- build --release --manifest-path examples/stm32l432/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32l432 \
273 --- build --release --manifest-path examples/stm32l5/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/stm32l5 \
274 --- build --release --manifest-path examples/stm32u0/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/stm32u0 \
275 --- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/stm32u5 \
276 --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32wb \
277 --- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/stm32wba \
278 --- build --release --manifest-path examples/stm32wba6/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/stm32wba6 \
279 --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32wl \
280 --- build --release --manifest-path examples/lpc55s69/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/lpc55s69 \
281 --- build --release --manifest-path examples/mimxrt1011/Cargo.toml --target thumbv7em-none-eabihf --artifact-dir out/examples/mimxrt1011 \
282 --- build --release --manifest-path examples/mimxrt1062-evk/Cargo.toml --target thumbv7em-none-eabihf --artifact-dir out/examples/mimxrt1062-evk \
283 --- build --release --manifest-path examples/mspm0g3507/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0g3507 \
284 --- build --release --manifest-path examples/mspm0g3519/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0g3519 \
285 --- build --release --manifest-path examples/mspm0l1306/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0l1306 \
286 --- build --release --manifest-path examples/mspm0l2228/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0l2228 \
287 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --artifact-dir out/examples/boot/nrf52840 \
288 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --artifact-dir out/examples/boot/nrf9160 \
289 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns,skip-include --artifact-dir out/examples/boot/nrf9120 \
290 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9151-ns,skip-include --artifact-dir out/examples/boot/nrf9151 \
291 --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9161-ns,skip-include --artifact-dir out/examples/boot/nrf9161 \
292 --- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --features skip-include --artifact-dir out/examples/boot/rp \
293 --- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --features skip-include --artifact-dir out/examples/boot/stm32f3 \
294 --- build --release --manifest-path examples/boot/application/stm32f7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --artifact-dir out/examples/boot/stm32f7 \
295 --- build --release --manifest-path examples/boot/application/stm32h7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --artifact-dir out/examples/boot/stm32h7 \
296 --- build --release --manifest-path examples/boot/application/stm32l0/Cargo.toml --target thumbv6m-none-eabi --features skip-include --artifact-dir out/examples/boot/stm32l0 \
297 --- build --release --manifest-path examples/boot/application/stm32l1/Cargo.toml --target thumbv7m-none-eabi --features skip-include --artifact-dir out/examples/boot/stm32l1 \
298 --- build --release --manifest-path examples/boot/application/stm32l4/Cargo.toml --target thumbv7em-none-eabi --features skip-include --artifact-dir out/examples/boot/stm32l4 \
299 --- build --release --manifest-path examples/boot/application/stm32wl/Cargo.toml --target thumbv7em-none-eabi --features skip-include --artifact-dir out/examples/boot/stm32wl \
300 --- build --release --manifest-path examples/boot/application/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/boot/stm32wb-dfu \
301 --- build --release --manifest-path examples/boot/application/stm32wba-dfu/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/boot/stm32wba-dfu \
302 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
303 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \
304 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns \
305 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9151-ns \
306 --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9161-ns \
307 --- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \
308 --- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32l496zg \
309 --- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wb55rg \
310 --- build --release --manifest-path examples/boot/bootloader/stm32wb-dfu/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wb55rg,verify \
311 --- build --release --manifest-path examples/boot/bootloader/stm32wba-dfu/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-stm32/stm32wba65ri,verify \
312 --- build --release --manifest-path examples/boot/bootloader/stm32-dual-bank/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32h743zi \
313 --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --artifact-dir out/examples/wasm \
314 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f100rd --artifact-dir out/tests/stm32f100rd \
315 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --artifact-dir out/tests/stm32f103c8 \
316 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f107vc --artifact-dir out/tests/stm32f107vc \
317 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --artifact-dir out/tests/stm32f429zi \
318 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f446re --artifact-dir out/tests/stm32f446re \
319 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g491re --artifact-dir out/tests/stm32g491re \
320 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g071rb --artifact-dir out/tests/stm32g071rb \
321 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32c031c6 --artifact-dir out/tests/stm32c031c6 \
322 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32c071rb --artifact-dir out/tests/stm32c071rb \
323 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi --artifact-dir out/tests/stm32h755zi \
324 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h753zi --artifact-dir out/tests/stm32h753zi \
325 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7a3zi --artifact-dir out/tests/stm32h7a3zi \
326 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --artifact-dir out/tests/stm32wb55rg \
327 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h563zi --artifact-dir out/tests/stm32h563zi \
328 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32u585ai --artifact-dir out/tests/stm32u585ai \
329 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32u5a5zj --artifact-dir out/tests/stm32u5a5zj \
330 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32wba52cg --artifact-dir out/tests/stm32wba52cg \
331 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l073rz --artifact-dir out/tests/stm32l073rz \
332 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l152re --artifact-dir out/tests/stm32l152re \
333 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4a6zg --artifact-dir out/tests/stm32l4a6zg \
334 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4r5zi --artifact-dir out/tests/stm32l4r5zi \
335 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze --artifact-dir out/tests/stm32l552ze \
336 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f767zi --artifact-dir out/tests/stm32f767zi \
337 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f207zg --artifact-dir out/tests/stm32f207zg \
338 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303ze --artifact-dir out/tests/stm32f303ze \
339 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l496zg --artifact-dir out/tests/stm32l496zg \
340 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55jc --artifact-dir out/tests/stm32wl55jc \
341 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7s3l8 --artifact-dir out/tests/stm32h7s3l8 \
342 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32f091rc --artifact-dir out/tests/stm32f091rc \
343 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h503rb --artifact-dir out/tests/stm32h503rb \
344 --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u083rc --artifact-dir out/tests/stm32u083rc \
345 --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --features rp2040 --artifact-dir out/tests/rpi-pico \
346 --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv8m.main-none-eabihf --features rp235xb --artifact-dir out/tests/pimoroni-pico-plus-2 \
347 --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51422 --artifact-dir out/tests/nrf51422-dk \
348 --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52832 --artifact-dir out/tests/nrf52832-dk \
349 --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52833 --artifact-dir out/tests/nrf52833-dk \
350 --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840 --artifact-dir out/tests/nrf52840-dk \
351 --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340 --artifact-dir out/tests/nrf5340-dk \
352 --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf9160 --artifact-dir out/tests/nrf9160-dk \
353 --- build --release --manifest-path tests/mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g3507 --artifact-dir out/tests/mspm0g3507 \
354 --- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \
355 $BUILD_EXTRA
356
357
358# MSPM0C1104 must be built seperately since cargo batch does not consider env vars set in `.cargo/config.toml`.
359# Since the target has 1KB of ram, we need to limit defmt's buffer size.
360DEFMT_RTT_BUFFER_SIZE="72" cargo batch \
361 --- build --release --manifest-path examples/mspm0c1104/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0c1104 \
362 28
363# temporarily disabled, these boards are dead. 29# temporarily disabled, these boards are dead.
364rm -rf out/tests/stm32f103c8 30rm -rf out/tests/stm32f103c8
diff --git a/docs/pages/embassy_in_the_wild.adoc b/docs/pages/embassy_in_the_wild.adoc
index 620794c31..cedbedada 100644
--- a/docs/pages/embassy_in_the_wild.adoc
+++ b/docs/pages/embassy_in_the_wild.adoc
@@ -2,6 +2,10 @@
2 2
3Here are known examples of real-world projects which make use of Embassy. Feel free to link:https://github.com/embassy-rs/embassy/blob/main/docs/pages/embassy_in_the_wild.adoc[add more]! 3Here are known examples of real-world projects which make use of Embassy. Feel free to link:https://github.com/embassy-rs/embassy/blob/main/docs/pages/embassy_in_the_wild.adoc[add more]!
4 4
5_newer entries at the top_
6
7* link:https://github.com/CarlKCarlK/clock[Embassy Clock: Layered, modular bare-metal clock with emulation]
8** A `no_std` Raspberry Pi Pico clock demonstrating layered Embassy tasks (Display->Blinker->Clock) for clean separation of multiplexing, blinking, and UI logic. Features single-button HH:MM/MM:SS time-set UI, heapless data structures, and a Renode emulator for hardware-free testing. See link:https://medium.com/@carlmkadie/how-rust-embassy-shine-on-embedded-devices-part-2-aad1adfccf72[this article] for details.
5* link:https://github.com/1-rafael-1/simple-robot[A simple tracked robot based on Raspberry Pi Pico 2] 9* link:https://github.com/1-rafael-1/simple-robot[A simple tracked robot based on Raspberry Pi Pico 2]
6** A hobbyist project building a tracked robot with basic autonomous and manual drive mode. 10** A hobbyist project building a tracked robot with basic autonomous and manual drive mode.
7* link:https://github.com/1-rafael-1/pi-pico-alarmclock-rust[A Raspberry Pi Pico W Alarmclock] 11* link:https://github.com/1-rafael-1/pi-pico-alarmclock-rust[A Raspberry Pi Pico W Alarmclock]
diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md
index dd462608b..6f079a11a 100644
--- a/embassy-executor/CHANGELOG.md
+++ b/embassy-executor/CHANGELOG.md
@@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
11- Added new metadata API for tasks. 11- Added new metadata API for tasks.
12- Main task automatically gets a name of `main` when the `metadata-name` feature is enabled. 12- Main task automatically gets a name of `main` when the `metadata-name` feature is enabled.
13- Upgraded rtos-trace 13- Upgraded rtos-trace
14- Added optional "highest priority" scheduling
15- Added optional "earliest deadline first" EDF scheduling
14 16
15## 0.9.1 - 2025-08-31 17## 0.9.1 - 2025-08-31
16 18
diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml
index 7763adbe5..f6dce5c0e 100644
--- a/embassy-executor/Cargo.toml
+++ b/embassy-executor/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2name = "embassy-executor" 2name = "embassy-executor"
3version = "0.9.0" 3version = "0.9.1"
4edition = "2021" 4edition = "2021"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6description = "async/await executor designed for embedded usage" 6description = "async/await executor designed for embedded usage"
@@ -24,18 +24,49 @@ build = [
24 {target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-thread"]}, 24 {target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-thread"]},
25 {target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt"]}, 25 {target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt"]},
26 {target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread"]}, 26 {target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread"]},
27 {target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "embassy-time-driver"]},
28 {target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "embassy-time-driver", "scheduler-priority"]},
29 {target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "embassy-time-driver", "scheduler-priority", "scheduler-deadline"]},
30 {target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "embassy-time-driver", "scheduler-deadline"]},
31 {target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "scheduler-priority", "scheduler-deadline"]},
32 {target = "thumbv7em-none-eabi", features = ["arch-cortex-m", "executor-interrupt", "executor-thread", "scheduler-deadline"]},
27 {target = "armv7a-none-eabi", features = ["arch-cortex-ar", "executor-thread"]}, 33 {target = "armv7a-none-eabi", features = ["arch-cortex-ar", "executor-thread"]},
28 {target = "armv7r-none-eabi", features = ["arch-cortex-ar", "executor-thread"]}, 34 {target = "armv7r-none-eabi", features = ["arch-cortex-ar", "executor-thread"]},
29 {target = "armv7r-none-eabihf", features = ["arch-cortex-ar", "executor-thread"]}, 35 {target = "armv7r-none-eabihf", features = ["arch-cortex-ar", "executor-thread"]},
30 {target = "riscv32imac-unknown-none-elf", features = ["arch-riscv32"]}, 36 {target = "riscv32imac-unknown-none-elf", features = ["arch-riscv32"]},
31 {target = "riscv32imac-unknown-none-elf", features = ["arch-riscv32", "executor-thread"]}, 37 {target = "riscv32imac-unknown-none-elf", features = ["arch-riscv32", "executor-thread"]},
38 # Nightly builds
39 {group = "nightly", target = "thumbv7em-none-eabi", features = ["nightly"]},
40 {group = "nightly", target = "thumbv7em-none-eabi", features = ["nightly", "log"]},
41 {group = "nightly", target = "thumbv7em-none-eabi", features = ["nightly", "defmt"]},
42 {group = "nightly", target = "thumbv6m-none-eabi", features = ["nightly", "defmt"]},
43 {group = "nightly", target = "thumbv6m-none-eabi", features = ["nightly", "defmt", "arch-cortex-m", "executor-thread", "executor-interrupt"]},
44 {group = "nightly", target = "thumbv7em-none-eabi", features = ["nightly", "arch-cortex-m"]},
45 {group = "nightly", target = "thumbv7em-none-eabi", features = ["nightly", "arch-cortex-m", "executor-thread"]},
46 {group = "nightly", target = "thumbv7em-none-eabi", features = ["nightly", "arch-cortex-m", "executor-interrupt"]},
47 {group = "nightly", target = "thumbv7em-none-eabi", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt"]},
48 {group = "nightly", target = "riscv32imac-unknown-none-elf", features = ["nightly", "arch-riscv32"]},
49 {group = "nightly", target = "riscv32imac-unknown-none-elf", features = ["nightly", "arch-riscv32", "executor-thread"]},
50 {group = "nightly", target = "armv7a-none-eabi", features = ["nightly", "arch-cortex-ar", "executor-thread"]},
51 {group = "nightly", target = "avr-none", features = ["nightly", "arch-avr", "avr-device/atmega328p"], build-std = ["core", "alloc"], env = { RUSTFLAGS = "-Ctarget-cpu=atmega328p" }},
52 # Xtensa builds
53 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = []},
54 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["log"]},
55 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt"]},
56 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32s2-none-elf", features = ["defmt"]},
57 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "arch-spin", "executor-thread"]},
58 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32s2-none-elf", features = ["defmt", "arch-spin", "executor-thread"]},
59 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32s3-none-elf", features = ["defmt", "arch-spin", "executor-thread"]},
60 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["arch-spin"]},
61 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["arch-spin", "rtos-trace"]},
62 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["arch-spin", "executor-thread"]},
32] 63]
33 64
34 65
35[package.metadata.embassy_docs] 66[package.metadata.embassy_docs]
36src_base = "https://github.com/embassy-rs/embassy/blob/embassy-executor-v$VERSION/embassy-executor/src/" 67src_base = "https://github.com/embassy-rs/embassy/blob/embassy-executor-v$VERSION/embassy-executor/src/"
37src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-executor/src/" 68src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-executor/src/"
38features = ["defmt"] 69features = ["defmt", "scheduler-deadline", "scheduler-priority"]
39flavors = [ 70flavors = [
40 { name = "std", target = "x86_64-unknown-linux-gnu", features = ["arch-std", "executor-thread"] }, 71 { name = "std", target = "x86_64-unknown-linux-gnu", features = ["arch-std", "executor-thread"] },
41 { name = "wasm", target = "wasm32-unknown-unknown", features = ["arch-wasm", "executor-thread"] }, 72 { name = "wasm", target = "wasm32-unknown-unknown", features = ["arch-wasm", "executor-thread"] },
@@ -46,7 +77,7 @@ flavors = [
46[package.metadata.docs.rs] 77[package.metadata.docs.rs]
47default-target = "thumbv7em-none-eabi" 78default-target = "thumbv7em-none-eabi"
48targets = ["thumbv7em-none-eabi"] 79targets = ["thumbv7em-none-eabi"]
49features = ["defmt", "arch-cortex-m", "executor-thread", "executor-interrupt"] 80features = ["defmt", "arch-cortex-m", "executor-thread", "executor-interrupt", "scheduler-deadline", "scheduler-priority", "embassy-time-driver"]
50 81
51[dependencies] 82[dependencies]
52defmt = { version = "1.0.1", optional = true } 83defmt = { version = "1.0.1", optional = true }
@@ -76,6 +107,11 @@ js-sys = { version = "0.3", optional = true }
76# arch-avr dependencies 107# arch-avr dependencies
77avr-device = { version = "0.7.0", optional = true } 108avr-device = { version = "0.7.0", optional = true }
78 109
110
111[dependencies.cordyceps]
112version = "0.3.4"
113features = ["no-cache-pad"]
114
79[dev-dependencies] 115[dev-dependencies]
80critical-section = { version = "1.1", features = ["std"] } 116critical-section = { version = "1.1", features = ["std"] }
81trybuild = "1.0" 117trybuild = "1.0"
@@ -123,5 +159,16 @@ executor-interrupt = []
123## Enable tracing hooks 159## Enable tracing hooks
124trace = ["_any_trace"] 160trace = ["_any_trace"]
125## Enable support for rtos-trace framework 161## Enable support for rtos-trace framework
126rtos-trace = ["_any_trace", "metadata-name", "dep:rtos-trace", "dep:embassy-time-driver"] 162rtos-trace = ["_any_trace", "metadata-name", "dep:rtos-trace", "embassy-time-driver"]
127_any_trace = [] 163_any_trace = []
164
165## Enable "Earliest Deadline First" Scheduler, using soft-realtime "deadlines" to prioritize
166## tasks based on the remaining time before their deadline. Adds some overhead.
167scheduler-deadline = []
168
169## Enable "Highest Priority First" Scheduler. Adds some overhead.
170scheduler-priority = []
171
172## Enable the embassy_time_driver dependency.
173## This can unlock extra APIs, for example for the `sheduler-deadline`
174embassy-time-driver = ["dep:embassy-time-driver"]
diff --git a/embassy-executor/src/metadata.rs b/embassy-executor/src/metadata.rs
index f92c9b37c..bc0df0f83 100644
--- a/embassy-executor/src/metadata.rs
+++ b/embassy-executor/src/metadata.rs
@@ -1,17 +1,25 @@
1#[cfg(feature = "metadata-name")] 1#[cfg(feature = "metadata-name")]
2use core::cell::Cell; 2use core::cell::Cell;
3use core::future::{poll_fn, Future}; 3use core::future::{poll_fn, Future};
4#[cfg(feature = "scheduler-priority")]
5use core::sync::atomic::{AtomicU8, Ordering};
4use core::task::Poll; 6use core::task::Poll;
5 7
6#[cfg(feature = "metadata-name")] 8#[cfg(feature = "metadata-name")]
7use critical_section::Mutex; 9use critical_section::Mutex;
8 10
9use crate::raw; 11use crate::raw;
12#[cfg(feature = "scheduler-deadline")]
13use crate::raw::Deadline;
10 14
11/// Metadata associated with a task. 15/// Metadata associated with a task.
12pub struct Metadata { 16pub struct Metadata {
13 #[cfg(feature = "metadata-name")] 17 #[cfg(feature = "metadata-name")]
14 name: Mutex<Cell<Option<&'static str>>>, 18 name: Mutex<Cell<Option<&'static str>>>,
19 #[cfg(feature = "scheduler-priority")]
20 priority: AtomicU8,
21 #[cfg(feature = "scheduler-deadline")]
22 deadline: raw::Deadline,
15} 23}
16 24
17impl Metadata { 25impl Metadata {
@@ -19,12 +27,26 @@ impl Metadata {
19 Self { 27 Self {
20 #[cfg(feature = "metadata-name")] 28 #[cfg(feature = "metadata-name")]
21 name: Mutex::new(Cell::new(None)), 29 name: Mutex::new(Cell::new(None)),
30 #[cfg(feature = "scheduler-priority")]
31 priority: AtomicU8::new(0),
32 // NOTE: The deadline is set to zero to allow the initializer to reside in `.bss`. This
33 // will be lazily initalized in `initialize_impl`
34 #[cfg(feature = "scheduler-deadline")]
35 deadline: raw::Deadline::new_unset(),
22 } 36 }
23 } 37 }
24 38
25 pub(crate) fn reset(&self) { 39 pub(crate) fn reset(&self) {
26 #[cfg(feature = "metadata-name")] 40 #[cfg(feature = "metadata-name")]
27 critical_section::with(|cs| self.name.borrow(cs).set(None)); 41 critical_section::with(|cs| self.name.borrow(cs).set(None));
42
43 #[cfg(feature = "scheduler-priority")]
44 self.set_priority(0);
45
46 // By default, deadlines are set to the maximum value, so that any task WITH
47 // a set deadline will ALWAYS be scheduled BEFORE a task WITHOUT a set deadline
48 #[cfg(feature = "scheduler-deadline")]
49 self.unset_deadline();
28 } 50 }
29 51
30 /// Get the metadata for the current task. 52 /// Get the metadata for the current task.
@@ -52,4 +74,75 @@ impl Metadata {
52 pub fn set_name(&self, name: &'static str) { 74 pub fn set_name(&self, name: &'static str) {
53 critical_section::with(|cs| self.name.borrow(cs).set(Some(name))) 75 critical_section::with(|cs| self.name.borrow(cs).set(Some(name)))
54 } 76 }
77
78 /// Get this task's priority.
79 #[cfg(feature = "scheduler-priority")]
80 pub fn priority(&self) -> u8 {
81 self.priority.load(Ordering::Relaxed)
82 }
83
84 /// Set this task's priority.
85 #[cfg(feature = "scheduler-priority")]
86 pub fn set_priority(&self, priority: u8) {
87 self.priority.store(priority, Ordering::Relaxed)
88 }
89
90 /// Get this task's deadline.
91 #[cfg(feature = "scheduler-deadline")]
92 pub fn deadline(&self) -> u64 {
93 self.deadline.instant_ticks()
94 }
95
96 /// Set this task's deadline.
97 ///
98 /// This method does NOT check whether the deadline has already passed.
99 #[cfg(feature = "scheduler-deadline")]
100 pub fn set_deadline(&self, instant_ticks: u64) {
101 self.deadline.set(instant_ticks);
102 }
103
104 /// Remove this task's deadline.
105 /// This brings it back to the defaul where it's not scheduled ahead of other tasks.
106 #[cfg(feature = "scheduler-deadline")]
107 pub fn unset_deadline(&self) {
108 self.deadline.set(Deadline::UNSET_TICKS);
109 }
110
111 /// Set this task's deadline `duration_ticks` in the future from when
112 /// this future is polled. This deadline is saturated to the max tick value.
113 ///
114 /// Analogous to `Timer::after`.
115 #[cfg(all(feature = "scheduler-deadline", feature = "embassy-time-driver"))]
116 pub fn set_deadline_after(&self, duration_ticks: u64) {
117 let now = embassy_time_driver::now();
118
119 // Since ticks is a u64, saturating add is PROBABLY overly cautious, leave
120 // it for now, we can probably make this wrapping_add for performance
121 // reasons later.
122 let deadline = now.saturating_add(duration_ticks);
123
124 self.set_deadline(deadline);
125 }
126
127 /// Set the this task's deadline `increment_ticks` from the previous deadline.
128 ///
129 /// This deadline is saturated to the max tick value.
130 ///
131 /// Note that by default (unless otherwise set), tasks start life with the deadline
132 /// not set, which means this method will have no effect.
133 ///
134 /// Analogous to one increment of `Ticker::every().next()`.
135 ///
136 /// Returns the deadline that was set.
137 #[cfg(feature = "scheduler-deadline")]
138 pub fn increment_deadline(&self, duration_ticks: u64) {
139 let last = self.deadline();
140
141 // Since ticks is a u64, saturating add is PROBABLY overly cautious, leave
142 // it for now, we can probably make this wrapping_add for performance
143 // reasons later.
144 let deadline = last.saturating_add(duration_ticks);
145
146 self.set_deadline(deadline);
147 }
55} 148}
diff --git a/embassy-executor/src/raw/deadline.rs b/embassy-executor/src/raw/deadline.rs
new file mode 100644
index 000000000..cc89fadb0
--- /dev/null
+++ b/embassy-executor/src/raw/deadline.rs
@@ -0,0 +1,44 @@
1use core::sync::atomic::{AtomicU32, Ordering};
2
3/// A type for interacting with the deadline of the current task
4///
5/// Requires the `scheduler-deadline` feature.
6///
7/// Note: Interacting with the deadline should be done locally in a task.
8/// In theory you could try to set or read the deadline from another task,
9/// but that will result in weird (though not unsound) behavior.
10pub(crate) struct Deadline {
11 instant_ticks_hi: AtomicU32,
12 instant_ticks_lo: AtomicU32,
13}
14
15impl Deadline {
16 pub(crate) const fn new(instant_ticks: u64) -> Self {
17 Self {
18 instant_ticks_hi: AtomicU32::new((instant_ticks >> 32) as u32),
19 instant_ticks_lo: AtomicU32::new(instant_ticks as u32),
20 }
21 }
22
23 pub(crate) const fn new_unset() -> Self {
24 Self::new(Self::UNSET_TICKS)
25 }
26
27 pub(crate) fn set(&self, instant_ticks: u64) {
28 self.instant_ticks_hi
29 .store((instant_ticks >> 32) as u32, Ordering::Relaxed);
30 self.instant_ticks_lo.store(instant_ticks as u32, Ordering::Relaxed);
31 }
32
33 /// Deadline value in ticks, same time base and ticks as `embassy-time`
34 pub(crate) fn instant_ticks(&self) -> u64 {
35 let hi = self.instant_ticks_hi.load(Ordering::Relaxed) as u64;
36 let lo = self.instant_ticks_lo.load(Ordering::Relaxed) as u64;
37
38 (hi << 32) | lo
39 }
40
41 /// Sentinel value representing an "unset" deadline, which has lower priority
42 /// than any other set deadline value
43 pub(crate) const UNSET_TICKS: u64 = u64::MAX;
44}
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index 4280c5750..9f36c60bc 100644
--- a/embassy-executor/src/raw/mod.rs
+++ b/embassy-executor/src/raw/mod.rs
@@ -7,8 +7,6 @@
7//! Using this module requires respecting subtle safety contracts. If you can, prefer using the safe 7//! Using this module requires respecting subtle safety contracts. If you can, prefer using the safe
8//! [executor wrappers](crate::Executor) and the [`embassy_executor::task`](embassy_executor_macros::task) macro, which are fully safe. 8//! [executor wrappers](crate::Executor) and the [`embassy_executor::task`](embassy_executor_macros::task) macro, which are fully safe.
9 9
10#[cfg_attr(target_has_atomic = "ptr", path = "run_queue_atomics.rs")]
11#[cfg_attr(not(target_has_atomic = "ptr"), path = "run_queue_critical_section.rs")]
12mod run_queue; 10mod run_queue;
13 11
14#[cfg_attr(all(cortex_m, target_has_atomic = "32"), path = "state_atomics_arm.rs")] 12#[cfg_attr(all(cortex_m, target_has_atomic = "32"), path = "state_atomics_arm.rs")]
@@ -28,6 +26,9 @@ pub(crate) mod util;
28#[cfg_attr(feature = "turbowakers", path = "waker_turbo.rs")] 26#[cfg_attr(feature = "turbowakers", path = "waker_turbo.rs")]
29mod waker; 27mod waker;
30 28
29#[cfg(feature = "scheduler-deadline")]
30mod deadline;
31
31use core::future::Future; 32use core::future::Future;
32use core::marker::PhantomData; 33use core::marker::PhantomData;
33use core::mem; 34use core::mem;
@@ -38,6 +39,8 @@ use core::sync::atomic::AtomicPtr;
38use core::sync::atomic::Ordering; 39use core::sync::atomic::Ordering;
39use core::task::{Context, Poll, Waker}; 40use core::task::{Context, Poll, Waker};
40 41
42#[cfg(feature = "scheduler-deadline")]
43pub(crate) use deadline::Deadline;
41use embassy_executor_timer_queue::TimerQueueItem; 44use embassy_executor_timer_queue::TimerQueueItem;
42#[cfg(feature = "arch-avr")] 45#[cfg(feature = "arch-avr")]
43use portable_atomic::AtomicPtr; 46use portable_atomic::AtomicPtr;
@@ -96,6 +99,7 @@ extern "Rust" fn __embassy_time_queue_item_from_waker(waker: &Waker) -> &'static
96pub(crate) struct TaskHeader { 99pub(crate) struct TaskHeader {
97 pub(crate) state: State, 100 pub(crate) state: State,
98 pub(crate) run_queue_item: RunQueueItem, 101 pub(crate) run_queue_item: RunQueueItem,
102
99 pub(crate) executor: AtomicPtr<SyncExecutor>, 103 pub(crate) executor: AtomicPtr<SyncExecutor>,
100 poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>, 104 poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>,
101 105
diff --git a/embassy-executor/src/raw/run_queue.rs b/embassy-executor/src/raw/run_queue.rs
new file mode 100644
index 000000000..b8b052310
--- /dev/null
+++ b/embassy-executor/src/raw/run_queue.rs
@@ -0,0 +1,213 @@
1use core::ptr::{addr_of_mut, NonNull};
2
3use cordyceps::sorted_list::Links;
4use cordyceps::Linked;
5#[cfg(any(feature = "scheduler-priority", feature = "scheduler-deadline"))]
6use cordyceps::SortedList;
7
8#[cfg(target_has_atomic = "ptr")]
9type TransferStack<T> = cordyceps::TransferStack<T>;
10
11#[cfg(not(target_has_atomic = "ptr"))]
12type TransferStack<T> = MutexTransferStack<T>;
13
14use super::{TaskHeader, TaskRef};
15
16/// Use `cordyceps::sorted_list::Links` as the singly linked list
17/// for RunQueueItems.
18pub(crate) type RunQueueItem = Links<TaskHeader>;
19
20/// Implements the `Linked` trait, allowing for singly linked list usage
21/// of any of cordyceps' `TransferStack` (used for the atomic runqueue),
22/// `SortedList` (used with the DRS scheduler), or `Stack`, which is
23/// popped atomically from the `TransferStack`.
24unsafe impl Linked<Links<TaskHeader>> for TaskHeader {
25 type Handle = TaskRef;
26
27 // Convert a TaskRef into a TaskHeader ptr
28 fn into_ptr(r: TaskRef) -> NonNull<TaskHeader> {
29 r.ptr
30 }
31
32 // Convert a TaskHeader into a TaskRef
33 unsafe fn from_ptr(ptr: NonNull<TaskHeader>) -> TaskRef {
34 TaskRef { ptr }
35 }
36
37 // Given a pointer to a TaskHeader, obtain a pointer to the Links structure,
38 // which can be used to traverse to other TaskHeader nodes in the linked list
39 unsafe fn links(ptr: NonNull<TaskHeader>) -> NonNull<Links<TaskHeader>> {
40 let ptr: *mut TaskHeader = ptr.as_ptr();
41 NonNull::new_unchecked(addr_of_mut!((*ptr).run_queue_item))
42 }
43}
44
45/// Atomic task queue using a very, very simple lock-free linked-list queue:
46///
47/// To enqueue a task, task.next is set to the old head, and head is atomically set to task.
48///
49/// Dequeuing is done in batches: the queue is emptied by atomically replacing head with
50/// null. Then the batch is iterated following the next pointers until null is reached.
51///
52/// Note that batches will be iterated in the reverse order as they were enqueued. This is OK
53/// for our purposes: it can't create fairness problems since the next batch won't run until the
54/// current batch is completely processed, so even if a task enqueues itself instantly (for example
55/// by waking its own waker) can't prevent other tasks from running.
56pub(crate) struct RunQueue {
57 stack: TransferStack<TaskHeader>,
58}
59
60impl RunQueue {
61 pub const fn new() -> Self {
62 Self {
63 stack: TransferStack::new(),
64 }
65 }
66
67 /// Enqueues an item. Returns true if the queue was empty.
68 ///
69 /// # Safety
70 ///
71 /// `item` must NOT be already enqueued in any queue.
72 #[inline(always)]
73 pub(crate) unsafe fn enqueue(&self, task: TaskRef, _tok: super::state::Token) -> bool {
74 self.stack.push_was_empty(
75 task,
76 #[cfg(not(target_has_atomic = "ptr"))]
77 _tok,
78 )
79 }
80
81 /// # Standard atomic runqueue
82 ///
83 /// Empty the queue, then call `on_task` for each task that was in the queue.
84 /// NOTE: It is OK for `on_task` to enqueue more tasks. In this case they're left in the queue
85 /// and will be processed by the *next* call to `dequeue_all`, *not* the current one.
86 #[cfg(not(any(feature = "scheduler-priority", feature = "scheduler-deadline")))]
87 pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) {
88 let taken = self.stack.take_all();
89 for taskref in taken {
90 run_dequeue(&taskref);
91 on_task(taskref);
92 }
93 }
94
95 /// # Earliest Deadline First Scheduler
96 ///
97 /// This algorithm will loop until all enqueued tasks are processed.
98 ///
99 /// Before polling a task, all currently enqueued tasks will be popped from the
100 /// runqueue, and will be added to the working `sorted` list, a linked-list that
101 /// sorts tasks by their deadline, with nearest deadline items in the front, and
102 /// furthest deadline items in the back.
103 ///
104 /// After popping and sorting all pending tasks, the SOONEST task will be popped
105 /// from the front of the queue, and polled by calling `on_task` on it.
106 ///
107 /// This process will repeat until the local `sorted` queue AND the global
108 /// runqueue are both empty, at which point this function will return.
109 #[cfg(any(feature = "scheduler-priority", feature = "scheduler-deadline"))]
110 pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) {
111 let mut sorted = SortedList::<TaskHeader>::new_with_cmp(|lhs, rhs| {
112 // compare by priority first
113 #[cfg(feature = "scheduler-priority")]
114 {
115 let lp = lhs.metadata.priority();
116 let rp = rhs.metadata.priority();
117 if lp != rp {
118 return lp.cmp(&rp).reverse();
119 }
120 }
121 // compare deadlines in case of tie.
122 #[cfg(feature = "scheduler-deadline")]
123 {
124 let ld = lhs.metadata.deadline();
125 let rd = rhs.metadata.deadline();
126 if ld != rd {
127 return ld.cmp(&rd);
128 }
129 }
130 core::cmp::Ordering::Equal
131 });
132
133 loop {
134 // For each loop, grab any newly pended items
135 let taken = self.stack.take_all();
136
137 // Sort these into the list - this is potentially expensive! We do an
138 // insertion sort of new items, which iterates the linked list.
139 //
140 // Something on the order of `O(n * m)`, where `n` is the number
141 // of new tasks, and `m` is the number of already pending tasks.
142 sorted.extend(taken);
143
144 // Pop the task with the SOONEST deadline. If there are no tasks
145 // pending, then we are done.
146 let Some(taskref) = sorted.pop_front() else {
147 return;
148 };
149
150 // We got one task, mark it as dequeued, and process the task.
151 run_dequeue(&taskref);
152 on_task(taskref);
153 }
154 }
155}
156
157/// atomic state does not require a cs...
158#[cfg(target_has_atomic = "ptr")]
159#[inline(always)]
160fn run_dequeue(taskref: &TaskRef) {
161 taskref.header().state.run_dequeue();
162}
163
164/// ...while non-atomic state does
165#[cfg(not(target_has_atomic = "ptr"))]
166#[inline(always)]
167fn run_dequeue(taskref: &TaskRef) {
168 critical_section::with(|cs| {
169 taskref.header().state.run_dequeue(cs);
170 })
171}
172
173/// A wrapper type that acts like TransferStack by wrapping a normal Stack in a CS mutex
174#[cfg(not(target_has_atomic = "ptr"))]
175struct MutexTransferStack<T: Linked<cordyceps::stack::Links<T>>> {
176 inner: critical_section::Mutex<core::cell::UnsafeCell<cordyceps::Stack<T>>>,
177}
178
179#[cfg(not(target_has_atomic = "ptr"))]
180impl<T: Linked<cordyceps::stack::Links<T>>> MutexTransferStack<T> {
181 const fn new() -> Self {
182 Self {
183 inner: critical_section::Mutex::new(core::cell::UnsafeCell::new(cordyceps::Stack::new())),
184 }
185 }
186
187 /// Push an item to the transfer stack, returning whether the stack was previously empty
188 fn push_was_empty(&self, item: T::Handle, token: super::state::Token) -> bool {
189 // SAFETY: The critical-section mutex guarantees that there is no *concurrent* access
190 // for the lifetime of the token, but does NOT protect against re-entrant access.
191 // However, we never *return* the reference, nor do we recurse (or call another method
192 // like `take_all`) that could ever allow for re-entrant aliasing. Therefore, the
193 // presence of the critical section is sufficient to guarantee exclusive access to
194 // the `inner` field for the purposes of this function.
195 let inner = unsafe { &mut *self.inner.borrow(token).get() };
196 let is_empty = inner.is_empty();
197 inner.push(item);
198 is_empty
199 }
200
201 fn take_all(&self) -> cordyceps::Stack<T> {
202 critical_section::with(|cs| {
203 // SAFETY: The critical-section mutex guarantees that there is no *concurrent* access
204 // for the lifetime of the token, but does NOT protect against re-entrant access.
205 // However, we never *return* the reference, nor do we recurse (or call another method
206 // like `push_was_empty`) that could ever allow for re-entrant aliasing. Therefore, the
207 // presence of the critical section is sufficient to guarantee exclusive access to
208 // the `inner` field for the purposes of this function.
209 let inner = unsafe { &mut *self.inner.borrow(cs).get() };
210 inner.take_all()
211 })
212 }
213}
diff --git a/embassy-executor/src/raw/run_queue_atomics.rs b/embassy-executor/src/raw/run_queue_atomics.rs
deleted file mode 100644
index ce511d79a..000000000
--- a/embassy-executor/src/raw/run_queue_atomics.rs
+++ /dev/null
@@ -1,88 +0,0 @@
1use core::ptr;
2use core::ptr::NonNull;
3use core::sync::atomic::{AtomicPtr, Ordering};
4
5use super::{TaskHeader, TaskRef};
6use crate::raw::util::SyncUnsafeCell;
7
8pub(crate) struct RunQueueItem {
9 next: SyncUnsafeCell<Option<TaskRef>>,
10}
11
12impl RunQueueItem {
13 pub const fn new() -> Self {
14 Self {
15 next: SyncUnsafeCell::new(None),
16 }
17 }
18}
19
20/// Atomic task queue using a very, very simple lock-free linked-list queue:
21///
22/// To enqueue a task, task.next is set to the old head, and head is atomically set to task.
23///
24/// Dequeuing is done in batches: the queue is emptied by atomically replacing head with
25/// null. Then the batch is iterated following the next pointers until null is reached.
26///
27/// Note that batches will be iterated in the reverse order as they were enqueued. This is OK
28/// for our purposes: it can't create fairness problems since the next batch won't run until the
29/// current batch is completely processed, so even if a task enqueues itself instantly (for example
30/// by waking its own waker) can't prevent other tasks from running.
31pub(crate) struct RunQueue {
32 head: AtomicPtr<TaskHeader>,
33}
34
35impl RunQueue {
36 pub const fn new() -> Self {
37 Self {
38 head: AtomicPtr::new(ptr::null_mut()),
39 }
40 }
41
42 /// Enqueues an item. Returns true if the queue was empty.
43 ///
44 /// # Safety
45 ///
46 /// `item` must NOT be already enqueued in any queue.
47 #[inline(always)]
48 pub(crate) unsafe fn enqueue(&self, task: TaskRef, _: super::state::Token) -> bool {
49 let mut was_empty = false;
50
51 self.head
52 .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |prev| {
53 was_empty = prev.is_null();
54 unsafe {
55 // safety: the pointer is either null or valid
56 let prev = NonNull::new(prev).map(|ptr| TaskRef::from_ptr(ptr.as_ptr()));
57 // safety: there are no concurrent accesses to `next`
58 task.header().run_queue_item.next.set(prev);
59 }
60 Some(task.as_ptr() as *mut _)
61 })
62 .ok();
63
64 was_empty
65 }
66
67 /// Empty the queue, then call `on_task` for each task that was in the queue.
68 /// NOTE: It is OK for `on_task` to enqueue more tasks. In this case they're left in the queue
69 /// and will be processed by the *next* call to `dequeue_all`, *not* the current one.
70 pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) {
71 // Atomically empty the queue.
72 let ptr = self.head.swap(ptr::null_mut(), Ordering::AcqRel);
73
74 // safety: the pointer is either null or valid
75 let mut next = unsafe { NonNull::new(ptr).map(|ptr| TaskRef::from_ptr(ptr.as_ptr())) };
76
77 // Iterate the linked list of tasks that were previously in the queue.
78 while let Some(task) = next {
79 // If the task re-enqueues itself, the `next` pointer will get overwritten.
80 // Therefore, first read the next pointer, and only then process the task.
81 // safety: there are no concurrent accesses to `next`
82 next = unsafe { task.header().run_queue_item.next.get() };
83
84 task.header().state.run_dequeue();
85 on_task(task);
86 }
87 }
88}
diff --git a/embassy-executor/src/raw/run_queue_critical_section.rs b/embassy-executor/src/raw/run_queue_critical_section.rs
deleted file mode 100644
index 86c4085ed..000000000
--- a/embassy-executor/src/raw/run_queue_critical_section.rs
+++ /dev/null
@@ -1,74 +0,0 @@
1use core::cell::Cell;
2
3use critical_section::{CriticalSection, Mutex};
4
5use super::TaskRef;
6
7pub(crate) struct RunQueueItem {
8 next: Mutex<Cell<Option<TaskRef>>>,
9}
10
11impl RunQueueItem {
12 pub const fn new() -> Self {
13 Self {
14 next: Mutex::new(Cell::new(None)),
15 }
16 }
17}
18
19/// Atomic task queue using a very, very simple lock-free linked-list queue:
20///
21/// To enqueue a task, task.next is set to the old head, and head is atomically set to task.
22///
23/// Dequeuing is done in batches: the queue is emptied by atomically replacing head with
24/// null. Then the batch is iterated following the next pointers until null is reached.
25///
26/// Note that batches will be iterated in the reverse order as they were enqueued. This is OK
27/// for our purposes: it can't create fairness problems since the next batch won't run until the
28/// current batch is completely processed, so even if a task enqueues itself instantly (for example
29/// by waking its own waker) can't prevent other tasks from running.
30pub(crate) struct RunQueue {
31 head: Mutex<Cell<Option<TaskRef>>>,
32}
33
34impl RunQueue {
35 pub const fn new() -> Self {
36 Self {
37 head: Mutex::new(Cell::new(None)),
38 }
39 }
40
41 /// Enqueues an item. Returns true if the queue was empty.
42 ///
43 /// # Safety
44 ///
45 /// `item` must NOT be already enqueued in any queue.
46 #[inline(always)]
47 pub(crate) unsafe fn enqueue(&self, task: TaskRef, cs: CriticalSection<'_>) -> bool {
48 let prev = self.head.borrow(cs).replace(Some(task));
49 task.header().run_queue_item.next.borrow(cs).set(prev);
50
51 prev.is_none()
52 }
53
54 /// Empty the queue, then call `on_task` for each task that was in the queue.
55 /// NOTE: It is OK for `on_task` to enqueue more tasks. In this case they're left in the queue
56 /// and will be processed by the *next* call to `dequeue_all`, *not* the current one.
57 pub(crate) fn dequeue_all(&self, on_task: impl Fn(TaskRef)) {
58 // Atomically empty the queue.
59 let mut next = critical_section::with(|cs| self.head.borrow(cs).take());
60
61 // Iterate the linked list of tasks that were previously in the queue.
62 while let Some(task) = next {
63 // If the task re-enqueues itself, the `next` pointer will get overwritten.
64 // Therefore, first read the next pointer, and only then process the task.
65
66 critical_section::with(|cs| {
67 next = task.header().run_queue_item.next.borrow(cs).get();
68 task.header().state.run_dequeue(cs);
69 });
70
71 on_task(task);
72 }
73 }
74}
diff --git a/embassy-net-wiznet/CHANGELOG.md b/embassy-net-wiznet/CHANGELOG.md
index e464efa69..a74dc3125 100644
--- a/embassy-net-wiznet/CHANGELOG.md
+++ b/embassy-net-wiznet/CHANGELOG.md
@@ -8,6 +8,9 @@ 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- Added experimental W6100 driver with disabled MAC filter (does not currently work with it enabled)
12- Introduced `SOCKET_INTR_CLR` register which is needed on W6100 and later models (on W5100/W5500 this is shared with `SOCKET_INTR` and the address is the same)
13
11## 0.2.1 - 2025-08-26 14## 0.2.1 - 2025-08-26
12 15
13## 0.1.1 - 2025-08-14 16## 0.1.1 - 2025-08-14
diff --git a/embassy-net-wiznet/src/chip/mod.rs b/embassy-net-wiznet/src/chip/mod.rs
index 2e7a9ed6c..47d7c5dc3 100644
--- a/embassy-net-wiznet/src/chip/mod.rs
+++ b/embassy-net-wiznet/src/chip/mod.rs
@@ -4,6 +4,8 @@ pub use w5500::W5500;
4mod w5100s; 4mod w5100s;
5use embedded_hal_async::spi::SpiDevice; 5use embedded_hal_async::spi::SpiDevice;
6pub use w5100s::W5100S; 6pub use w5100s::W5100S;
7mod w6100;
8pub use w6100::W6100;
7 9
8pub(crate) trait SealedChip { 10pub(crate) trait SealedChip {
9 type Address; 11 type Address;
@@ -28,7 +30,9 @@ pub(crate) trait SealedChip {
28 const SOCKET_RECVD_SIZE: Self::Address; 30 const SOCKET_RECVD_SIZE: Self::Address;
29 const SOCKET_RX_DATA_READ_PTR: Self::Address; 31 const SOCKET_RX_DATA_READ_PTR: Self::Address;
30 const SOCKET_INTR_MASK: Self::Address; 32 const SOCKET_INTR_MASK: Self::Address;
33 #[allow(dead_code)]
31 const SOCKET_INTR: Self::Address; 34 const SOCKET_INTR: Self::Address;
35 const SOCKET_INTR_CLR: Self::Address;
32 36
33 const SOCKET_MODE_VALUE: u8; 37 const SOCKET_MODE_VALUE: u8;
34 38
diff --git a/embassy-net-wiznet/src/chip/w5100s.rs b/embassy-net-wiznet/src/chip/w5100s.rs
index 4c4b7ab16..1eef2369e 100644
--- a/embassy-net-wiznet/src/chip/w5100s.rs
+++ b/embassy-net-wiznet/src/chip/w5100s.rs
@@ -29,6 +29,7 @@ impl super::SealedChip for W5100S {
29 const SOCKET_RX_DATA_READ_PTR: Self::Address = SOCKET_BASE + 0x28; 29 const SOCKET_RX_DATA_READ_PTR: Self::Address = SOCKET_BASE + 0x28;
30 const SOCKET_INTR_MASK: Self::Address = SOCKET_BASE + 0x2C; 30 const SOCKET_INTR_MASK: Self::Address = SOCKET_BASE + 0x2C;
31 const SOCKET_INTR: Self::Address = SOCKET_BASE + 0x02; 31 const SOCKET_INTR: Self::Address = SOCKET_BASE + 0x02;
32 const SOCKET_INTR_CLR: Self::Address = SOCKET_BASE + 0x02;
32 33
33 const SOCKET_MODE_VALUE: u8 = (1 << 2) | (1 << 6); 34 const SOCKET_MODE_VALUE: u8 = (1 << 2) | (1 << 6);
34 35
diff --git a/embassy-net-wiznet/src/chip/w5500.rs b/embassy-net-wiznet/src/chip/w5500.rs
index 5cfcb94e4..198ba3226 100644
--- a/embassy-net-wiznet/src/chip/w5500.rs
+++ b/embassy-net-wiznet/src/chip/w5500.rs
@@ -33,6 +33,7 @@ impl super::SealedChip for W5500 {
33 const SOCKET_RX_DATA_READ_PTR: Self::Address = (RegisterBlock::Socket0, 0x28); 33 const SOCKET_RX_DATA_READ_PTR: Self::Address = (RegisterBlock::Socket0, 0x28);
34 const SOCKET_INTR_MASK: Self::Address = (RegisterBlock::Socket0, 0x2C); 34 const SOCKET_INTR_MASK: Self::Address = (RegisterBlock::Socket0, 0x2C);
35 const SOCKET_INTR: Self::Address = (RegisterBlock::Socket0, 0x02); 35 const SOCKET_INTR: Self::Address = (RegisterBlock::Socket0, 0x02);
36 const SOCKET_INTR_CLR: Self::Address = (RegisterBlock::Socket0, 0x02);
36 37
37 const SOCKET_MODE_VALUE: u8 = (1 << 2) | (1 << 7); 38 const SOCKET_MODE_VALUE: u8 = (1 << 2) | (1 << 7);
38 39
diff --git a/embassy-net-wiznet/src/chip/w6100.rs b/embassy-net-wiznet/src/chip/w6100.rs
new file mode 100644
index 000000000..740b0edaf
--- /dev/null
+++ b/embassy-net-wiznet/src/chip/w6100.rs
@@ -0,0 +1,83 @@
1use embedded_hal_async::spi::{Operation, SpiDevice};
2
3#[repr(u8)]
4pub enum RegisterBlock {
5 Common = 0x00,
6 Socket0 = 0x01,
7 TxBuf = 0x02,
8 RxBuf = 0x03,
9}
10
11/// Wiznet W6100 chip.
12pub enum W6100 {}
13
14impl super::Chip for W6100 {}
15impl super::SealedChip for W6100 {
16 type Address = (RegisterBlock, u16);
17
18 const CHIP_VERSION: u8 = 0x46;
19
20 const COMMON_MODE: Self::Address = (RegisterBlock::Common, 0x2004);
21 const COMMON_MAC: Self::Address = (RegisterBlock::Common, 0x4120);
22 // SIMR (SOCKET Interrupt Mask Register)
23 const COMMON_SOCKET_INTR: Self::Address = (RegisterBlock::Common, 0x2114);
24 const COMMON_PHY_CFG: Self::Address = (RegisterBlock::Common, 0x3000);
25 const COMMON_VERSION: Self::Address = (RegisterBlock::Common, 0x0002);
26
27 const SOCKET_MODE: Self::Address = (RegisterBlock::Socket0, 0x0000);
28 const SOCKET_COMMAND: Self::Address = (RegisterBlock::Socket0, 0x0010);
29 const SOCKET_RXBUF_SIZE: Self::Address = (RegisterBlock::Socket0, 0x0220);
30 const SOCKET_TXBUF_SIZE: Self::Address = (RegisterBlock::Socket0, 0x0200);
31 const SOCKET_TX_FREE_SIZE: Self::Address = (RegisterBlock::Socket0, 0x0204);
32 const SOCKET_TX_DATA_WRITE_PTR: Self::Address = (RegisterBlock::Socket0, 0x020C);
33 const SOCKET_RECVD_SIZE: Self::Address = (RegisterBlock::Socket0, 0x0224);
34 const SOCKET_RX_DATA_READ_PTR: Self::Address = (RegisterBlock::Socket0, 0x0228);
35 // Sn_IMR (SOCKET n Interrupt Mask Register)
36 const SOCKET_INTR_MASK: Self::Address = (RegisterBlock::Socket0, 0x0024);
37 // Sn_IR (SOCKET n Interrupt Register)
38 const SOCKET_INTR: Self::Address = (RegisterBlock::Socket0, 0x0020);
39 // Sn_IRCLR (Sn_IR Clear Register)
40 const SOCKET_INTR_CLR: Self::Address = (RegisterBlock::Socket0, 0x0028);
41
42 // MACRAW mode. See Page 57 of https://docs.wiznet.io/img/products/w6100/w6100_ds_v105e.pdf
43 // Note: Bit 7 is MAC filter. On the W5500 this is normally turned ON however the W6100 will not successfully retrieve an IP address with this enabled. Disabling for now and will have live with the extra noise.
44 const SOCKET_MODE_VALUE: u8 = 0b0000_0111;
45
46 const BUF_SIZE: u16 = 0x1000;
47 const AUTO_WRAP: bool = true;
48
49 fn rx_addr(addr: u16) -> Self::Address {
50 (RegisterBlock::RxBuf, addr)
51 }
52
53 fn tx_addr(addr: u16) -> Self::Address {
54 (RegisterBlock::TxBuf, addr)
55 }
56
57 async fn bus_read<SPI: SpiDevice>(
58 spi: &mut SPI,
59 address: Self::Address,
60 data: &mut [u8],
61 ) -> Result<(), SPI::Error> {
62 let address_phase = address.1.to_be_bytes();
63 let control_phase = [(address.0 as u8) << 3];
64 let operations = &mut [
65 Operation::Write(&address_phase),
66 Operation::Write(&control_phase),
67 Operation::TransferInPlace(data),
68 ];
69 spi.transaction(operations).await
70 }
71
72 async fn bus_write<SPI: SpiDevice>(spi: &mut SPI, address: Self::Address, data: &[u8]) -> Result<(), SPI::Error> {
73 let address_phase = address.1.to_be_bytes();
74 let control_phase = [(address.0 as u8) << 3 | 0b0000_0100];
75 let data_phase = data;
76 let operations = &mut [
77 Operation::Write(&address_phase[..]),
78 Operation::Write(&control_phase),
79 Operation::Write(&data_phase),
80 ];
81 spi.transaction(operations).await
82 }
83}
diff --git a/embassy-net-wiznet/src/device.rs b/embassy-net-wiznet/src/device.rs
index d2b6bb0c3..8ef92b022 100644
--- a/embassy-net-wiznet/src/device.rs
+++ b/embassy-net-wiznet/src/device.rs
@@ -125,7 +125,7 @@ impl<C: Chip, SPI: SpiDevice> WiznetDevice<C, SPI> {
125 125
126 async fn reset_interrupt(&mut self, code: Interrupt) -> Result<(), SPI::Error> { 126 async fn reset_interrupt(&mut self, code: Interrupt) -> Result<(), SPI::Error> {
127 let data = [code as u8]; 127 let data = [code as u8];
128 self.bus_write(C::SOCKET_INTR, &data).await 128 self.bus_write(C::SOCKET_INTR_CLR, &data).await
129 } 129 }
130 130
131 async fn get_tx_write_ptr(&mut self) -> Result<u16, SPI::Error> { 131 async fn get_tx_write_ptr(&mut self) -> Result<u16, SPI::Error> {
diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml
index 245626c14..61a2c858a 100644
--- a/embassy-net/Cargo.toml
+++ b/embassy-net/Cargo.toml
@@ -26,6 +26,19 @@ build = [
26 {target = "thumbv7em-none-eabi", features = ["defmt", "dns", "medium-ip", "proto-ipv4", "proto-ipv6", "tcp", "udp"]}, 26 {target = "thumbv7em-none-eabi", features = ["defmt", "dns", "medium-ip", "proto-ipv4", "proto-ipv6", "tcp", "udp"]},
27 {target = "thumbv7em-none-eabi", features = ["defmt", "dns", "medium-ethernet", "medium-ip", "proto-ipv4", "proto-ipv6", "tcp", "udp"]}, 27 {target = "thumbv7em-none-eabi", features = ["defmt", "dns", "medium-ethernet", "medium-ip", "proto-ipv4", "proto-ipv6", "tcp", "udp"]},
28 {target = "thumbv7em-none-eabi", features = ["defmt", "dns", "medium-ethernet", "medium-ieee802154", "medium-ip", "proto-ipv4", "proto-ipv6", "tcp", "udp"]}, 28 {target = "thumbv7em-none-eabi", features = ["defmt", "dns", "medium-ethernet", "medium-ieee802154", "medium-ip", "proto-ipv4", "proto-ipv6", "tcp", "udp"]},
29 # Xtensa builds
30 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "tcp", "udp", "dns", "proto-ipv4", "medium-ethernet", "packet-trace"]},
31 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "tcp", "udp", "dns", "proto-ipv4", "multicast", "medium-ethernet"]},
32 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "tcp", "udp", "dns", "dhcpv4", "medium-ethernet"]},
33 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "tcp", "udp", "dns", "dhcpv4", "medium-ethernet", "dhcpv4-hostname"]},
34 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "tcp", "udp", "dns", "proto-ipv6", "medium-ethernet"]},
35 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "tcp", "udp", "dns", "proto-ipv6", "medium-ieee802154"]},
36 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "tcp", "udp", "dns", "proto-ipv6", "medium-ethernet", "medium-ieee802154"]},
37 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "tcp", "udp", "dns", "proto-ipv6", "medium-ethernet"]},
38 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "tcp", "udp", "dns", "proto-ipv4", "proto-ipv6", "medium-ethernet"]},
39 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "tcp", "udp", "dns", "proto-ipv4", "proto-ipv6", "medium-ip"]},
40 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "tcp", "udp", "dns", "proto-ipv4", "proto-ipv6", "medium-ip", "medium-ethernet"]},
41 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32-none-elf", features = ["defmt", "tcp", "udp", "dns", "proto-ipv4", "proto-ipv6", "medium-ip", "medium-ethernet", "medium-ieee802154"]},
29] 42]
30 43
31[package.metadata.embassy_docs] 44[package.metadata.embassy_docs]
diff --git a/embassy-net/README.md b/embassy-net/README.md
index 1722ffc7b..1c5b30a9c 100644
--- a/embassy-net/README.md
+++ b/embassy-net/README.md
@@ -25,6 +25,7 @@ unimplemented features of the network protocols.
25- [`embassy-stm32`](https://github.com/embassy-rs/embassy/tree/main/embassy-stm32) for the builtin Ethernet MAC in all STM32 chips (STM32F1, STM32F2, STM32F4, STM32F7, STM32H7, STM32H5). 25- [`embassy-stm32`](https://github.com/embassy-rs/embassy/tree/main/embassy-stm32) for the builtin Ethernet MAC in all STM32 chips (STM32F1, STM32F2, STM32F4, STM32F7, STM32H7, STM32H5).
26- [`embassy-net-wiznet`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-wiznet) for Wiznet SPI Ethernet MAC+PHY chips (W5100S, W5500) 26- [`embassy-net-wiznet`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-wiznet) for Wiznet SPI Ethernet MAC+PHY chips (W5100S, W5500)
27- [`embassy-net-esp-hosted`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-esp-hosted) for using ESP32 chips with the [`esp-hosted`](https://github.com/espressif/esp-hosted) firmware as WiFi adapters for another non-ESP32 MCU. 27- [`embassy-net-esp-hosted`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-esp-hosted) for using ESP32 chips with the [`esp-hosted`](https://github.com/espressif/esp-hosted) firmware as WiFi adapters for another non-ESP32 MCU.
28- [`embassy-nrf`](https://github.com/embassy-rs/embassy/tree/main/embassy-nrf) for IEEE 802.15.4 support on nrf chips.
28 29
29## Examples 30## Examples
30 31
diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md
index 5dc941b25..befa34ecf 100644
--- a/embassy-nrf/CHANGELOG.md
+++ b/embassy-nrf/CHANGELOG.md
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9## Unreleased - ReleaseDate 9## Unreleased - ReleaseDate
10 10
11- changed: nrf54l: Disable glitch detection and enable DC/DC in init. 11- changed: nrf54l: Disable glitch detection and enable DC/DC in init.
12- changed: Add embassy-net-driver-channel implementation for IEEE 802.15.4
12 13
13## 0.7.0 - 2025-08-26 14## 0.7.0 - 2025-08-26
14 15
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index 2ce75cfac..4afd28fbd 100644
--- a/embassy-nrf/Cargo.toml
+++ b/embassy-nrf/Cargo.toml
@@ -79,6 +79,9 @@ gpiote = []
79## Use RTC1 as the time driver for `embassy-time`, with a tick rate of 32.768khz 79## Use RTC1 as the time driver for `embassy-time`, with a tick rate of 32.768khz
80time-driver-rtc1 = ["_time-driver"] 80time-driver-rtc1 = ["_time-driver"]
81 81
82## Enable embassy-net 802.15.4 driver
83net-driver = ["_net-driver"]
84
82## Allow using the NFC pins as regular GPIO pins (P0_09/P0_10 on nRF52, P0_02/P0_03 on nRF53) 85## Allow using the NFC pins as regular GPIO pins (P0_09/P0_10 on nRF52, P0_02/P0_03 on nRF53)
83nfc-pins-as-gpio = [] 86nfc-pins-as-gpio = []
84 87
@@ -154,6 +157,8 @@ _nrf91 = []
154 157
155_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768", "dep:embassy-time-queue-utils", "embassy-embedded-hal/time"] 158_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768", "dep:embassy-time-queue-utils", "embassy-embedded-hal/time"]
156 159
160_net-driver = ["dep:embassy-net-driver-channel","dep:embassy-futures"]
161
157# trustzone state. 162# trustzone state.
158_s = [] 163_s = []
159_ns = [] 164_ns = []
@@ -177,6 +182,8 @@ embassy-sync = { version = "0.7.2", path = "../embassy-sync" }
177embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } 182embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] }
178embassy-embedded-hal = { version = "0.5.0", path = "../embassy-embedded-hal", default-features = false } 183embassy-embedded-hal = { version = "0.5.0", path = "../embassy-embedded-hal", default-features = false }
179embassy-usb-driver = { version = "0.2.0", path = "../embassy-usb-driver" } 184embassy-usb-driver = { version = "0.2.0", path = "../embassy-usb-driver" }
185embassy-net-driver-channel = { version = "0.3.2", path = "../embassy-net-driver-channel", optional = true}
186embassy-futures = { version = "0.1.2", path = "../embassy-futures", optional = true}
180 187
181embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 188embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
182embedded-hal-1 = { package = "embedded-hal", version = "1.0" } 189embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
diff --git a/embassy-nrf/README.md b/embassy-nrf/README.md
index 3df5f1fa5..26b1fa5ea 100644
--- a/embassy-nrf/README.md
+++ b/embassy-nrf/README.md
@@ -28,6 +28,10 @@ allows running Rust code without a SPM or TF-M binary, saving flash space and si
28 28
29If the `time-driver-rtc1` feature is enabled, the HAL uses the RTC peripheral as a global time driver for [embassy-time](https://crates.io/crates/embassy-time), with a tick rate of 32768 Hz. 29If the `time-driver-rtc1` feature is enabled, the HAL uses the RTC peripheral as a global time driver for [embassy-time](https://crates.io/crates/embassy-time), with a tick rate of 32768 Hz.
30 30
31## Embassy-net-driver
32
33If the board supports IEEE 802.15.4 (see `src/radio/mod.rs`) the corresponding [embassy-net-driver](https://crates.io/crates/embassy-net-driver) implementation can be enabled with the feature `net-driver`.
34
31## Embedded-hal 35## Embedded-hal
32 36
33The `embassy-nrf` HAL implements the traits from [embedded-hal](https://crates.io/crates/embedded-hal) (v0.2 and 1.0) and [embedded-hal-async](https://crates.io/crates/embedded-hal-async), as well as [embedded-io](https://crates.io/crates/embedded-io) and [embedded-io-async](https://crates.io/crates/embedded-io-async). 37The `embassy-nrf` HAL implements the traits from [embedded-hal](https://crates.io/crates/embedded-hal) (v0.2 and 1.0) and [embedded-hal-async](https://crates.io/crates/embedded-hal-async), as well as [embedded-io](https://crates.io/crates/embedded-io) and [embedded-io-async](https://crates.io/crates/embedded-io-async).
diff --git a/embassy-nrf/src/embassy_net_802154_driver.rs b/embassy-nrf/src/embassy_net_802154_driver.rs
new file mode 100644
index 000000000..8662be787
--- /dev/null
+++ b/embassy-nrf/src/embassy_net_802154_driver.rs
@@ -0,0 +1,96 @@
1//! embassy-net IEEE 802.15.4 driver
2
3use embassy_futures::select::{select3, Either3};
4use embassy_net_driver_channel::driver::LinkState;
5use embassy_net_driver_channel::{self as ch};
6use embassy_time::{Duration, Ticker};
7
8use crate::radio::ieee802154::{Packet, Radio};
9use crate::radio::InterruptHandler;
10use crate::{self as nrf, interrupt};
11
12/// MTU for the nrf radio.
13pub const MTU: usize = Packet::CAPACITY as usize;
14
15/// embassy-net device for the driver.
16pub type Device<'d> = embassy_net_driver_channel::Device<'d, MTU>;
17
18/// Internal state for the embassy-net driver.
19pub struct State<const N_RX: usize, const N_TX: usize> {
20 ch_state: ch::State<MTU, N_RX, N_TX>,
21}
22
23impl<const N_RX: usize, const N_TX: usize> State<N_RX, N_TX> {
24 /// Create a new `State`.
25 pub const fn new() -> Self {
26 Self {
27 ch_state: ch::State::new(),
28 }
29 }
30}
31
32/// Background runner for the driver.
33///
34/// You must call `.run()` in a background task for the driver to operate.
35pub struct Runner<'d, T: nrf::radio::Instance> {
36 radio: nrf::radio::ieee802154::Radio<'d, T>,
37 ch: ch::Runner<'d, MTU>,
38}
39
40impl<'d, T: nrf::radio::Instance> Runner<'d, T> {
41 /// Drives the radio. Needs to run to use the driver.
42 pub async fn run(mut self) -> ! {
43 let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split();
44 let mut tick = Ticker::every(Duration::from_millis(500));
45 let mut packet = Packet::new();
46 state_chan.set_link_state(LinkState::Up);
47 loop {
48 match select3(
49 async {
50 let rx_buf = rx_chan.rx_buf().await;
51 self.radio.receive(&mut packet).await.ok().map(|_| rx_buf)
52 },
53 tx_chan.tx_buf(),
54 tick.next(),
55 )
56 .await
57 {
58 Either3::First(Some(rx_buf)) => {
59 let len = rx_buf.len().min(packet.len() as usize);
60 (&mut rx_buf[..len]).copy_from_slice(&*packet);
61 rx_chan.rx_done(len);
62 }
63 Either3::Second(tx_buf) => {
64 let len = tx_buf.len().min(Packet::CAPACITY as usize);
65 packet.copy_from_slice(&tx_buf[..len]);
66 self.radio.try_send(&mut packet).await.ok().unwrap();
67 tx_chan.tx_done();
68 }
69 _ => {}
70 }
71 }
72 }
73}
74
75/// Make sure to use `HfclkSource::ExternalXtal` as the `hfclk_source`
76/// to use the radio (nrf52840 product spec v1.11 5.4.1)
77/// ```
78/// # use embassy_nrf::config::*;
79/// let mut config = Config::default();
80/// config.hfclk_source = HfclkSource::ExternalXtal;
81/// ```
82pub async fn new<'a, const N_RX: usize, const N_TX: usize, T: nrf::radio::Instance, Irq>(
83 mac_addr: [u8; 8],
84 radio: nrf::Peri<'a, T>,
85 irq: Irq,
86 state: &'a mut State<N_RX, N_TX>,
87) -> Result<(Device<'a>, Runner<'a, T>), ()>
88where
89 Irq: interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'a,
90{
91 let radio = Radio::new(radio, irq);
92
93 let (runner, device) = ch::new(&mut state.ch_state, ch::driver::HardwareAddress::Ieee802154(mac_addr));
94
95 Ok((device, Runner { ch: runner, radio }))
96}
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index aa4801897..897e660b8 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -137,6 +137,17 @@ pub mod qspi;
137#[cfg(not(feature = "_nrf54l"))] // TODO 137#[cfg(not(feature = "_nrf54l"))] // TODO
138#[cfg(not(any(feature = "_nrf91", feature = "_nrf5340-app")))] 138#[cfg(not(any(feature = "_nrf91", feature = "_nrf5340-app")))]
139pub mod radio; 139pub mod radio;
140
141#[cfg(any(
142 feature = "nrf52811",
143 feature = "nrf52820",
144 feature = "nrf52833",
145 feature = "nrf52840",
146 feature = "_nrf5340-net"
147))]
148#[cfg(feature = "_net-driver")]
149pub mod embassy_net_802154_driver;
150
140#[cfg(not(feature = "_nrf54l"))] // TODO 151#[cfg(not(feature = "_nrf54l"))] // TODO
141#[cfg(feature = "_nrf5340")] 152#[cfg(feature = "_nrf5340")]
142pub mod reset; 153pub mod reset;
diff --git a/embassy-nxp/CHANGELOG.md b/embassy-nxp/CHANGELOG.md
index 7042ad14c..ab97c4185 100644
--- a/embassy-nxp/CHANGELOG.md
+++ b/embassy-nxp/CHANGELOG.md
@@ -7,5 +7,5 @@ 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 10- Moved NXP LPC55S69 from `lpc55-pac` to `nxp-pac`
11- First release with changelog. 11- First release with changelog.
diff --git a/embassy-nxp/Cargo.toml b/embassy-nxp/Cargo.toml
index ab0bfbfd7..455915f29 100644
--- a/embassy-nxp/Cargo.toml
+++ b/embassy-nxp/Cargo.toml
@@ -7,7 +7,7 @@ publish = false
7 7
8[package.metadata.embassy] 8[package.metadata.embassy]
9build = [ 9build = [
10 {target = "thumbv8m.main-none-eabihf", features = ["defmt", "lpc55"]}, 10 {target = "thumbv8m.main-none-eabihf", features = ["defmt", "lpc55-core0"]},
11 {target = "thumbv7em-none-eabihf", features = ["defmt", "mimxrt1011", "rt", "time-driver-pit"]}, 11 {target = "thumbv7em-none-eabihf", features = ["defmt", "mimxrt1011", "rt", "time-driver-pit"]},
12 {target = "thumbv7em-none-eabihf", features = ["defmt", "mimxrt1062", "rt", "time-driver-pit"]}, 12 {target = "thumbv7em-none-eabihf", features = ["defmt", "mimxrt1062", "rt", "time-driver-pit"]},
13] 13]
@@ -18,7 +18,7 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-nxp/s
18features = ["defmt", "unstable-pac" ] # TODO: Add time-driver-any, as both lpc55 and mimxrt1xxx use different drivers. 18features = ["defmt", "unstable-pac" ] # TODO: Add time-driver-any, as both lpc55 and mimxrt1xxx use different drivers.
19 19
20flavors = [ 20flavors = [
21 { regex_feature = "lpc55", target = "thumbv8m.main-none-eabihf" }, 21 { regex_feature = "lpc55-core0", target = "thumbv8m.main-none-eabihf" },
22 { regex_feature = "mimxrt.*", target = "thumbv7em-none-eabihf" }, 22 { regex_feature = "mimxrt.*", target = "thumbv7em-none-eabihf" },
23] 23]
24 24
@@ -36,21 +36,20 @@ embassy-time-queue-utils = { version = "0.3.0", path = "../embassy-time-queue-ut
36embedded-io = "0.6.1" 36embedded-io = "0.6.1"
37embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } 37embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
38## Chip dependencies 38## Chip dependencies
39lpc55-pac = { version = "0.5.0", optional = true } 39nxp-pac = { version = "0.1.0", optional = true, git = "https://github.com/i509VCB/nxp-pac", rev = "b736e3038254d593024aaa1a5a7b1f95a5728538"}
40nxp-pac = { version = "0.1.0", optional = true, git = "https://github.com/i509VCB/nxp-pac", rev = "be4dd0936c20d5897364a381b1d95a99514c1e7e" }
41 40
42imxrt-rt = { version = "0.1.7", optional = true, features = ["device"] } 41imxrt-rt = { version = "0.1.7", optional = true, features = ["device"] }
43 42
44[build-dependencies] 43[build-dependencies]
45cfg_aliases = "0.2.1" 44cfg_aliases = "0.2.1"
46nxp-pac = { version = "0.1.0", git = "https://github.com/i509VCB/nxp-pac", rev = "be4dd0936c20d5897364a381b1d95a99514c1e7e", features = ["metadata"], optional = true } 45nxp-pac = { version = "0.1.0", git = "https://github.com/i509VCB/nxp-pac", rev = "b736e3038254d593024aaa1a5a7b1f95a5728538", features = ["metadata"], optional = true }
47proc-macro2 = "1.0.95" 46proc-macro2 = "1.0.95"
48quote = "1.0.15" 47quote = "1.0.15"
49 48
50[features] 49[features]
51default = ["rt"] 50default = ["rt"]
52# Enable PACs as optional dependencies, since some chip families will use different pac crates (temporarily). 51# Enable PACs as optional dependencies, since some chip families will use different pac crates (temporarily).
53rt = ["lpc55-pac?/rt", "nxp-pac?/rt"] 52rt = ["nxp-pac?/rt"]
54 53
55## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers. 54## Enable [defmt support](https://docs.rs/defmt) and enables `defmt` debug-log messages and formatting in embassy drivers.
56defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt"] 55defmt = ["dep:defmt", "embassy-hal-internal/defmt", "embassy-sync/defmt"]
@@ -79,6 +78,6 @@ _rt1xxx = []
79_time_driver = ["dep:embassy-time-driver", "dep:embassy-time-queue-utils"] 78_time_driver = ["dep:embassy-time-driver", "dep:embassy-time-queue-utils"]
80 79
81#! ### Chip selection features 80#! ### Chip selection features
82lpc55 = ["dep:lpc55-pac"] 81lpc55-core0 = ["nxp-pac/lpc55s69_cm33_core0"]
83mimxrt1011 = ["nxp-pac/mimxrt1011", "_rt1xxx", "dep:imxrt-rt"] 82mimxrt1011 = ["nxp-pac/mimxrt1011", "_rt1xxx", "dep:imxrt-rt"]
84mimxrt1062 = ["nxp-pac/mimxrt1062", "_rt1xxx", "dep:imxrt-rt"] 83mimxrt1062 = ["nxp-pac/mimxrt1062", "_rt1xxx", "dep:imxrt-rt"]
diff --git a/embassy-nxp/src/chips/lpc55.rs b/embassy-nxp/src/chips/lpc55.rs
index e168ced00..711bff3e7 100644
--- a/embassy-nxp/src/chips/lpc55.rs
+++ b/embassy-nxp/src/chips/lpc55.rs
@@ -1,4 +1,4 @@
1pub use lpc55_pac as pac; 1pub use nxp_pac as pac;
2 2
3embassy_hal_internal::peripherals! { 3embassy_hal_internal::peripherals! {
4 // External pins. These are not only GPIOs, they are multi-purpose pins and can be used by other 4 // External pins. These are not only GPIOs, they are multi-purpose pins and can be used by other
diff --git a/embassy-nxp/src/gpio.rs b/embassy-nxp/src/gpio.rs
index 3049cc12d..717b38d96 100644
--- a/embassy-nxp/src/gpio.rs
+++ b/embassy-nxp/src/gpio.rs
@@ -1,7 +1,7 @@
1//! General purpose input/output (GPIO) driver. 1//! General purpose input/output (GPIO) driver.
2#![macro_use] 2#![macro_use]
3 3
4#[cfg_attr(feature = "lpc55", path = "./gpio/lpc55.rs")] 4#[cfg_attr(feature = "lpc55-core0", path = "./gpio/lpc55.rs")]
5#[cfg_attr(rt1xxx, path = "./gpio/rt1xxx.rs")] 5#[cfg_attr(rt1xxx, path = "./gpio/rt1xxx.rs")]
6mod inner; 6mod inner;
7pub use inner::*; 7pub use inner::*;
diff --git a/embassy-nxp/src/gpio/lpc55.rs b/embassy-nxp/src/gpio/lpc55.rs
index 8f407bb3a..36ea99d21 100644
--- a/embassy-nxp/src/gpio/lpc55.rs
+++ b/embassy-nxp/src/gpio/lpc55.rs
@@ -1,12 +1,17 @@
1use embassy_hal_internal::{impl_peripheral, PeripheralType}; 1use embassy_hal_internal::{impl_peripheral, PeripheralType};
2 2
3use crate::pac::iocon::vals::{PioDigimode, PioMode};
4use crate::pac::{GPIO, IOCON, SYSCON};
3use crate::{peripherals, Peri}; 5use crate::{peripherals, Peri};
4 6
5pub(crate) fn init() { 7pub(crate) fn init() {
6 // Enable clocks for GPIO, PINT, and IOCON 8 // Enable clocks for GPIO, PINT, and IOCON
7 syscon_reg() 9 SYSCON.ahbclkctrl0().modify(|w| {
8 .ahbclkctrl0 10 w.set_gpio0(true);
9 .modify(|_, w| w.gpio0().enable().gpio1().enable().mux().enable().iocon().enable()); 11 w.set_gpio1(true);
12 w.set_mux(true);
13 w.set_iocon(true);
14 });
10 info!("GPIO initialized"); 15 info!("GPIO initialized");
11} 16}
12 17
@@ -59,21 +64,24 @@ impl<'d> Output<'d> {
59 } 64 }
60 65
61 pub fn set_high(&mut self) { 66 pub fn set_high(&mut self) {
62 gpio_reg().set[self.pin.pin_bank() as usize].write(|w| unsafe { w.bits(self.pin.bit()) }) 67 GPIO.set(self.pin.pin_bank() as usize)
68 .write(|w| w.set_setp(self.pin.bit()));
63 } 69 }
64 70
65 pub fn set_low(&mut self) { 71 pub fn set_low(&mut self) {
66 gpio_reg().clr[self.pin.pin_bank() as usize].write(|w| unsafe { w.bits(self.pin.bit()) }) 72 GPIO.clr(self.pin.pin_bank() as usize)
73 .write(|w| w.set_clrp(self.pin.bit()));
67 } 74 }
68 75
69 pub fn toggle(&mut self) { 76 pub fn toggle(&mut self) {
70 gpio_reg().not[self.pin.pin_bank() as usize].write(|w| unsafe { w.bits(self.pin.bit()) }) 77 GPIO.not(self.pin.pin_bank() as usize)
78 .write(|w| w.set_notp(self.pin.bit()));
71 } 79 }
72 80
73 /// Get the current output level of the pin. Note that the value returned by this function is 81 /// Get the current output level of the pin. Note that the value returned by this function is
74 /// the voltage level reported by the pin, not the value set by the output driver. 82 /// the voltage level reported by the pin, not the value set by the output driver.
75 pub fn level(&self) -> Level { 83 pub fn level(&self) -> Level {
76 let bits = gpio_reg().pin[self.pin.pin_bank() as usize].read().bits(); 84 let bits = GPIO.pin(self.pin.pin_bank() as usize).read().port();
77 if bits & self.pin.bit() != 0 { 85 if bits & self.pin.bit() != 0 {
78 Level::High 86 Level::High
79 } else { 87 } else {
@@ -101,18 +109,18 @@ impl<'d> Input<'d> {
101 109
102 /// Set the pull configuration for the pin. To disable the pull, use [Pull::None]. 110 /// Set the pull configuration for the pin. To disable the pull, use [Pull::None].
103 pub fn set_pull(&mut self, pull: Pull) { 111 pub fn set_pull(&mut self, pull: Pull) {
104 match_iocon!(register, iocon_reg(), self.pin.pin_bank(), self.pin.pin_number(), { 112 match_iocon!(register, self.pin.pin_bank(), self.pin.pin_number(), {
105 register.modify(|_, w| match pull { 113 register.modify(|w| match pull {
106 Pull::None => w.mode().inactive(), 114 Pull::None => w.set_mode(PioMode::INACTIVE),
107 Pull::Up => w.mode().pull_up(), 115 Pull::Up => w.set_mode(PioMode::PULL_UP),
108 Pull::Down => w.mode().pull_down(), 116 Pull::Down => w.set_mode(PioMode::PULL_DOWN),
109 }); 117 });
110 }); 118 });
111 } 119 }
112 120
113 /// Get the current input level of the pin. 121 /// Get the current input level of the pin.
114 pub fn read(&self) -> Level { 122 pub fn read(&self) -> Level {
115 let bits = gpio_reg().pin[self.pin.pin_bank() as usize].read().bits(); 123 let bits = GPIO.pin(self.pin.pin_bank() as usize).read().port();
116 if bits & self.pin.bit() != 0 { 124 if bits & self.pin.bit() != 0 {
117 Level::High 125 Level::High
118 } else { 126 } else {
@@ -188,8 +196,8 @@ impl<'d> Flex<'d> {
188 /// Set the pin to digital mode. This is required for using a pin as a GPIO pin. The default 196 /// Set the pin to digital mode. This is required for using a pin as a GPIO pin. The default
189 /// setting for pins is (usually) non-digital. 197 /// setting for pins is (usually) non-digital.
190 fn set_as_digital(&mut self) { 198 fn set_as_digital(&mut self) {
191 match_iocon!(register, iocon_reg(), self.pin_bank(), self.pin_number(), { 199 match_iocon!(register, self.pin_bank(), self.pin_number(), {
192 register.modify(|_, w| w.digimode().digital()); 200 register.modify(|w| w.set_digimode(PioDigimode::DIGITAL));
193 }); 201 });
194 } 202 }
195 203
@@ -197,12 +205,14 @@ impl<'d> Flex<'d> {
197 /// function handles itself. 205 /// function handles itself.
198 pub fn set_as_output(&mut self) { 206 pub fn set_as_output(&mut self) {
199 self.set_as_digital(); 207 self.set_as_digital();
200 gpio_reg().dirset[self.pin.pin_bank() as usize].write(|w| unsafe { w.dirsetp().bits(self.bit()) }) 208 GPIO.dirset(self.pin.pin_bank() as usize)
209 .write(|w| w.set_dirsetp(self.bit()))
201 } 210 }
202 211
203 pub fn set_as_input(&mut self) { 212 pub fn set_as_input(&mut self) {
204 self.set_as_digital(); 213 self.set_as_digital();
205 gpio_reg().dirclr[self.pin.pin_bank() as usize].write(|w| unsafe { w.dirclrp().bits(self.bit()) }) 214 GPIO.dirclr(self.pin.pin_bank() as usize)
215 .write(|w| w.set_dirclrp(self.bit()))
206 } 216 }
207} 217}
208 218
@@ -262,52 +272,6 @@ impl SealedPin for AnyPin {
262 } 272 }
263} 273}
264 274
265/// Get the GPIO register block. This is used to configure all GPIO pins.
266///
267/// # Safety
268/// Due to the type system of peripherals, access to the settings of a single pin is possible only
269/// by a single thread at a time. Read/Write operations on a single registers are NOT atomic. You
270/// must ensure that the GPIO registers are not accessed concurrently by multiple threads.
271pub(crate) fn gpio_reg() -> &'static lpc55_pac::gpio::RegisterBlock {
272 unsafe { &*lpc55_pac::GPIO::ptr() }
273}
274
275/// Get the IOCON register block.
276///
277/// # Safety
278/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO
279/// registers are not accessed concurrently by multiple threads.
280pub(crate) fn iocon_reg() -> &'static lpc55_pac::iocon::RegisterBlock {
281 unsafe { &*lpc55_pac::IOCON::ptr() }
282}
283
284/// Get the INPUTMUX register block.
285///
286/// # Safety
287/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO
288/// registers are not accessed concurrently by multiple threads.
289pub(crate) fn inputmux_reg() -> &'static lpc55_pac::inputmux::RegisterBlock {
290 unsafe { &*lpc55_pac::INPUTMUX::ptr() }
291}
292
293/// Get the SYSCON register block.
294///
295/// # Safety
296/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO
297/// registers are not accessed concurrently by multiple threads.
298pub(crate) fn syscon_reg() -> &'static lpc55_pac::syscon::RegisterBlock {
299 unsafe { &*lpc55_pac::SYSCON::ptr() }
300}
301
302/// Get the PINT register block.
303///
304/// # Safety
305/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO
306/// registers are not accessed concurrently by multiple threads.
307pub(crate) fn pint_reg() -> &'static lpc55_pac::pint::RegisterBlock {
308 unsafe { &*lpc55_pac::PINT::ptr() }
309}
310
311/// Match the pin bank and number of a pin to the corresponding IOCON register. 275/// Match the pin bank and number of a pin to the corresponding IOCON register.
312/// 276///
313/// # Example 277/// # Example
@@ -316,270 +280,26 @@ pub(crate) fn pint_reg() -> &'static lpc55_pac::pint::RegisterBlock {
316/// use embassy_nxp::pac_utils::{iocon_reg, match_iocon}; 280/// use embassy_nxp::pac_utils::{iocon_reg, match_iocon};
317/// 281///
318/// // Make pin PIO1_6 digital and set it to pull-down mode. 282/// // Make pin PIO1_6 digital and set it to pull-down mode.
319/// match_iocon!(register, iocon_reg(), Bank::Bank1, 6, { 283/// match_iocon!(register, Bank::Bank1, 6, {
320/// register.modify(|_, w| w.mode().pull_down().digimode().digital()); 284/// register.modify(|w|{
285/// w.set_mode(PioMode::PULL_DOWN);
286/// w.set_digimode(PioDigimode::DIGITAL);
287///
288/// }
321/// }); 289/// });
322/// ``` 290/// ```
323macro_rules! match_iocon { 291macro_rules! match_iocon {
324 ($register:ident, $iocon_register:expr, $pin_bank:expr, $pin_number:expr, $action:expr) => { 292 ($register:ident, $pin_bank:expr, $pin_number:expr, $action:expr) => {
325 match ($pin_bank, $pin_number) { 293 match $pin_bank {
326 (Bank::Bank0, 0) => { 294 Bank::Bank0 => {
327 let $register = &($iocon_register).pio0_0; 295 let $register = IOCON.pio0($pin_number as usize);
328 $action;
329 }
330 (Bank::Bank0, 1) => {
331 let $register = &($iocon_register).pio0_1;
332 $action;
333 }
334 (Bank::Bank0, 2) => {
335 let $register = &($iocon_register).pio0_2;
336 $action;
337 }
338 (Bank::Bank0, 3) => {
339 let $register = &($iocon_register).pio0_3;
340 $action;
341 }
342 (Bank::Bank0, 4) => {
343 let $register = &($iocon_register).pio0_4;
344 $action;
345 }
346 (Bank::Bank0, 5) => {
347 let $register = &($iocon_register).pio0_5;
348 $action;
349 }
350 (Bank::Bank0, 6) => {
351 let $register = &($iocon_register).pio0_6;
352 $action;
353 }
354 (Bank::Bank0, 7) => {
355 let $register = &($iocon_register).pio0_7;
356 $action;
357 }
358 (Bank::Bank0, 8) => {
359 let $register = &($iocon_register).pio0_8;
360 $action;
361 }
362 (Bank::Bank0, 9) => {
363 let $register = &($iocon_register).pio0_9;
364 $action;
365 }
366 (Bank::Bank0, 10) => {
367 let $register = &($iocon_register).pio0_10;
368 $action; 296 $action;
369 } 297 }
370 (Bank::Bank0, 11) => { 298
371 let $register = &($iocon_register).pio0_11; 299 Bank::Bank1 => {
372 $action; 300 let $register = IOCON.pio1($pin_number as usize);
373 }
374 (Bank::Bank0, 12) => {
375 let $register = &($iocon_register).pio0_12;
376 $action;
377 }
378 (Bank::Bank0, 13) => {
379 let $register = &($iocon_register).pio0_13;
380 $action;
381 }
382 (Bank::Bank0, 14) => {
383 let $register = &($iocon_register).pio0_14;
384 $action;
385 }
386 (Bank::Bank0, 15) => {
387 let $register = &($iocon_register).pio0_15;
388 $action;
389 }
390 (Bank::Bank0, 16) => {
391 let $register = &($iocon_register).pio0_16;
392 $action;
393 }
394 (Bank::Bank0, 17) => {
395 let $register = &($iocon_register).pio0_17;
396 $action;
397 }
398 (Bank::Bank0, 18) => {
399 let $register = &($iocon_register).pio0_18;
400 $action;
401 }
402 (Bank::Bank0, 19) => {
403 let $register = &($iocon_register).pio0_19;
404 $action;
405 }
406 (Bank::Bank0, 20) => {
407 let $register = &($iocon_register).pio0_20;
408 $action;
409 }
410 (Bank::Bank0, 21) => {
411 let $register = &($iocon_register).pio0_21;
412 $action;
413 }
414 (Bank::Bank0, 22) => {
415 let $register = &($iocon_register).pio0_22;
416 $action;
417 }
418 (Bank::Bank0, 23) => {
419 let $register = &($iocon_register).pio0_23;
420 $action;
421 }
422 (Bank::Bank0, 24) => {
423 let $register = &($iocon_register).pio0_24;
424 $action;
425 }
426 (Bank::Bank0, 25) => {
427 let $register = &($iocon_register).pio0_25;
428 $action;
429 }
430 (Bank::Bank0, 26) => {
431 let $register = &($iocon_register).pio0_26;
432 $action;
433 }
434 (Bank::Bank0, 27) => {
435 let $register = &($iocon_register).pio0_27;
436 $action;
437 }
438 (Bank::Bank0, 28) => {
439 let $register = &($iocon_register).pio0_28;
440 $action;
441 }
442 (Bank::Bank0, 29) => {
443 let $register = &($iocon_register).pio0_29;
444 $action;
445 }
446 (Bank::Bank0, 30) => {
447 let $register = &($iocon_register).pio0_30;
448 $action;
449 }
450 (Bank::Bank0, 31) => {
451 let $register = &($iocon_register).pio0_31;
452 $action;
453 }
454 (Bank::Bank1, 0) => {
455 let $register = &($iocon_register).pio1_0;
456 $action;
457 }
458 (Bank::Bank1, 1) => {
459 let $register = &($iocon_register).pio1_1;
460 $action;
461 }
462 (Bank::Bank1, 2) => {
463 let $register = &($iocon_register).pio1_2;
464 $action;
465 }
466 (Bank::Bank1, 3) => {
467 let $register = &($iocon_register).pio1_3;
468 $action;
469 }
470 (Bank::Bank1, 4) => {
471 let $register = &($iocon_register).pio1_4;
472 $action;
473 }
474 (Bank::Bank1, 5) => {
475 let $register = &($iocon_register).pio1_5;
476 $action;
477 }
478 (Bank::Bank1, 6) => {
479 let $register = &($iocon_register).pio1_6;
480 $action;
481 }
482 (Bank::Bank1, 7) => {
483 let $register = &($iocon_register).pio1_7;
484 $action;
485 }
486 (Bank::Bank1, 8) => {
487 let $register = &($iocon_register).pio1_8;
488 $action;
489 }
490 (Bank::Bank1, 9) => {
491 let $register = &($iocon_register).pio1_9;
492 $action;
493 }
494 (Bank::Bank1, 10) => {
495 let $register = &($iocon_register).pio1_10;
496 $action;
497 }
498 (Bank::Bank1, 11) => {
499 let $register = &($iocon_register).pio1_11;
500 $action;
501 }
502 (Bank::Bank1, 12) => {
503 let $register = &($iocon_register).pio1_12;
504 $action;
505 }
506 (Bank::Bank1, 13) => {
507 let $register = &($iocon_register).pio1_13;
508 $action;
509 }
510 (Bank::Bank1, 14) => {
511 let $register = &($iocon_register).pio1_14;
512 $action;
513 }
514 (Bank::Bank1, 15) => {
515 let $register = &($iocon_register).pio1_15;
516 $action;
517 }
518 (Bank::Bank1, 16) => {
519 let $register = &($iocon_register).pio1_16;
520 $action;
521 }
522 (Bank::Bank1, 17) => {
523 let $register = &($iocon_register).pio1_17;
524 $action;
525 }
526 (Bank::Bank1, 18) => {
527 let $register = &($iocon_register).pio1_18;
528 $action;
529 }
530 (Bank::Bank1, 19) => {
531 let $register = &($iocon_register).pio1_19;
532 $action;
533 }
534 (Bank::Bank1, 20) => {
535 let $register = &($iocon_register).pio1_20;
536 $action;
537 }
538 (Bank::Bank1, 21) => {
539 let $register = &($iocon_register).pio1_21;
540 $action;
541 }
542 (Bank::Bank1, 22) => {
543 let $register = &($iocon_register).pio1_22;
544 $action;
545 }
546 (Bank::Bank1, 23) => {
547 let $register = &($iocon_register).pio1_23;
548 $action;
549 }
550 (Bank::Bank1, 24) => {
551 let $register = &($iocon_register).pio1_24;
552 $action;
553 }
554 (Bank::Bank1, 25) => {
555 let $register = &($iocon_register).pio1_25;
556 $action;
557 }
558 (Bank::Bank1, 26) => {
559 let $register = &($iocon_register).pio1_26;
560 $action;
561 }
562 (Bank::Bank1, 27) => {
563 let $register = &($iocon_register).pio1_27;
564 $action;
565 }
566 (Bank::Bank1, 28) => {
567 let $register = &($iocon_register).pio1_28;
568 $action;
569 }
570 (Bank::Bank1, 29) => {
571 let $register = &($iocon_register).pio1_29;
572 $action;
573 }
574 (Bank::Bank1, 30) => {
575 let $register = &($iocon_register).pio1_30;
576 $action;
577 }
578 (Bank::Bank1, 31) => {
579 let $register = &($iocon_register).pio1_31;
580 $action; 301 $action;
581 } 302 }
582 _ => unreachable!(),
583 } 303 }
584 }; 304 };
585} 305}
diff --git a/embassy-nxp/src/lib.rs b/embassy-nxp/src/lib.rs
index 3fcb14b7e..74142a10b 100644
--- a/embassy-nxp/src/lib.rs
+++ b/embassy-nxp/src/lib.rs
@@ -4,9 +4,9 @@
4pub(crate) mod fmt; 4pub(crate) mod fmt;
5 5
6pub mod gpio; 6pub mod gpio;
7#[cfg(feature = "lpc55")] 7#[cfg(feature = "lpc55-core0")]
8pub mod pint; 8pub mod pint;
9#[cfg(feature = "lpc55")] 9#[cfg(feature = "lpc55-core0")]
10pub mod usart; 10pub mod usart;
11 11
12#[cfg(feature = "_time_driver")] 12#[cfg(feature = "_time_driver")]
@@ -15,7 +15,7 @@ pub mod usart;
15mod time_driver; 15mod time_driver;
16 16
17// This mod MUST go last, so that it sees all the `impl_foo!` macros 17// This mod MUST go last, so that it sees all the `impl_foo!` macros
18#[cfg_attr(feature = "lpc55", path = "chips/lpc55.rs")] 18#[cfg_attr(feature = "lpc55-core0", path = "chips/lpc55.rs")]
19#[cfg_attr(feature = "mimxrt1011", path = "chips/mimxrt1011.rs")] 19#[cfg_attr(feature = "mimxrt1011", path = "chips/mimxrt1011.rs")]
20#[cfg_attr(feature = "mimxrt1062", path = "chips/mimxrt1062.rs")] 20#[cfg_attr(feature = "mimxrt1062", path = "chips/mimxrt1062.rs")]
21mod chip; 21mod chip;
@@ -83,10 +83,10 @@ pub fn init(_config: config::Config) -> Peripherals {
83 pac::CCM.ccgr6().modify(|v| v.set_cg0(1)); 83 pac::CCM.ccgr6().modify(|v| v.set_cg0(1));
84 } 84 }
85 85
86 #[cfg(any(feature = "lpc55", rt1xxx))] 86 #[cfg(any(feature = "lpc55-core0", rt1xxx))]
87 gpio::init(); 87 gpio::init();
88 88
89 #[cfg(feature = "lpc55")] 89 #[cfg(feature = "lpc55-core0")]
90 pint::init(); 90 pint::init();
91 91
92 #[cfg(feature = "_time_driver")] 92 #[cfg(feature = "_time_driver")]
diff --git a/embassy-nxp/src/pint.rs b/embassy-nxp/src/pint.rs
index ff414b4e6..e594aaa6a 100644
--- a/embassy-nxp/src/pint.rs
+++ b/embassy-nxp/src/pint.rs
@@ -5,10 +5,11 @@ use core::pin::Pin as FuturePin;
5use core::task::{Context, Poll}; 5use core::task::{Context, Poll};
6 6
7use critical_section::Mutex; 7use critical_section::Mutex;
8use embassy_hal_internal::interrupt::InterruptExt;
8use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
9 10
10use crate::gpio::{self, inputmux_reg, pint_reg, syscon_reg, AnyPin, Level, SealedPin}; 11use crate::gpio::{self, AnyPin, Level, SealedPin};
11use crate::pac::interrupt; 12use crate::pac::{interrupt, INPUTMUX, PINT, SYSCON};
12use crate::Peri; 13use crate::Peri;
13 14
14struct PinInterrupt { 15struct PinInterrupt {
@@ -88,18 +89,18 @@ enum InterruptOn {
88} 89}
89 90
90pub(crate) fn init() { 91pub(crate) fn init() {
91 syscon_reg().ahbclkctrl0.modify(|_, w| w.pint().enable()); 92 SYSCON.ahbclkctrl0().modify(|w| w.set_pint(true));
92 93
93 // Enable interrupts 94 // Enable interrupts
94 unsafe { 95 unsafe {
95 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT0); 96 interrupt::PIN_INT0.enable();
96 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT1); 97 interrupt::PIN_INT1.enable();
97 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT2); 98 interrupt::PIN_INT2.enable();
98 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT3); 99 interrupt::PIN_INT3.enable();
99 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT4); 100 interrupt::PIN_INT4.enable();
100 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT5); 101 interrupt::PIN_INT5.enable();
101 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT6); 102 interrupt::PIN_INT6.enable();
102 crate::pac::NVIC::unmask(crate::pac::Interrupt::PIN_INT7); 103 interrupt::PIN_INT7.enable();
103 }; 104 };
104 105
105 info!("Pin interrupts initialized"); 106 info!("Pin interrupts initialized");
@@ -119,24 +120,19 @@ impl<'d> InputFuture<'d> {
119 let interrupt_number = next_available_interrupt()?; 120 let interrupt_number = next_available_interrupt()?;
120 121
121 // Clear interrupt, just in case 122 // Clear interrupt, just in case
122 pint_reg() 123 PINT.rise().write(|w| w.set_rdet(1 << interrupt_number));
123 .rise 124 PINT.fall().write(|w| w.set_fdet(1 << interrupt_number));
124 .write(|w| unsafe { w.rdet().bits(1 << interrupt_number) });
125 pint_reg()
126 .fall
127 .write(|w| unsafe { w.fdet().bits(1 << interrupt_number) });
128 125
129 // Enable input multiplexing on pin interrupt register 0 for pin (32*bank + pin_number) 126 // Enable input multiplexing on pin interrupt register 0 for pin (32*bank + pin_number)
130 inputmux_reg().pintsel[interrupt_number] 127 INPUTMUX
131 .write(|w| unsafe { w.intpin().bits(32 * pin.pin_bank() as u8 + pin.pin_number()) }); 128 .pintsel(interrupt_number as usize)
129 .write(|w| w.set_intpin(32 * pin.pin_bank() as u8 + pin.pin_number()));
132 130
133 match interrupt_on { 131 match interrupt_on {
134 InterruptOn::Level(level) => { 132 InterruptOn::Level(level) => {
135 // Set pin interrupt register to edge sensitive or level sensitive 133 // Set pin interrupt register to edge sensitive or level sensitive
136 // 0 = edge sensitive, 1 = level sensitive 134 // 0 = edge sensitive, 1 = level sensitive
137 pint_reg() 135 PINT.isel().modify(|w| w.set_pmode(w.pmode() | (1 << interrupt_number)));
138 .isel
139 .modify(|r, w| unsafe { w.bits(r.bits() | (1 << interrupt_number)) });
140 136
141 // Enable level interrupt. 137 // Enable level interrupt.
142 // 138 //
@@ -144,63 +140,44 @@ impl<'d> InputFuture<'d> {
144 // is activated. 140 // is activated.
145 141
146 // 0 = no-op, 1 = enable 142 // 0 = no-op, 1 = enable
147 pint_reg() 143 PINT.sienr().write(|w| w.set_setenrl(1 << interrupt_number));
148 .sienr
149 .write(|w| unsafe { w.setenrl().bits(1 << interrupt_number) });
150 144
151 // Set active level 145 // Set active level
152 match level { 146 match level {
153 Level::Low => { 147 Level::Low => {
154 // 0 = no-op, 1 = select LOW 148 // 0 = no-op, 1 = select LOW
155 pint_reg() 149 PINT.cienf().write(|w| w.set_cenaf(1 << interrupt_number));
156 .cienf
157 .write(|w| unsafe { w.cenaf().bits(1 << interrupt_number) });
158 } 150 }
159 Level::High => { 151 Level::High => {
160 // 0 = no-op, 1 = select HIGH 152 // 0 = no-op, 1 = select HIGH
161 pint_reg() 153 PINT.sienf().write(|w| w.set_setenaf(1 << interrupt_number));
162 .sienf
163 .write(|w| unsafe { w.setenaf().bits(1 << interrupt_number) });
164 } 154 }
165 } 155 }
166 } 156 }
167 InterruptOn::Edge(edge) => { 157 InterruptOn::Edge(edge) => {
168 // Set pin interrupt register to edge sensitive or level sensitive 158 // Set pin interrupt register to edge sensitive or level sensitive
169 // 0 = edge sensitive, 1 = level sensitive 159 // 0 = edge sensitive, 1 = level sensitive
170 pint_reg() 160 PINT.isel()
171 .isel 161 .modify(|w| w.set_pmode(w.pmode() & !(1 << interrupt_number)));
172 .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << interrupt_number)) });
173 162
174 // Enable rising/falling edge detection 163 // Enable rising/falling edge detection
175 match edge { 164 match edge {
176 Edge::Rising => { 165 Edge::Rising => {
177 // 0 = no-op, 1 = enable rising edge 166 // 0 = no-op, 1 = enable rising edge
178 pint_reg() 167 PINT.sienr().write(|w| w.set_setenrl(1 << interrupt_number));
179 .sienr
180 .write(|w| unsafe { w.setenrl().bits(1 << interrupt_number) });
181 // 0 = no-op, 1 = disable falling edge 168 // 0 = no-op, 1 = disable falling edge
182 pint_reg() 169 PINT.cienf().write(|w| w.set_cenaf(1 << interrupt_number));
183 .cienf
184 .write(|w| unsafe { w.cenaf().bits(1 << interrupt_number) });
185 } 170 }
186 Edge::Falling => { 171 Edge::Falling => {
187 // 0 = no-op, 1 = enable falling edge 172 // 0 = no-op, 1 = enable falling edge
188 pint_reg() 173 PINT.sienf().write(|w| w.set_setenaf(1 << interrupt_number));
189 .sienf
190 .write(|w| unsafe { w.setenaf().bits(1 << interrupt_number) });
191 // 0 = no-op, 1 = disable rising edge 174 // 0 = no-op, 1 = disable rising edge
192 pint_reg() 175 PINT.cienr().write(|w| w.set_cenrl(1 << interrupt_number));
193 .cienr
194 .write(|w| unsafe { w.cenrl().bits(1 << interrupt_number) });
195 } 176 }
196 Edge::Both => { 177 Edge::Both => {
197 // 0 = no-op, 1 = enable 178 // 0 = no-op, 1 = enable
198 pint_reg() 179 PINT.sienr().write(|w| w.set_setenrl(1 << interrupt_number));
199 .sienr 180 PINT.sienf().write(|w| w.set_setenaf(1 << interrupt_number));
200 .write(|w| unsafe { w.setenrl().bits(1 << interrupt_number) });
201 pint_reg()
202 .sienf
203 .write(|w| unsafe { w.setenaf().bits(1 << interrupt_number) });
204 } 181 }
205 } 182 }
206 } 183 }
@@ -239,12 +216,8 @@ impl<'d> Drop for InputFuture<'d> {
239 216
240 // Disable pin interrupt 217 // Disable pin interrupt
241 // 0 = no-op, 1 = disable 218 // 0 = no-op, 1 = disable
242 pint_reg() 219 PINT.cienr().write(|w| w.set_cenrl(1 << interrupt_number));
243 .cienr 220 PINT.cienf().write(|w| w.set_cenaf(1 << interrupt_number));
244 .write(|w| unsafe { w.cenrl().bits(1 << interrupt_number) });
245 pint_reg()
246 .cienf
247 .write(|w| unsafe { w.cenaf().bits(1 << interrupt_number) });
248 221
249 critical_section::with(|cs| { 222 critical_section::with(|cs| {
250 let mut pin_interrupts = PIN_INTERRUPTS.borrow(cs).borrow_mut(); 223 let mut pin_interrupts = PIN_INTERRUPTS.borrow(cs).borrow_mut();
@@ -277,12 +250,8 @@ impl<'d> Future for InputFuture<'d> {
277} 250}
278 251
279fn handle_interrupt(interrupt_number: usize) { 252fn handle_interrupt(interrupt_number: usize) {
280 pint_reg() 253 PINT.rise().write(|w| w.set_rdet(1 << interrupt_number));
281 .rise 254 PINT.fall().write(|w| w.set_fdet(1 << interrupt_number));
282 .write(|w| unsafe { w.rdet().bits(1 << interrupt_number) });
283 pint_reg()
284 .fall
285 .write(|w| unsafe { w.fdet().bits(1 << interrupt_number) });
286 255
287 critical_section::with(|cs| { 256 critical_section::with(|cs| {
288 let mut pin_interrupts = PIN_INTERRUPTS.borrow(cs).borrow_mut(); 257 let mut pin_interrupts = PIN_INTERRUPTS.borrow(cs).borrow_mut();
diff --git a/embassy-nxp/src/time_driver/rtc.rs b/embassy-nxp/src/time_driver/rtc.rs
index 94272e9c2..fb6de6a5e 100644
--- a/embassy-nxp/src/time_driver/rtc.rs
+++ b/embassy-nxp/src/time_driver/rtc.rs
@@ -6,7 +6,9 @@ use embassy_hal_internal::interrupt::{InterruptExt, Priority};
6use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; 6use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex;
7use embassy_time_driver::{time_driver_impl, Driver}; 7use embassy_time_driver::{time_driver_impl, Driver};
8use embassy_time_queue_utils::Queue; 8use embassy_time_queue_utils::Queue;
9use lpc55_pac::{interrupt, PMC, RTC, SYSCON}; 9
10use crate::pac::{interrupt, pmc, rtc, PMC, RTC, SYSCON};
11
10struct AlarmState { 12struct AlarmState {
11 timestamp: Cell<u64>, 13 timestamp: Cell<u64>,
12} 14}
@@ -32,33 +34,32 @@ time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
32}); 34});
33impl RtcDriver { 35impl RtcDriver {
34 fn init(&'static self) { 36 fn init(&'static self) {
35 let syscon = unsafe { &*SYSCON::ptr() }; 37 let syscon = SYSCON;
36 let pmc = unsafe { &*PMC::ptr() }; 38 let pmc = PMC;
37 let rtc = unsafe { &*RTC::ptr() }; 39 let rtc = RTC;
38 40
39 syscon.ahbclkctrl0.modify(|_, w| w.rtc().enable()); 41 syscon.ahbclkctrl0().modify(|w| w.set_rtc(true));
40 42
41 // By default the RTC enters software reset. If for some reason it is 43 // By default the RTC enters software reset. If for some reason it is
42 // not in reset, we enter and them promptly leave.q 44 // not in reset, we enter and them promptly leave.q
43 rtc.ctrl.modify(|_, w| w.swreset().set_bit()); 45 rtc.ctrl().modify(|w| w.set_swreset(true));
44 rtc.ctrl.modify(|_, w| w.swreset().clear_bit()); 46 rtc.ctrl().modify(|w| w.set_swreset(false));
45 47
46 // Select clock source - either XTAL or FRO 48 // Select clock source - either XTAL or FRO
47 // pmc.rtcosc32k.write(|w| w.sel().xtal32k()); 49 // pmc.rtcosc32k().write(|w| w.set_sel(pmc::vals::Sel::XTAL32K));
48 pmc.rtcosc32k.write(|w| w.sel().fro32k()); 50 pmc.rtcosc32k().write(|w| w.set_sel(pmc::vals::Sel::FRO32K));
49 51
50 // Start the RTC peripheral 52 // Start the RTC peripheral
51 rtc.ctrl.modify(|_, w| w.rtc_osc_pd().power_up()); 53 rtc.ctrl().modify(|w| w.set_rtc_osc_pd(rtc::vals::RtcOscPd::POWER_UP));
52
53 // rtc.ctrl.modify(|_, w| w.rtc_en().clear_bit()); // EXTRA
54 54
55 //reset/clear(?) counter 55 //reset/clear(?) counter
56 rtc.count.reset(); 56 rtc.count().modify(|w| w.set_val(0));
57 //en rtc main counter 57 //en rtc main counter
58 rtc.ctrl.modify(|_, w| w.rtc_en().set_bit()); 58 rtc.ctrl().modify(|w| w.set_rtc_en(true));
59 rtc.ctrl.modify(|_, w| w.rtc1khz_en().set_bit()); 59 rtc.ctrl().modify(|w| w.set_rtc1khz_en(true));
60 // subsec counter enable 60 // subsec counter enable
61 rtc.ctrl.modify(|_, w| w.rtc_subsec_ena().set_bit()); 61 rtc.ctrl()
62 .modify(|w| w.set_rtc_subsec_ena(rtc::vals::RtcSubsecEna::POWER_UP));
62 63
63 // enable irq 64 // enable irq
64 unsafe { 65 unsafe {
@@ -68,7 +69,7 @@ impl RtcDriver {
68 } 69 }
69 70
70 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool { 71 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
71 let rtc = unsafe { &*RTC::ptr() }; 72 let rtc = RTC;
72 let alarm = &self.alarms.borrow(cs); 73 let alarm = &self.alarms.borrow(cs);
73 alarm.timestamp.set(timestamp); 74 alarm.timestamp.set(timestamp);
74 let now = self.now(); 75 let now = self.now();
@@ -83,33 +84,38 @@ impl RtcDriver {
83 let sec = (diff / 32768) as u32; 84 let sec = (diff / 32768) as u32;
84 let subsec = (diff % 32768) as u32; 85 let subsec = (diff % 32768) as u32;
85 86
86 let current_sec = rtc.count.read().val().bits(); 87 let current_sec = rtc.count().read().val();
87 let target_sec = current_sec.wrapping_add(sec as u32); 88 let target_sec = current_sec.wrapping_add(sec as u32);
88 89
89 rtc.match_.write(|w| unsafe { w.matval().bits(target_sec) }); 90 rtc.match_().write(|w| w.set_matval(target_sec));
90 rtc.wake.write(|w| unsafe { 91 rtc.wake().write(|w| {
91 let ms = (subsec * 1000) / 32768; 92 let ms = (subsec * 1000) / 32768;
92 w.val().bits(ms as u16) 93 w.set_val(ms as u16)
93 }); 94 });
95
94 if subsec > 0 { 96 if subsec > 0 {
95 let ms = (subsec * 1000) / 32768; 97 let ms = (subsec * 1000) / 32768;
96 rtc.wake.write(|w| unsafe { w.val().bits(ms as u16) }); 98 rtc.wake().write(|w| w.set_val(ms as u16));
97 } 99 }
98 rtc.ctrl.modify(|_, w| w.alarm1hz().clear_bit().wake1khz().clear_bit()); 100
101 rtc.ctrl().modify(|w| {
102 w.set_alarm1hz(false);
103 w.set_wake1khz(rtc::vals::Wake1khz::RUN)
104 });
99 true 105 true
100 } 106 }
101 107
102 fn on_interrupt(&self) { 108 fn on_interrupt(&self) {
103 critical_section::with(|cs| { 109 critical_section::with(|cs| {
104 let rtc = unsafe { &*RTC::ptr() }; 110 let rtc = RTC;
105 let flags = rtc.ctrl.read(); 111 let flags = rtc.ctrl().read();
106 if flags.alarm1hz().bit_is_clear() { 112 if flags.alarm1hz() == false {
107 rtc.ctrl.modify(|_, w| w.alarm1hz().set_bit()); 113 rtc.ctrl().modify(|w| w.set_alarm1hz(true));
108 self.trigger_alarm(cs); 114 self.trigger_alarm(cs);
109 } 115 }
110 116
111 if flags.wake1khz().bit_is_clear() { 117 if flags.wake1khz() == rtc::vals::Wake1khz::RUN {
112 rtc.ctrl.modify(|_, w| w.wake1khz().set_bit()); 118 rtc.ctrl().modify(|w| w.set_wake1khz(rtc::vals::Wake1khz::TIMEOUT));
113 self.trigger_alarm(cs); 119 self.trigger_alarm(cs);
114 } 120 }
115 }); 121 });
@@ -135,13 +141,13 @@ impl RtcDriver {
135 141
136impl Driver for RtcDriver { 142impl Driver for RtcDriver {
137 fn now(&self) -> u64 { 143 fn now(&self) -> u64 {
138 let rtc = unsafe { &*RTC::ptr() }; 144 let rtc = RTC;
139 145
140 loop { 146 loop {
141 let sec1 = rtc.count.read().val().bits() as u64; 147 let sec1 = rtc.count().read().val() as u64;
142 let sub1 = rtc.subsec.read().subsec().bits() as u64; 148 let sub1 = rtc.subsec().read().subsec() as u64;
143 let sec2 = rtc.count.read().val().bits() as u64; 149 let sec2 = rtc.count().read().val() as u64;
144 let sub2 = rtc.subsec.read().subsec().bits() as u64; 150 let sub2 = rtc.subsec().read().subsec() as u64;
145 151
146 if sec1 == sec2 && sub1 == sub2 { 152 if sec1 == sec2 && sub1 == sub2 {
147 return sec1 * 32768 + sub1; 153 return sec1 * 32768 + sub1;
@@ -162,7 +168,7 @@ impl Driver for RtcDriver {
162 }) 168 })
163 } 169 }
164} 170}
165#[cortex_m_rt::interrupt] 171#[interrupt]
166fn RTC() { 172fn RTC() {
167 DRIVER.on_interrupt(); 173 DRIVER.on_interrupt();
168} 174}
diff --git a/embassy-nxp/src/usart.rs b/embassy-nxp/src/usart.rs
index 009c251e2..1d8886f24 100644
--- a/embassy-nxp/src/usart.rs
+++ b/embassy-nxp/src/usart.rs
@@ -1,6 +1,5 @@
1//! Universal Synchronous/Asynchronous Receiver/Transmitter (USART) driver. 1//! Universal Synchronous/Asynchronous Receiver/Transmitter (USART) driver.
2#![macro_use]
3 2
4#[cfg_attr(feature = "lpc55", path = "./usart/lpc55.rs")] 3#[cfg_attr(feature = "lpc55-core0", path = "./usart/lpc55.rs")]
5mod inner; 4mod inner;
6pub use inner::*; 5pub use inner::*;
diff --git a/embassy-nxp/src/usart/lpc55.rs b/embassy-nxp/src/usart/lpc55.rs
index 3f7456a2e..428b80c4b 100644
--- a/embassy-nxp/src/usart/lpc55.rs
+++ b/embassy-nxp/src/usart/lpc55.rs
@@ -2,9 +2,12 @@ use core::marker::PhantomData;
2 2
3use embassy_hal_internal::{Peri, PeripheralType}; 3use embassy_hal_internal::{Peri, PeripheralType};
4use embedded_io::{self, ErrorKind}; 4use embedded_io::{self, ErrorKind};
5pub use sealed::SealedInstance;
6 5
7use crate::gpio::AnyPin; 6use crate::gpio::{match_iocon, AnyPin, Bank, SealedPin};
7use crate::pac::flexcomm::Flexcomm as FlexcommReg;
8use crate::pac::iocon::vals::PioFunc;
9use crate::pac::usart::Usart as UsartReg;
10use crate::pac::*;
8use crate::{Blocking, Mode}; 11use crate::{Blocking, Mode};
9 12
10/// Serial error 13/// Serial error
@@ -47,16 +50,6 @@ pub enum DataBits {
47 DataBits9, 50 DataBits9,
48} 51}
49 52
50impl DataBits {
51 fn bits(&self) -> u8 {
52 match self {
53 Self::DataBits7 => 0b00,
54 Self::DataBits8 => 0b01,
55 Self::DataBits9 => 0b10,
56 }
57 }
58}
59
60/// Parity bit. 53/// Parity bit.
61#[derive(Clone, Copy, PartialEq, Eq, Debug)] 54#[derive(Clone, Copy, PartialEq, Eq, Debug)]
62pub enum Parity { 55pub enum Parity {
@@ -68,16 +61,6 @@ pub enum Parity {
68 ParityOdd, 61 ParityOdd,
69} 62}
70 63
71impl Parity {
72 fn bits(&self) -> u8 {
73 match self {
74 Self::ParityNone => 0b00,
75 Self::ParityEven => 0b10,
76 Self::ParityOdd => 0b11,
77 }
78 }
79}
80
81/// Stop bits. 64/// Stop bits.
82#[derive(Clone, Copy, PartialEq, Eq, Debug)] 65#[derive(Clone, Copy, PartialEq, Eq, Debug)]
83pub enum StopBits { 66pub enum StopBits {
@@ -87,15 +70,6 @@ pub enum StopBits {
87 Stop2, 70 Stop2,
88} 71}
89 72
90impl StopBits {
91 fn bits(&self) -> bool {
92 return match self {
93 Self::Stop1 => false,
94 Self::Stop2 => true,
95 };
96 }
97}
98
99/// UART config. 73/// UART config.
100#[non_exhaustive] 74#[non_exhaustive]
101#[derive(Clone, Debug)] 75#[derive(Clone, Debug)]
@@ -117,7 +91,7 @@ pub struct Config {
117impl Default for Config { 91impl Default for Config {
118 fn default() -> Self { 92 fn default() -> Self {
119 Self { 93 Self {
120 baudrate: 9600, 94 baudrate: 115200,
121 data_bits: DataBits::DataBits8, 95 data_bits: DataBits::DataBits8,
122 stop_bits: StopBits::Stop1, 96 stop_bits: StopBits::Stop1,
123 parity: Parity::ParityNone, 97 parity: Parity::ParityNone,
@@ -131,59 +105,72 @@ impl Default for Config {
131/// 'd: the lifetime marker ensuring correct borrow checking for peripherals used at compile time 105/// 'd: the lifetime marker ensuring correct borrow checking for peripherals used at compile time
132/// T: the peripheral instance type allowing usage of peripheral specific registers 106/// T: the peripheral instance type allowing usage of peripheral specific registers
133/// M: the operating mode of USART peripheral 107/// M: the operating mode of USART peripheral
134pub struct Usart<'d, T: Instance, M: Mode> { 108pub struct Usart<'d, M: Mode> {
135 tx: UsartTx<'d, T, M>, 109 tx: UsartTx<'d, M>,
136 rx: UsartRx<'d, T, M>, 110 rx: UsartRx<'d, M>,
137} 111}
138 112
139pub struct UsartTx<'d, T: Instance, M: Mode> { 113pub struct UsartTx<'d, M: Mode> {
140 phantom: PhantomData<(&'d (), T, M)>, 114 info: &'static Info,
115 phantom: PhantomData<(&'d (), M)>,
141} 116}
142 117
143pub struct UsartRx<'d, T: Instance, M: Mode> { 118pub struct UsartRx<'d, M: Mode> {
144 phantom: PhantomData<(&'d (), T, M)>, 119 info: &'static Info,
120 phantom: PhantomData<(&'d (), M)>,
145} 121}
146 122
147impl<'d, T: Instance, M: Mode> UsartTx<'d, T, M> { 123impl<'d, M: Mode> UsartTx<'d, M> {
148 pub fn new(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self { 124 pub fn new<T: Instance>(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self {
149 Usart::<T, M>::init(Some(tx.into()), None, config); 125 Usart::<M>::init::<T>(Some(tx.into()), None, config);
150 Self::new_inner() 126 Self::new_inner(T::info())
151 } 127 }
152 128
153 #[inline] 129 #[inline]
154 fn new_inner() -> Self { 130 fn new_inner(info: &'static Info) -> Self {
155 Self { phantom: PhantomData } 131 Self {
132 info,
133 phantom: PhantomData,
134 }
156 } 135 }
157 136
158 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 137 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
159 T::blocking_write(buffer) 138 for &b in buffer {
139 while !(self.info.usart_reg.fifostat().read().txnotfull()) {}
140 self.info.usart_reg.fifowr().write(|w| w.set_txdata(b as u16));
141 }
142 Ok(())
160 } 143 }
161 144
162 pub fn blocking_flush(&mut self) -> Result<(), Error> { 145 pub fn blocking_flush(&mut self) -> Result<(), Error> {
163 T::blocking_flush() 146 while !(self.info.usart_reg.fifostat().read().txempty()) {}
147 Ok(())
164 } 148 }
165 149
166 pub fn tx_busy(&self) -> bool { 150 pub fn tx_busy(&self) -> bool {
167 T::tx_busy() 151 !(self.info.usart_reg.fifostat().read().txempty())
168 } 152 }
169} 153}
170 154
171impl<'d, T: Instance> UsartTx<'d, T, Blocking> { 155impl<'d> UsartTx<'d, Blocking> {
172 pub fn new_blocking(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self { 156 pub fn new_blocking<T: Instance>(_usart: Peri<'d, T>, tx: Peri<'d, impl TxPin<T>>, config: Config) -> Self {
173 Usart::<T, Blocking>::init(Some(tx.into()), None, config); 157 Usart::<Blocking>::init::<T>(Some(tx.into()), None, config);
174 Self::new_inner() 158 Self::new_inner(T::info())
175 } 159 }
176} 160}
177 161
178impl<'d, T: Instance, M: Mode> UsartRx<'d, T, M> { 162impl<'d, M: Mode> UsartRx<'d, M> {
179 pub fn new(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self { 163 pub fn new<T: Instance>(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self {
180 Usart::<T, M>::init(None, Some(rx.into()), config); 164 Usart::<M>::init::<T>(None, Some(rx.into()), config);
181 Self::new_inner() 165 Self::new_inner(T::info())
182 } 166 }
183 167
184 #[inline] 168 #[inline]
185 fn new_inner() -> Self { 169 fn new_inner(info: &'static Info) -> Self {
186 Self { phantom: PhantomData } 170 Self {
171 info,
172 phantom: PhantomData,
173 }
187 } 174 }
188 175
189 pub fn blocking_read(&mut self, mut buffer: &mut [u8]) -> Result<(), Error> { 176 pub fn blocking_read(&mut self, mut buffer: &mut [u8]) -> Result<(), Error> {
@@ -201,19 +188,35 @@ impl<'d, T: Instance, M: Mode> UsartRx<'d, T, M> {
201 /// - Ok(n) -> read n bytes 188 /// - Ok(n) -> read n bytes
202 /// - Err(n, Error) -> read n-1 bytes, but encountered an error while reading nth byte 189 /// - Err(n, Error) -> read n-1 bytes, but encountered an error while reading nth byte
203 fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, (usize, Error)> { 190 fn drain_fifo(&mut self, buffer: &mut [u8]) -> Result<usize, (usize, Error)> {
204 T::drain_fifo(buffer) 191 for (i, b) in buffer.iter_mut().enumerate() {
192 while !(self.info.usart_reg.fifostat().read().rxnotempty()) {}
193 if self.info.usart_reg.fifostat().read().rxerr() {
194 return Err((i, Error::Overrun));
195 } else if self.info.usart_reg.fifordnopop().read().parityerr() {
196 return Err((i, Error::Parity));
197 } else if self.info.usart_reg.fifordnopop().read().framerr() {
198 return Err((i, Error::Framing));
199 } else if self.info.usart_reg.fifordnopop().read().rxnoise() {
200 return Err((i, Error::Noise));
201 } else if self.info.usart_reg.intstat().read().deltarxbrk() {
202 return Err((i, Error::Break));
203 }
204 let dr = self.info.usart_reg.fiford().read().rxdata() as u8;
205 *b = dr;
206 }
207 Ok(buffer.len())
205 } 208 }
206} 209}
207 210
208impl<'d, T: Instance> UsartRx<'d, T, Blocking> { 211impl<'d> UsartRx<'d, Blocking> {
209 pub fn new_blocking(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self { 212 pub fn new_blocking<T: Instance>(_usart: Peri<'d, T>, rx: Peri<'d, impl RxPin<T>>, config: Config) -> Self {
210 Usart::<T, Blocking>::init(None, Some(rx.into()), config); 213 Usart::<Blocking>::init::<T>(None, Some(rx.into()), config);
211 Self::new_inner() 214 Self::new_inner(T::info())
212 } 215 }
213} 216}
214 217
215impl<'d, T: Instance> Usart<'d, T, Blocking> { 218impl<'d> Usart<'d, Blocking> {
216 pub fn new_blocking( 219 pub fn new_blocking<T: Instance>(
217 usart: Peri<'d, T>, 220 usart: Peri<'d, T>,
218 tx: Peri<'d, impl TxPin<T>>, 221 tx: Peri<'d, impl TxPin<T>>,
219 rx: Peri<'d, impl RxPin<T>>, 222 rx: Peri<'d, impl RxPin<T>>,
@@ -223,29 +226,70 @@ impl<'d, T: Instance> Usart<'d, T, Blocking> {
223 } 226 }
224} 227}
225 228
226impl<'d, T: Instance, M: Mode> Usart<'d, T, M> { 229impl<'d, M: Mode> Usart<'d, M> {
227 fn new_inner(_usart: Peri<'d, T>, mut tx: Peri<'d, AnyPin>, mut rx: Peri<'d, AnyPin>, config: Config) -> Self { 230 fn new_inner<T: Instance>(
228 Self::init(Some(tx.reborrow()), Some(rx.reborrow()), config); 231 _usart: Peri<'d, T>,
232 mut tx: Peri<'d, AnyPin>,
233 mut rx: Peri<'d, AnyPin>,
234 config: Config,
235 ) -> Self {
236 Self::init::<T>(Some(tx.reborrow()), Some(rx.reborrow()), config);
229 Self { 237 Self {
230 tx: UsartTx::new_inner(), 238 tx: UsartTx::new_inner(T::info()),
231 rx: UsartRx::new_inner(), 239 rx: UsartRx::new_inner(T::info()),
232 } 240 }
233 } 241 }
234 242
235 fn init(_tx: Option<Peri<'_, AnyPin>>, _rx: Option<Peri<'_, AnyPin>>, config: Config) { 243 fn init<T: Instance>(tx: Option<Peri<'_, AnyPin>>, rx: Option<Peri<'_, AnyPin>>, config: Config) {
236 T::enable_clock(); 244 Self::configure_flexcomm(T::info().fc_reg, T::instance_number());
237 T::reset_flexcomm(); 245 Self::configure_clock::<T>(&config);
238 let source_clock: u32 = T::select_clock(config.baudrate); 246 Self::pin_config::<T>(tx, rx);
239 T::configure_flexcomm(); 247 Self::configure_usart(T::info(), &config);
240 T::tx_pin_config();
241 T::rx_pin_config();
242 Self::set_baudrate(source_clock, config.baudrate);
243 T::configure_usart(config);
244 T::disable_dma();
245 T::enable_usart();
246 } 248 }
247 249
248 fn set_baudrate(source_clock: u32, baudrate: u32) { 250 fn configure_clock<T: Instance>(config: &Config) {
251 // Select source clock
252
253 // Adaptive clock choice based on baud rate
254 // To get the desired baud rate, it is essential to choose the clock bigger than baud rate so that it can be 'chiseled'
255 // There are two types of dividers: integer divider (baud rate generator register and oversample selection value)
256 // and fractional divider (fractional rate divider).
257
258 // By default, oversampling rate is 16 which is an industry standard.
259 // That means 16 clocks are used to deliver the byte to recipient.
260 // In this way the probability of getting correct bytes instead of noise directly increases as oversampling increases as well.
261
262 // Minimum and maximum values were computed taking these formulas into account:
263 // For minimum value, MULT = 0, BRGVAL = 0
264 // For maximum value, MULT = 255, BRGVAL = 255
265 // Flexcomm Interface function clock = (clock selected via FCCLKSEL) / (1 + MULT / DIV)
266 // By default, OSRVAL = 15 (see above)
267 // Baud rate = [FCLK / (OSRVAL+1)] / (BRGVAL + 1)
268 let source_clock = match config.baudrate {
269 750_001..=6_000_000 => {
270 SYSCON
271 .fcclksel(T::instance_number())
272 .modify(|w| w.set_sel(syscon::vals::FcclkselSel::ENUM_0X3)); // 96 MHz
273 96_000_000
274 }
275 1501..=750_000 => {
276 SYSCON
277 .fcclksel(T::instance_number())
278 .modify(|w| w.set_sel(syscon::vals::FcclkselSel::ENUM_0X2)); // 12 MHz
279 12_000_000
280 }
281 121..=1500 => {
282 SYSCON
283 .fcclksel(T::instance_number())
284 .modify(|w| w.set_sel(syscon::vals::FcclkselSel::ENUM_0X4)); // 1 MHz
285 1_000_000
286 }
287 _ => {
288 panic!("{} baudrate is not permitted in this mode", config.baudrate);
289 }
290 };
291 // Calculate MULT and BRG values based on baudrate
292
249 // There are two types of dividers: integer divider (baud rate generator register and oversample selection value) 293 // There are two types of dividers: integer divider (baud rate generator register and oversample selection value)
250 // and fractional divider (fractional rate divider). 294 // and fractional divider (fractional rate divider).
251 // For oversampling, the default is industry standard 16x oversampling, i.e. OSRVAL = 15 295 // For oversampling, the default is industry standard 16x oversampling, i.e. OSRVAL = 15
@@ -274,14 +318,167 @@ impl<'d, T: Instance, M: Mode> Usart<'d, T, M> {
274 // Secondly, MULT is calculated to ultimately 'chisel' the clock to get the baud rate. 318 // Secondly, MULT is calculated to ultimately 'chisel' the clock to get the baud rate.
275 // The deduced formulas are written below. 319 // The deduced formulas are written below.
276 320
277 let brg_value = (source_clock / (16 * baudrate)).min(255); 321 let brg_value = (source_clock / (16 * config.baudrate)).min(255);
278 let raw_clock = source_clock / (16 * brg_value); 322 let raw_clock = source_clock / (16 * brg_value);
279 let mult_value = ((raw_clock * 256 / baudrate) - 256).min(255); 323 let mult_value = ((raw_clock * 256 / config.baudrate) - 256).min(255);
280 T::set_baudrate(mult_value as u8, brg_value as u8); 324
325 // Write values to the registers
326
327 // FCLK = (clock selected via FCCLKSEL) / (1+ MULT / DIV)
328 // Remark: To use the fractional baud rate generator, 0xFF must be wirtten to the DIV value
329 // to yield a denominator vale of 256. All other values are not supported
330 SYSCON.flexfrgctrl(T::instance_number()).modify(|w| {
331 w.set_div(0xFF);
332 w.set_mult(mult_value as u8);
333 });
334
335 // Baud rate = [FCLK / (OSRVAL+1)] / (BRGVAL + 1)
336 // By default, oversampling is 16x, i.e. OSRVAL = 15
337
338 // Typical industry standard USARTs use a 16x oversample clock to transmit and receive
339 // asynchronous data. This is the number of BRG clocks used for one data bit. The
340 // Oversample Select Register (OSR) allows this USART to use a 16x down to a 5x
341 // oversample clock. There is no oversampling in synchronous modes.
342 T::info()
343 .usart_reg
344 .brg()
345 .modify(|w| w.set_brgval((brg_value - 1) as u16));
346 }
347
348 fn pin_config<T: Instance>(tx: Option<Peri<'_, AnyPin>>, rx: Option<Peri<'_, AnyPin>>) {
349 if let Some(tx_pin) = tx {
350 match_iocon!(register, tx_pin.pin_bank(), tx_pin.pin_number(), {
351 register.modify(|w| {
352 w.set_func(T::tx_pin_func());
353 w.set_mode(iocon::vals::PioMode::INACTIVE);
354 w.set_slew(iocon::vals::PioSlew::STANDARD);
355 w.set_invert(false);
356 w.set_digimode(iocon::vals::PioDigimode::DIGITAL);
357 w.set_od(iocon::vals::PioOd::NORMAL);
358 });
359 })
360 }
361
362 if let Some(rx_pin) = rx {
363 match_iocon!(register, rx_pin.pin_bank(), rx_pin.pin_number(), {
364 register.modify(|w| {
365 w.set_func(T::rx_pin_func());
366 w.set_mode(iocon::vals::PioMode::INACTIVE);
367 w.set_slew(iocon::vals::PioSlew::STANDARD);
368 w.set_invert(false);
369 w.set_digimode(iocon::vals::PioDigimode::DIGITAL);
370 w.set_od(iocon::vals::PioOd::NORMAL);
371 });
372 })
373 };
374 }
375
376 fn configure_flexcomm(flexcomm_register: crate::pac::flexcomm::Flexcomm, instance_number: usize) {
377 critical_section::with(|_cs| {
378 if !(SYSCON.ahbclkctrl0().read().iocon()) {
379 SYSCON.ahbclkctrl0().modify(|w| w.set_iocon(true));
380 }
381 });
382 critical_section::with(|_cs| {
383 if !(SYSCON.ahbclkctrl1().read().fc(instance_number)) {
384 SYSCON.ahbclkctrl1().modify(|w| w.set_fc(instance_number, true));
385 }
386 });
387 SYSCON
388 .presetctrl1()
389 .modify(|w| w.set_fc_rst(instance_number, syscon::vals::FcRst::ASSERTED));
390 SYSCON
391 .presetctrl1()
392 .modify(|w| w.set_fc_rst(instance_number, syscon::vals::FcRst::RELEASED));
393 flexcomm_register
394 .pselid()
395 .modify(|w| w.set_persel(flexcomm::vals::Persel::USART));
396 }
397
398 fn configure_usart(info: &'static Info, config: &Config) {
399 let registers = info.usart_reg;
400 // See section 34.6.1
401 registers.cfg().modify(|w| {
402 // LIN break mode enable
403 // Disabled. Break detect and generate is configured for normal operation.
404 w.set_linmode(false);
405 //CTS Enable. Determines whether CTS is used for flow control. CTS can be from the
406 //input pin, or from the USART’s own RTS if loopback mode is enabled.
407 // No flow control. The transmitter does not receive any automatic flow control signal.
408 w.set_ctsen(false);
409 // Selects synchronous or asynchronous operation.
410 w.set_syncen(usart::vals::Syncen::ASYNCHRONOUS_MODE);
411 // Selects the clock polarity and sampling edge of received data in synchronous mode.
412 w.set_clkpol(usart::vals::Clkpol::RISING_EDGE);
413 // Synchronous mode Master select.
414 // When synchronous mode is enabled, the USART is a master.
415 w.set_syncmst(usart::vals::Syncmst::MASTER);
416 // Selects data loopback mode
417 w.set_loop_(usart::vals::Loop::NORMAL);
418 // Output Enable Turnaround time enable for RS-485 operation.
419 // Disabled. If selected by OESEL, the Output Enable signal deasserted at the end of
420 // the last stop bit of a transmission.
421 w.set_oeta(false);
422 // Output enable select.
423 // Standard. The RTS signal is used as the standard flow control function.
424 w.set_oesel(usart::vals::Oesel::STANDARD);
425 // Automatic address matching enable.
426 // Disabled. When addressing is enabled by ADDRDET, address matching is done by
427 // software. This provides the possibility of versatile addressing (e.g. respond to more
428 // than one address)
429 w.set_autoaddr(false);
430 // Output enable polarity.
431 // Low. If selected by OESEL, the output enable is active low.
432 w.set_oepol(usart::vals::Oepol::LOW);
433 });
434
435 // Configurations based on the config written by a user
436 registers.cfg().modify(|w| {
437 w.set_datalen(match config.data_bits {
438 DataBits::DataBits7 => usart::vals::Datalen::BIT_7,
439 DataBits::DataBits8 => usart::vals::Datalen::BIT_8,
440 DataBits::DataBits9 => usart::vals::Datalen::BIT_9,
441 });
442 w.set_paritysel(match config.parity {
443 Parity::ParityNone => usart::vals::Paritysel::NO_PARITY,
444 Parity::ParityEven => usart::vals::Paritysel::EVEN_PARITY,
445 Parity::ParityOdd => usart::vals::Paritysel::ODD_PARITY,
446 });
447 w.set_stoplen(match config.stop_bits {
448 StopBits::Stop1 => usart::vals::Stoplen::BIT_1,
449 StopBits::Stop2 => usart::vals::Stoplen::BITS_2,
450 });
451 w.set_rxpol(match config.invert_rx {
452 false => usart::vals::Rxpol::STANDARD,
453 true => usart::vals::Rxpol::INVERTED,
454 });
455 w.set_txpol(match config.invert_tx {
456 false => usart::vals::Txpol::STANDARD,
457 true => usart::vals::Txpol::INVERTED,
458 });
459 });
460
461 // DMA-related settings
462 registers.fifocfg().modify(|w| {
463 w.set_dmatx(false);
464 w.set_dmatx(false);
465 });
466
467 // Enabling USART
468 registers.fifocfg().modify(|w| {
469 w.set_enabletx(true);
470 w.set_enablerx(true);
471 });
472 registers.cfg().modify(|w| w.set_enable(true));
473
474 // Drain RX FIFO in case it still has some unrelevant data
475 while registers.fifostat().read().rxnotempty() {
476 let _ = registers.fiford().read().0;
477 }
281 } 478 }
282} 479}
283 480
284impl<'d, T: Instance, M: Mode> Usart<'d, T, M> { 481impl<'d, M: Mode> Usart<'d, M> {
285 /// Transmit the provided buffer blocking execution until done. 482 /// Transmit the provided buffer blocking execution until done.
286 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { 483 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
287 self.tx.blocking_write(buffer) 484 self.tx.blocking_write(buffer)
@@ -304,19 +501,19 @@ impl<'d, T: Instance, M: Mode> Usart<'d, T, M> {
304 501
305 /// Split the Usart into a transmitter and receiver, which is particularly 502 /// Split the Usart into a transmitter and receiver, which is particularly
306 /// useful when having two tasks correlating to transmitting and receiving. 503 /// useful when having two tasks correlating to transmitting and receiving.
307 pub fn split(self) -> (UsartTx<'d, T, M>, UsartRx<'d, T, M>) { 504 pub fn split(self) -> (UsartTx<'d, M>, UsartRx<'d, M>) {
308 (self.tx, self.rx) 505 (self.tx, self.rx)
309 } 506 }
310 507
311 /// Split the Usart into a transmitter and receiver by mutable reference, 508 /// Split the Usart into a transmitter and receiver by mutable reference,
312 /// which is particularly useful when having two tasks correlating to 509 /// which is particularly useful when having two tasks correlating to
313 /// transmitting and receiving. 510 /// transmitting and receiving.
314 pub fn split_ref(&mut self) -> (&mut UsartTx<'d, T, M>, &mut UsartRx<'d, T, M>) { 511 pub fn split_ref(&mut self) -> (&mut UsartTx<'d, M>, &mut UsartRx<'d, M>) {
315 (&mut self.tx, &mut self.rx) 512 (&mut self.tx, &mut self.rx)
316 } 513 }
317} 514}
318 515
319impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UsartTx<'d, T, M> { 516impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for UsartTx<'d, M> {
320 type Error = Error; 517 type Error = Error;
321 518
322 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { 519 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
@@ -328,7 +525,7 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for
328 } 525 }
329} 526}
330 527
331impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Usart<'d, T, M> { 528impl<'d, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for Usart<'d, M> {
332 type Error = Error; 529 type Error = Error;
333 530
334 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> { 531 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
@@ -340,11 +537,11 @@ impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::serial::Write<u8> for
340 } 537 }
341} 538}
342 539
343impl<'d, T: Instance> embedded_io::ErrorType for UsartTx<'d, T, Blocking> { 540impl<'d> embedded_io::ErrorType for UsartTx<'d, Blocking> {
344 type Error = Error; 541 type Error = Error;
345} 542}
346 543
347impl<'d, T: Instance> embedded_io::Write for UsartTx<'d, T, Blocking> { 544impl<'d> embedded_io::Write for UsartTx<'d, Blocking> {
348 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 545 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
349 self.blocking_write(buf).map(|_| buf.len()) 546 self.blocking_write(buf).map(|_| buf.len())
350 } 547 }
@@ -354,21 +551,21 @@ impl<'d, T: Instance> embedded_io::Write for UsartTx<'d, T, Blocking> {
354 } 551 }
355} 552}
356 553
357impl<'d, T: Instance> embedded_io::ErrorType for UsartRx<'d, T, Blocking> { 554impl<'d> embedded_io::ErrorType for UsartRx<'d, Blocking> {
358 type Error = Error; 555 type Error = Error;
359} 556}
360 557
361impl<'d, T: Instance> embedded_io::Read for UsartRx<'d, T, Blocking> { 558impl<'d> embedded_io::Read for UsartRx<'d, Blocking> {
362 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { 559 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
363 self.blocking_read(buf).map(|_| buf.len()) 560 self.blocking_read(buf).map(|_| buf.len())
364 } 561 }
365} 562}
366 563
367impl<'d, T: Instance> embedded_io::ErrorType for Usart<'d, T, Blocking> { 564impl<'d> embedded_io::ErrorType for Usart<'d, Blocking> {
368 type Error = Error; 565 type Error = Error;
369} 566}
370 567
371impl<'d, T: Instance> embedded_io::Write for Usart<'d, T, Blocking> { 568impl<'d> embedded_io::Write for Usart<'d, Blocking> {
372 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> { 569 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
373 self.blocking_write(buf).map(|_| buf.len()) 570 self.blocking_write(buf).map(|_| buf.len())
374 } 571 }
@@ -378,468 +575,69 @@ impl<'d, T: Instance> embedded_io::Write for Usart<'d, T, Blocking> {
378 } 575 }
379} 576}
380 577
381impl<'d, T: Instance> embedded_io::Read for Usart<'d, T, Blocking> { 578impl<'d> embedded_io::Read for Usart<'d, Blocking> {
382 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> { 579 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
383 self.blocking_read(buf).map(|_| buf.len()) 580 self.blocking_read(buf).map(|_| buf.len())
384 } 581 }
385} 582}
386 583
387type UsartRegBlock = crate::pac::usart0::RegisterBlock; 584struct Info {
388 585 usart_reg: UsartReg,
389mod sealed { 586 fc_reg: FlexcommReg,
390 use crate::usart::inner::UsartRegBlock; 587}
391 use crate::usart::{Config, Error};
392 pub trait SealedInstance {
393 fn usart_reg() -> &'static UsartRegBlock;
394 fn enable_clock();
395 fn select_clock(baudrate: u32) -> u32;
396 fn configure_flexcomm();
397 fn set_baudrate(mult_value: u8, brg_value: u8);
398 fn reset_flexcomm();
399 fn tx_pin_config();
400 fn rx_pin_config();
401
402 fn configure_usart(config: Config) {
403 // See section 34.6.1
404 Self::usart_reg().cfg.modify(|_, w| {
405 // LIN break mode enable
406 w.linmode()
407 // Disabled. Break detect and generate is configured for normal operation.
408 .disabled()
409 //CTS Enable. Determines whether CTS is used for flow control. CTS can be from the
410 //input pin, or from the USART’s own RTS if loopback mode is enabled.
411 .ctsen()
412 // No flow control. The transmitter does not receive any automatic flow control signal.
413 .disabled()
414 // Selects synchronous or asynchronous operation.
415 .syncen()
416 .asynchronous_mode()
417 // Selects the clock polarity and sampling edge of received data in synchronous mode.
418 .clkpol()
419 .rising_edge()
420 // Synchronous mode Master select.
421 .syncmst()
422 // When synchronous mode is enabled, the USART is a master.
423 .master()
424 // Selects data loopback mode
425 .loop_()
426 // Normal operation
427 .normal()
428 // Output Enable Turnaround time enable for RS-485 operation.
429 .oeta()
430 // Disabled. If selected by OESEL, the Output Enable signal deasserted at the end of
431 // the last stop bit of a transmission.
432 .disabled()
433 // Output enable select.
434 .oesel()
435 // Standard. The RTS signal is used as the standard flow control function.
436 .standard()
437 // Automatic address matching enable.
438 .autoaddr()
439 // Disabled. When addressing is enabled by ADDRDET, address matching is done by
440 // software. This provides the possibility of versatile addressing (e.g. respond to more
441 // than one address)
442 .disabled()
443 // Output enable polarity.
444 .oepol()
445 // Low. If selected by OESEL, the output enable is active low.
446 .low()
447 });
448 588
449 Self::usart_reg().cfg.modify(|_, w| unsafe { 589trait SealedInstance {
450 w.datalen() 590 fn info() -> &'static Info;
451 .bits(config.data_bits.bits()) 591 fn instance_number() -> usize;
452 .paritysel() 592 fn tx_pin_func() -> PioFunc;
453 .bits(config.parity.bits()) 593 fn rx_pin_func() -> PioFunc;
454 .stoplen()
455 .bit(config.stop_bits.bits())
456 .rxpol()
457 .bit(config.invert_rx)
458 .txpol()
459 .bit(config.invert_tx)
460 });
461 }
462 fn disable_dma() {
463 Self::usart_reg()
464 .fifocfg
465 .modify(|_, w| w.dmatx().disabled().dmarx().disabled());
466 }
467 fn enable_usart() {
468 Self::usart_reg()
469 .fifocfg
470 .modify(|_, w| w.enabletx().enabled().enablerx().enabled());
471 Self::usart_reg().cfg.modify(|_, w| w.enable().enabled());
472 while Self::usart_reg().fifostat.read().rxnotempty().bit_is_set() {
473 let _ = Self::usart_reg().fiford.read().bits();
474 }
475 }
476 fn blocking_write(buffer: &[u8]) -> Result<(), Error> {
477 for &b in buffer {
478 while Self::usart_reg().fifostat.read().txnotfull().bit_is_clear() {}
479 Self::usart_reg()
480 .fifowr
481 .modify(|_, w| unsafe { w.txdata().bits(b as u16) });
482 }
483 Ok(())
484 }
485 fn blocking_flush() -> Result<(), Error> {
486 while Self::usart_reg().fifostat.read().txempty().bit_is_clear() {}
487 Ok(())
488 }
489 fn tx_busy() -> bool {
490 Self::usart_reg().fifostat.read().txempty().bit_is_clear()
491 }
492 fn drain_fifo(buffer: &mut [u8]) -> Result<usize, (usize, Error)> {
493 for (i, b) in buffer.iter_mut().enumerate() {
494 while Self::usart_reg().fifostat.read().rxnotempty().bit_is_clear() {}
495
496 if Self::usart_reg().fifostat.read().rxerr().bit_is_set() {
497 return Err((i, Error::Overrun));
498 } else if Self::usart_reg().fifordnopop.read().parityerr().bit_is_set() {
499 return Err((i, Error::Parity));
500 } else if Self::usart_reg().fifordnopop.read().framerr().bit_is_set() {
501 return Err((i, Error::Framing));
502 } else if Self::usart_reg().fifordnopop.read().rxnoise().bit_is_set() {
503 return Err((i, Error::Noise));
504 } else if Self::usart_reg().intstat.read().deltarxbrk().bit_is_set() {
505 return Err((i, Error::Break));
506 }
507 let dr = Self::usart_reg().fiford.read().bits() as u8;
508 *b = dr;
509 }
510 Ok(buffer.len())
511 }
512 }
513} 594}
514 595
515/// UART instance. 596/// UART instance.
516#[allow(private_bounds)] 597#[allow(private_bounds)]
517pub trait Instance: sealed::SealedInstance + PeripheralType {} 598pub trait Instance: SealedInstance + PeripheralType {}
518 599
519#[macro_export]
520macro_rules! impl_instance { 600macro_rules! impl_instance {
521 ( 601 ($inst:ident, $fc:ident, $tx_pin:ident, $rx_pin:ident, $fc_num:expr) => {
522 $inst:ident, 602 impl $crate::usart::inner::SealedInstance for $crate::peripherals::$inst {
523 usart_peripheral: $USARTX:ident, 603 fn info() -> &'static Info {
524 usart_crate: $usartX:ident, 604 static INFO: Info = Info {
525 605 usart_reg: crate::pac::$inst,
526 flexcomm: { 606 fc_reg: crate::pac::$fc,
527 field: $FLEXCOMM_FIELD:ident,
528 clock_field: $FLEXCOMM_CLK_FIELD:ident
529 },
530
531 reset: {
532 bit: $RESET_BIT:ident
533 },
534
535 clock: {
536 sel_field: $CLKSEL_FIELD:ident,
537 frg_field: $FRG_FIELD:ident
538 },
539
540 pins: {
541 tx: $TX_IOCON:ident => $TX_FUNC:expr,
542 rx: $RX_IOCON:ident => $RX_FUNC:expr
543 }
544
545 ) => {
546 impl $crate::usart::SealedInstance for $crate::peripherals::$inst {
547 fn usart_reg() -> &'static UsartRegBlock {
548 unsafe { &*$crate::pac::$USARTX::ptr() }
549 }
550
551 fn enable_clock() {
552 critical_section::with(|_cs| {
553 if syscon_reg().ahbclkctrl0.read().iocon().is_disable() {
554 syscon_reg().ahbclkctrl0.modify(|_, w| w.iocon().enable());
555 }
556 if syscon_reg().ahbclkctrl1.read().$FLEXCOMM_CLK_FIELD().is_disable() {
557 syscon_reg()
558 .ahbclkctrl1
559 .modify(|_, w| w.$FLEXCOMM_CLK_FIELD().enable());
560 }
561 });
562 }
563
564 fn configure_flexcomm() {
565 let flexcomm = unsafe { &*$crate::pac::$FLEXCOMM_FIELD::ptr() };
566 flexcomm.pselid.modify(|_, w| w.persel().usart());
567 }
568
569 fn reset_flexcomm() {
570 syscon_reg().presetctrl1.modify(|_, w| w.$RESET_BIT().set_bit());
571 syscon_reg().presetctrl1.modify(|_, w| w.$RESET_BIT().clear_bit());
572 }
573
574 fn select_clock(baudrate: u32) -> u32 {
575 // Adaptive clock choice based on baud rate
576 // To get the desired baud rate, it is essential to choose the clock bigger than baud rate so that it can be 'chiseled'
577 // There are two types of dividers: integer divider (baud rate generator register and oversample selection value)
578 // and fractional divider (fractional rate divider).
579
580 // By default, oversampling rate is 16 which is an industry standard.
581 // That means 16 clocks are used to deliver the byte to recipient.
582 // In this way the probability of getting correct bytes instead of noise directly increases as oversampling increases as well.
583
584 // Minimum and maximum values were computed taking these formulas into account:
585 // For minimum value, MULT = 0, BRGVAL = 0
586 // For maximum value, MULT = 255, BRGVAL = 255
587 // Flexcomm Interface function clock = (clock selected via FCCLKSEL) / (1 + MULT / DIV)
588 // By default, OSRVAL = 15 (see above)
589 // Baud rate = [FCLK / (OSRVAL+1)] / (BRGVAL + 1)
590 return match baudrate {
591 750_001..=6000000 => {
592 syscon_reg().$CLKSEL_FIELD().write(|w| w.sel().enum_0x3()); // 96 MHz
593 96_000_000
594 }
595 1501..=750_000 => {
596 syscon_reg().$CLKSEL_FIELD().write(|w| w.sel().enum_0x2()); // 12 MHz
597 12_000_000
598 }
599 121..=1500 => {
600 syscon_reg().$CLKSEL_FIELD().write(|w| w.sel().enum_0x4()); // 1 MHz
601 1_000_000
602 }
603 _ => {
604 panic!("{} baudrate is not permitted in this mode", baudrate);
605 }
606 }; 607 };
608 &INFO
607 } 609 }
608 610 #[inline]
609 fn set_baudrate(mult_value: u8, brg_value: u8) { 611 fn instance_number() -> usize {
610 // FCLK = (clock selected via FCCLKSEL) / (1+ MULT / DIV) 612 $fc_num
611 // Remark: To use the fractional baud rate generator, 0xFF must be wirtten to the DIV value
612 // to yield a denominator vale of 256. All other values are not supported
613 syscon_reg()
614 .$FRG_FIELD()
615 .modify(|_, w| unsafe { w.div().bits(0xFF).mult().bits(mult_value as u8) });
616
617 // Baud rate = [FCLK / (OSRVAL+1)] / (BRGVAL + 1)
618 // By default, oversampling is 16x, i.e. OSRVAL = 15
619
620 // Typical industry standard USARTs use a 16x oversample clock to transmit and receive
621 // asynchronous data. This is the number of BRG clocks used for one data bit. The
622 // Oversample Select Register (OSR) allows this USART to use a 16x down to a 5x
623 // oversample clock. There is no oversampling in synchronous modes.
624 Self::usart_reg()
625 .brg
626 .modify(|_, w| unsafe { w.brgval().bits((brg_value - 1) as u16) });
627 } 613 }
628 614 #[inline]
629 fn tx_pin_config() { 615 fn tx_pin_func() -> PioFunc {
630 iocon_reg().$TX_IOCON.modify(|_, w| unsafe { 616 PioFunc::$tx_pin
631 w.func()
632 .bits($TX_FUNC)
633 .digimode()
634 .digital()
635 .slew()
636 .standard()
637 .mode()
638 .inactive()
639 .invert()
640 .disabled()
641 .od()
642 .normal()
643 });
644 } 617 }
645 618 #[inline]
646 fn rx_pin_config() { 619 fn rx_pin_func() -> PioFunc {
647 iocon_reg().$RX_IOCON.modify(|_, w| unsafe { 620 PioFunc::$rx_pin
648 w.func()
649 .bits($RX_FUNC)
650 .digimode()
651 .digital()
652 .slew()
653 .standard()
654 .mode()
655 .inactive()
656 .invert()
657 .disabled()
658 .od()
659 .normal()
660 });
661 } 621 }
662 } 622 }
663
664 impl $crate::usart::Instance for $crate::peripherals::$inst {} 623 impl $crate::usart::Instance for $crate::peripherals::$inst {}
665 }; 624 };
666} 625}
667 626
668impl_instance!(USART0, usart_peripheral: USART0, usart_crate: usart0, 627impl_instance!(USART0, FLEXCOMM0, ALT1, ALT1, 0);
669 flexcomm: { 628impl_instance!(USART1, FLEXCOMM1, ALT2, ALT2, 1);
670 field: FLEXCOMM0, 629impl_instance!(USART2, FLEXCOMM2, ALT1, ALT1, 2);
671 clock_field: fc0 630impl_instance!(USART3, FLEXCOMM3, ALT1, ALT1, 3);
672 }, 631impl_instance!(USART4, FLEXCOMM4, ALT1, ALT2, 4);
673 632impl_instance!(USART5, FLEXCOMM5, ALT3, ALT3, 5);
674 reset: { 633impl_instance!(USART6, FLEXCOMM6, ALT2, ALT2, 6);
675 bit: fc0_rst 634impl_instance!(USART7, FLEXCOMM7, ALT7, ALT7, 7);
676 },
677
678 clock: {
679 sel_field: fcclksel0,
680 frg_field: flexfrg0ctrl
681 },
682
683 pins: {
684 tx: pio1_6 => 1,
685 rx: pio1_5 => 1
686 }
687);
688
689impl_instance!(USART1, usart_peripheral: USART1, usart_crate: usart1,
690 flexcomm: {
691 field: FLEXCOMM1,
692 clock_field: fc1
693 },
694
695 reset: {
696 bit: fc1_rst
697 },
698
699 clock: {
700 sel_field: fcclksel1,
701 frg_field: flexfrg1ctrl
702 },
703
704 pins: {
705 tx: pio1_11 => 2,
706 rx: pio1_10 => 2
707 }
708);
709
710impl_instance!(USART2, usart_peripheral: USART2, usart_crate: usart2,
711 flexcomm: {
712 field: FLEXCOMM2,
713 clock_field: fc2
714 },
715
716 reset: {
717 bit: fc2_rst
718 },
719
720 clock: {
721 sel_field: fcclksel2,
722 frg_field: flexfrg2ctrl
723 },
724
725 pins: {
726 tx: pio0_27 => 1,
727 rx: pio1_24 => 1
728 }
729);
730
731impl_instance!(USART3, usart_peripheral: USART3, usart_crate: usart3,
732 flexcomm: {
733 field: FLEXCOMM3,
734 clock_field: fc3
735 },
736
737 reset: {
738 bit: fc3_rst
739 },
740
741 clock: {
742 sel_field: fcclksel3,
743 frg_field: flexfrg3ctrl
744 },
745
746 pins: {
747 tx: pio0_2 => 1,
748 rx: pio0_3 => 1
749 }
750);
751
752impl_instance!(USART4, usart_peripheral: USART4, usart_crate: usart4,
753 flexcomm: {
754 field: FLEXCOMM4,
755 clock_field: fc4
756 },
757
758 reset: {
759 bit: fc4_rst
760 },
761
762 clock: {
763 sel_field: fcclksel4,
764 frg_field: flexfrg4ctrl
765 },
766
767 pins: {
768 tx: pio0_16 => 1,
769 rx: pio0_5 => 2
770 }
771);
772
773impl_instance!(USART5, usart_peripheral: USART5, usart_crate: usart5,
774 flexcomm: {
775 field: FLEXCOMM5,
776 clock_field: fc5
777 },
778
779 reset: {
780 bit: fc5_rst
781 },
782
783 clock: {
784 sel_field: fcclksel5,
785 frg_field: flexfrg5ctrl
786 },
787
788 pins: {
789 tx: pio0_9 => 3,
790 rx: pio0_8 => 3
791 }
792);
793
794impl_instance!(USART6, usart_peripheral: USART6, usart_crate: usart6,
795 flexcomm: {
796 field: FLEXCOMM6,
797 clock_field: fc6
798 },
799
800 reset: {
801 bit: fc6_rst
802 },
803
804 clock: {
805 sel_field: fcclksel6,
806 frg_field: flexfrg6ctrl
807 },
808
809 pins: {
810 tx: pio1_16 => 2,
811 rx: pio1_13 => 2
812 }
813);
814
815impl_instance!(USART7, usart_peripheral: USART7, usart_crate: usart7,
816 flexcomm: {
817 field: FLEXCOMM7,
818 clock_field: fc7
819 },
820
821 reset: {
822 bit: fc7_rst
823 },
824
825 clock: {
826 sel_field: fcclksel7,
827 frg_field: flexfrg7ctrl
828 },
829
830 pins: {
831 tx: pio0_19 => 7,
832 rx: pio0_20 => 7
833 }
834);
835 635
836/// Trait for TX pins. 636/// Trait for TX pins.
837pub trait TxPin<T: Instance>: crate::gpio::Pin {} 637pub trait TxPin<T: Instance>: crate::gpio::Pin {}
838/// Trait for RX pins. 638/// Trait for RX pins.
839pub trait RxPin<T: Instance>: crate::gpio::Pin {} 639pub trait RxPin<T: Instance>: crate::gpio::Pin {}
840 640
841// TODO: Add RTS, CTS and CLK pin traits
842
843macro_rules! impl_pin { 641macro_rules! impl_pin {
844 ($pin:ident, $instance:ident, Tx) => { 642 ($pin:ident, $instance:ident, Tx) => {
845 impl TxPin<crate::peripherals::$instance> for crate::peripherals::$pin {} 643 impl TxPin<crate::peripherals::$instance> for crate::peripherals::$pin {}
@@ -849,37 +647,19 @@ macro_rules! impl_pin {
849 }; 647 };
850} 648}
851 649
852impl_pin!(PIO1_5, USART0, Rx);
853impl_pin!(PIO1_6, USART0, Tx); 650impl_pin!(PIO1_6, USART0, Tx);
854impl_pin!(PIO1_10, USART1, Rx); 651impl_pin!(PIO1_5, USART0, Rx);
855impl_pin!(PIO1_11, USART1, Tx); 652impl_pin!(PIO1_11, USART1, Tx);
653impl_pin!(PIO1_10, USART1, Rx);
856impl_pin!(PIO0_27, USART2, Tx); 654impl_pin!(PIO0_27, USART2, Tx);
857impl_pin!(PIO1_24, USART2, Rx); 655impl_pin!(PIO1_24, USART2, Rx);
858impl_pin!(PIO0_2, USART3, Tx); 656impl_pin!(PIO0_2, USART3, Tx);
859impl_pin!(PIO0_3, USART3, Rx); 657impl_pin!(PIO0_3, USART3, Rx);
860impl_pin!(PIO0_16, USART4, Tx); 658impl_pin!(PIO0_16, USART4, Tx);
861impl_pin!(PIO0_5, USART4, Rx); 659impl_pin!(PIO0_5, USART4, Rx);
862impl_pin!(PIO0_8, USART5, Rx);
863impl_pin!(PIO0_9, USART5, Tx); 660impl_pin!(PIO0_9, USART5, Tx);
661impl_pin!(PIO0_8, USART5, Rx);
864impl_pin!(PIO1_16, USART6, Tx); 662impl_pin!(PIO1_16, USART6, Tx);
865impl_pin!(PIO1_13, USART6, Rx); 663impl_pin!(PIO1_13, USART6, Rx);
866impl_pin!(PIO0_20, USART7, Rx);
867impl_pin!(PIO0_19, USART7, Tx); 664impl_pin!(PIO0_19, USART7, Tx);
868 665impl_pin!(PIO0_20, USART7, Rx);
869/// Get the SYSCON register block.
870///
871/// # Safety
872/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO
873/// registers are not accessed concurrently by multiple threads.
874pub(crate) fn syscon_reg() -> &'static crate::pac::syscon::RegisterBlock {
875 unsafe { &*crate::pac::SYSCON::ptr() }
876}
877
878/// Get the IOCON register block.
879///
880/// # Safety
881/// Read/Write operations on a single registers are NOT atomic. You must ensure that the GPIO
882/// registers are not accessed concurrently by multiple threads.
883pub(crate) fn iocon_reg() -> &'static crate::pac::iocon::RegisterBlock {
884 unsafe { &*crate::pac::IOCON::ptr() }
885}
diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md
index b50d41dd1..841c9f068 100644
--- a/embassy-rp/CHANGELOG.md
+++ b/embassy-rp/CHANGELOG.md
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
10 10
11- Add PIO SPI 11- Add PIO SPI
12- Add PIO I2S input 12- Add PIO I2S input
13- Add PIO onewire parasite power strong pullup
13 14
14## 0.8.0 - 2025-08-26 15## 0.8.0 - 2025-08-26
15 16
diff --git a/embassy-rp/src/pio_programs/onewire.rs b/embassy-rp/src/pio_programs/onewire.rs
index 287ddab41..980d0fe5f 100644
--- a/embassy-rp/src/pio_programs/onewire.rs
+++ b/embassy-rp/src/pio_programs/onewire.rs
@@ -52,7 +52,8 @@ impl<'a, PIO: Instance> PioOneWireProgram<'a, PIO> {
52 52
53 ; The low pulse was already done, we only need to delay and poll the bit in case we are reading 53 ; The low pulse was already done, we only need to delay and poll the bit in case we are reading
54 write_1: 54 write_1:
55 nop side 0 [( 6 / CLK) - 1] ; Delay before sampling the input pin 55 jmp y--, continue_1 side 0 [( 6 / CLK) - 1] ; Delay before sampling input. Always decrement y
56 continue_1:
56 in pins, 1 side 0 [(48 / CLK) - 1] ; This writes the state of the pin into the ISR 57 in pins, 1 side 0 [(48 / CLK) - 1] ; This writes the state of the pin into the ISR
57 ; Fallthrough 58 ; Fallthrough
58 59
@@ -61,9 +62,24 @@ impl<'a, PIO: Instance> PioOneWireProgram<'a, PIO> {
61 .wrap_target 62 .wrap_target
62 out x, 1 side 0 [(12 / CLK) - 1] ; Stalls if no data available in TX FIFO and OSR 63 out x, 1 side 0 [(12 / CLK) - 1] ; Stalls if no data available in TX FIFO and OSR
63 jmp x--, write_1 side 1 [( 6 / CLK) - 1] ; Do the always low part of a bit, jump to write_1 if we want to write a 1 bit 64 jmp x--, write_1 side 1 [( 6 / CLK) - 1] ; Do the always low part of a bit, jump to write_1 if we want to write a 1 bit
64 in null, 1 side 1 [(54 / CLK) - 1] ; Do the remainder of the low part of a 0 bit 65 jmp y--, continue_0 side 1 [(48 / CLK) - 1] ; Do the remainder of the low part of a 0 bit
65 ; This writes 0 into the ISR so that the shift count stays in sync 66 jmp pullup side 1 [( 6 / CLK) - 1] ; Remain low while jumping
67 continue_0:
68 in null, 1 side 1 [( 6 / CLK) - 1] ; This writes 0 into the ISR so that the shift count stays in sync
66 .wrap 69 .wrap
70
71 ; Assume that strong pullup commands always have MSB (the last bit) = 0,
72 ; since the rising edge can be used to start the operation.
73 ; That's the case for DS18B20 (44h and 48h).
74 pullup:
75 set pins, 1 side 1[( 6 / CLK) - 1] ; Drive pin high output immediately.
76 ; Strong pullup must be within 10us of rise.
77 in null, 1 side 1[( 6 / CLK) - 1] ; Keep ISR in sync. Must occur after the y--.
78 out null, 8 side 1[( 6 / CLK) - 1] ; Wait for write_bytes_pullup() delay to complete.
79 ; The delay is hundreds of ms, so done externally.
80 set pins, 0 side 0[( 6 / CLK) - 1] ; Back to open drain, pin low when driven
81 in null, 8 side 1[( 6 / CLK) - 1] ; Inform write_bytes_pullup() it's ready
82 jmp next_bit side 0[( 6 / CLK) - 1] ; Continue
67 "# 83 "#
68 ); 84 );
69 85
@@ -98,6 +114,7 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> {
98 let mut cfg = Config::default(); 114 let mut cfg = Config::default();
99 cfg.use_program(&program.prg, &[&pin]); 115 cfg.use_program(&program.prg, &[&pin]);
100 cfg.set_in_pins(&[&pin]); 116 cfg.set_in_pins(&[&pin]);
117 cfg.set_set_pins(&[&pin]);
101 118
102 let shift_cfg = ShiftConfig { 119 let shift_cfg = ShiftConfig {
103 auto_fill: true, 120 auto_fill: true,
@@ -146,6 +163,19 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> {
146 163
147 /// Write bytes to the onewire bus 164 /// Write bytes to the onewire bus
148 pub async fn write_bytes(&mut self, data: &[u8]) { 165 pub async fn write_bytes(&mut self, data: &[u8]) {
166 unsafe { self.sm.set_y(u32::MAX as u32) };
167 let (rx, tx) = self.sm.rx_tx();
168 for b in data {
169 tx.wait_push(*b as u32).await;
170
171 // Empty the buffer that is being filled with every write
172 let _ = rx.wait_pull().await;
173 }
174 }
175
176 /// Write bytes to the onewire bus, then apply a strong pullup
177 pub async fn write_bytes_pullup(&mut self, data: &[u8], pullup_time: embassy_time::Duration) {
178 unsafe { self.sm.set_y(data.len() as u32 * 8 - 1) };
149 let (rx, tx) = self.sm.rx_tx(); 179 let (rx, tx) = self.sm.rx_tx();
150 for b in data { 180 for b in data {
151 tx.wait_push(*b as u32).await; 181 tx.wait_push(*b as u32).await;
@@ -153,10 +183,19 @@ impl<'d, PIO: Instance, const SM: usize> PioOneWire<'d, PIO, SM> {
153 // Empty the buffer that is being filled with every write 183 // Empty the buffer that is being filled with every write
154 let _ = rx.wait_pull().await; 184 let _ = rx.wait_pull().await;
155 } 185 }
186
187 // Perform the delay, usually hundreds of ms.
188 embassy_time::Timer::after(pullup_time).await;
189
190 // Signal that delay has completed
191 tx.wait_push(0 as u32).await;
192 // Wait until it's back at 0 low, open drain
193 let _ = rx.wait_pull().await;
156 } 194 }
157 195
158 /// Read bytes from the onewire bus 196 /// Read bytes from the onewire bus
159 pub async fn read_bytes(&mut self, data: &mut [u8]) { 197 pub async fn read_bytes(&mut self, data: &mut [u8]) {
198 unsafe { self.sm.set_y(u32::MAX as u32) };
160 let (rx, tx) = self.sm.rx_tx(); 199 let (rx, tx) = self.sm.rx_tx();
161 for b in data { 200 for b in data {
162 // Write all 1's so that we can read what the device responds 201 // Write all 1's so that we can read what the device responds
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
index aa979e9b8..59328404f 100644
--- a/embassy-stm32/CHANGELOG.md
+++ b/embassy-stm32/CHANGELOG.md
@@ -16,6 +16,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
16- fix: STM32: Prevent dropped DacChannel from disabling Dac peripheral if another DacChannel is still in scope ([#4577](https://github.com/embassy-rs/embassy/pull/4577)) 16- fix: STM32: Prevent dropped DacChannel from disabling Dac peripheral if another DacChannel is still in scope ([#4577](https://github.com/embassy-rs/embassy/pull/4577))
17- feat: Added support for more OctoSPI configurations (e.g. APS6408 RAM) ([#4581](https://github.com/embassy-rs/embassy/pull/4581)) 17- feat: Added support for more OctoSPI configurations (e.g. APS6408 RAM) ([#4581](https://github.com/embassy-rs/embassy/pull/4581))
18- feat: More ADC enums for g0 PAC, API change for over sampling, allow separate sample times 18- feat: More ADC enums for g0 PAC, API change for over sampling, allow separate sample times
19- fix: stm32/usart: fix bug with blocking flush in buffered uart ([#4648](https://github.com/embassy-rs/embassy/pull/4648))
20- fix: stm32/(ospi/hspi/xspi): Fix the alternate bytes register config sticking around for subsequent writes
21- feat: Configurable gpio speed for QSPI
22- feat: derive Clone, Copy and defmt::Format for all *SPI-related configs
23- fix: handle address and data-length errors in OSPI
24- feat: Allow OSPI DMA writes larger than 64kB using chunking
19 25
20## 0.4.0 - 2025-08-26 26## 0.4.0 - 2025-08-26
21 27
diff --git a/embassy-stm32/src/adc/adc4.rs b/embassy-stm32/src/adc/adc4.rs
index 31cbdc0d7..255dc7956 100644
--- a/embassy-stm32/src/adc/adc4.rs
+++ b/embassy-stm32/src/adc/adc4.rs
@@ -83,7 +83,8 @@ pub enum DacChannel {
83} 83}
84 84
85/// Number of samples used for averaging. 85/// Number of samples used for averaging.
86#[derive(Copy, Clone)] 86#[derive(Copy, Clone, Debug)]
87#[cfg_attr(feature = "defmt", derive(defmt::Format))]
87pub enum Averaging { 88pub enum Averaging {
88 Disabled, 89 Disabled,
89 Samples2, 90 Samples2,
diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs
index f5870801e..f2837a8f1 100644
--- a/embassy-stm32/src/adc/c0.rs
+++ b/embassy-stm32/src/adc/c0.rs
@@ -138,7 +138,8 @@ impl<'a> defmt::Format for Prescaler {
138/// Number of samples used for averaging. 138/// Number of samples used for averaging.
139/// TODO: Implement hardware averaging setting. 139/// TODO: Implement hardware averaging setting.
140#[allow(unused)] 140#[allow(unused)]
141#[derive(Copy, Clone)] 141#[derive(Copy, Clone, Debug)]
142#[cfg_attr(feature = "defmt", derive(defmt::Format))]
142pub enum Averaging { 143pub enum Averaging {
143 Disabled, 144 Disabled,
144 Samples2, 145 Samples2,
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index d50fb9001..16063ce4d 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -107,6 +107,8 @@ cfg_if! {
107} 107}
108 108
109/// Number of samples used for averaging. 109/// Number of samples used for averaging.
110#[derive(Copy, Clone, Debug)]
111#[cfg_attr(feature = "defmt", derive(defmt::Format))]
110pub enum Averaging { 112pub enum Averaging {
111 Disabled, 113 Disabled,
112 Samples2, 114 Samples2,
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index b0871019a..b66437e6e 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -142,7 +142,8 @@ impl Prescaler {
142} 142}
143 143
144/// Number of samples used for averaging. 144/// Number of samples used for averaging.
145#[derive(Copy, Clone)] 145#[derive(Copy, Clone, Debug)]
146#[cfg_attr(feature = "defmt", derive(defmt::Format))]
146pub enum Averaging { 147pub enum Averaging {
147 Disabled, 148 Disabled,
148 Samples2, 149 Samples2,
diff --git a/embassy-stm32/src/hspi/mod.rs b/embassy-stm32/src/hspi/mod.rs
index 62bc0e979..95d9e5099 100644
--- a/embassy-stm32/src/hspi/mod.rs
+++ b/embassy-stm32/src/hspi/mod.rs
@@ -86,6 +86,8 @@ impl Default for Config {
86} 86}
87 87
88/// HSPI transfer configuration. 88/// HSPI transfer configuration.
89#[derive(Clone, Copy)]
90#[cfg_attr(feature = "defmt", derive(defmt::Format))]
89pub struct TransferConfig { 91pub struct TransferConfig {
90 /// Instruction width (IMODE) 92 /// Instruction width (IMODE)
91 pub iwidth: HspiWidth, 93 pub iwidth: HspiWidth,
@@ -116,7 +118,7 @@ pub struct TransferConfig {
116 118
117 /// Data width (DMODE) 119 /// Data width (DMODE)
118 pub dwidth: HspiWidth, 120 pub dwidth: HspiWidth,
119 /// Data buffer 121 /// Data Double Transfer rate enable
120 pub ddtr: bool, 122 pub ddtr: bool,
121 123
122 /// Number of dummy cycles (DCYC) 124 /// Number of dummy cycles (DCYC)
@@ -395,11 +397,6 @@ impl<'d, T: Instance, M: PeriMode> Hspi<'d, T, M> {
395 // Configure alternate bytes 397 // Configure alternate bytes
396 if let Some(ab) = command.alternate_bytes { 398 if let Some(ab) = command.alternate_bytes {
397 T::REGS.abr().write(|v| v.set_alternate(ab)); 399 T::REGS.abr().write(|v| v.set_alternate(ab));
398 T::REGS.ccr().modify(|w| {
399 w.set_abmode(command.abwidth.into());
400 w.set_abdtr(command.abdtr);
401 w.set_absize(command.absize.into());
402 })
403 } 400 }
404 401
405 // Configure dummy cycles 402 // Configure dummy cycles
@@ -411,14 +408,14 @@ impl<'d, T: Instance, M: PeriMode> Hspi<'d, T, M> {
411 if let Some(data_length) = data_len { 408 if let Some(data_length) = data_len {
412 T::REGS.dlr().write(|v| { 409 T::REGS.dlr().write(|v| {
413 v.set_dl((data_length - 1) as u32); 410 v.set_dl((data_length - 1) as u32);
414 }) 411 });
415 } else { 412 } else {
416 T::REGS.dlr().write(|v| { 413 T::REGS.dlr().write(|v| {
417 v.set_dl((0) as u32); 414 v.set_dl((0) as u32);
418 }) 415 });
419 } 416 }
420 417
421 // Configure instruction/address/data modes 418 // Configure instruction/address/alternate bytes/data modes
422 T::REGS.ccr().modify(|w| { 419 T::REGS.ccr().modify(|w| {
423 w.set_imode(command.iwidth.into()); 420 w.set_imode(command.iwidth.into());
424 w.set_idtr(command.idtr); 421 w.set_idtr(command.idtr);
@@ -428,6 +425,10 @@ impl<'d, T: Instance, M: PeriMode> Hspi<'d, T, M> {
428 w.set_addtr(command.addtr); 425 w.set_addtr(command.addtr);
429 w.set_adsize(command.adsize.into()); 426 w.set_adsize(command.adsize.into());
430 427
428 w.set_abmode(command.abwidth.into());
429 w.set_abdtr(command.abdtr);
430 w.set_absize(command.absize.into());
431
431 w.set_dmode(command.dwidth.into()); 432 w.set_dmode(command.dwidth.into());
432 w.set_ddtr(command.ddtr); 433 w.set_ddtr(command.ddtr);
433 }); 434 });
diff --git a/embassy-stm32/src/ospi/enums.rs b/embassy-stm32/src/ospi/enums.rs
index 4021f7ce3..4db801752 100644
--- a/embassy-stm32/src/ospi/enums.rs
+++ b/embassy-stm32/src/ospi/enums.rs
@@ -23,6 +23,7 @@ impl Into<u8> for OspiMode {
23/// Ospi lane width 23/// Ospi lane width
24#[allow(dead_code)] 24#[allow(dead_code)]
25#[derive(Copy, Clone)] 25#[derive(Copy, Clone)]
26#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26pub enum OspiWidth { 27pub enum OspiWidth {
27 /// None 28 /// None
28 NONE, 29 NONE,
@@ -71,6 +72,7 @@ impl Into<bool> for FlashSelection {
71#[allow(dead_code)] 72#[allow(dead_code)]
72#[allow(missing_docs)] 73#[allow(missing_docs)]
73#[derive(Copy, Clone)] 74#[derive(Copy, Clone)]
75#[cfg_attr(feature = "defmt", derive(defmt::Format))]
74pub enum WrapSize { 76pub enum WrapSize {
75 None, 77 None,
76 _16Bytes, 78 _16Bytes,
@@ -95,6 +97,7 @@ impl Into<u8> for WrapSize {
95#[allow(missing_docs)] 97#[allow(missing_docs)]
96#[allow(dead_code)] 98#[allow(dead_code)]
97#[derive(Copy, Clone)] 99#[derive(Copy, Clone)]
100#[cfg_attr(feature = "defmt", derive(defmt::Format))]
98pub enum MemoryType { 101pub enum MemoryType {
99 Micron, 102 Micron,
100 Macronix, 103 Macronix,
@@ -120,6 +123,7 @@ impl Into<u8> for MemoryType {
120/// Ospi memory size. 123/// Ospi memory size.
121#[allow(missing_docs)] 124#[allow(missing_docs)]
122#[derive(Copy, Clone)] 125#[derive(Copy, Clone)]
126#[cfg_attr(feature = "defmt", derive(defmt::Format))]
123pub enum MemorySize { 127pub enum MemorySize {
124 _1KiB, 128 _1KiB,
125 _2KiB, 129 _2KiB,
@@ -180,6 +184,7 @@ impl Into<u8> for MemorySize {
180 184
181/// Ospi Address size 185/// Ospi Address size
182#[derive(Copy, Clone)] 186#[derive(Copy, Clone)]
187#[cfg_attr(feature = "defmt", derive(defmt::Format))]
183pub enum AddressSize { 188pub enum AddressSize {
184 /// 8-bit address 189 /// 8-bit address
185 _8Bit, 190 _8Bit,
@@ -205,6 +210,7 @@ impl Into<u8> for AddressSize {
205/// Time the Chip Select line stays high. 210/// Time the Chip Select line stays high.
206#[allow(missing_docs)] 211#[allow(missing_docs)]
207#[derive(Copy, Clone)] 212#[derive(Copy, Clone)]
213#[cfg_attr(feature = "defmt", derive(defmt::Format))]
208pub enum ChipSelectHighTime { 214pub enum ChipSelectHighTime {
209 _1Cycle, 215 _1Cycle,
210 _2Cycle, 216 _2Cycle,
@@ -234,6 +240,7 @@ impl Into<u8> for ChipSelectHighTime {
234/// FIFO threshold. 240/// FIFO threshold.
235#[allow(missing_docs)] 241#[allow(missing_docs)]
236#[derive(Copy, Clone)] 242#[derive(Copy, Clone)]
243#[cfg_attr(feature = "defmt", derive(defmt::Format))]
237pub enum FIFOThresholdLevel { 244pub enum FIFOThresholdLevel {
238 _1Bytes, 245 _1Bytes,
239 _2Bytes, 246 _2Bytes,
@@ -311,6 +318,7 @@ impl Into<u8> for FIFOThresholdLevel {
311/// Dummy cycle count 318/// Dummy cycle count
312#[allow(missing_docs)] 319#[allow(missing_docs)]
313#[derive(Copy, Clone)] 320#[derive(Copy, Clone)]
321#[cfg_attr(feature = "defmt", derive(defmt::Format))]
314pub enum DummyCycles { 322pub enum DummyCycles {
315 _0, 323 _0,
316 _1, 324 _1,
diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs
index 8384f4fc4..d93cecb69 100644
--- a/embassy-stm32/src/ospi/mod.rs
+++ b/embassy-stm32/src/ospi/mod.rs
@@ -23,6 +23,7 @@ use crate::{peripherals, Peri};
23 23
24/// OPSI driver config. 24/// OPSI driver config.
25#[derive(Clone, Copy)] 25#[derive(Clone, Copy)]
26#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26pub struct Config { 27pub struct Config {
27 /// Fifo threshold used by the peripheral to generate the interrupt indicating data 28 /// Fifo threshold used by the peripheral to generate the interrupt indicating data
28 /// or space is available in the FIFO 29 /// or space is available in the FIFO
@@ -30,7 +31,9 @@ pub struct Config {
30 /// Indicates the type of external device connected 31 /// Indicates the type of external device connected
31 pub memory_type: MemoryType, // Need to add an additional enum to provide this public interface 32 pub memory_type: MemoryType, // Need to add an additional enum to provide this public interface
32 /// Defines the size of the external device connected to the OSPI corresponding 33 /// Defines the size of the external device connected to the OSPI corresponding
33 /// to the number of address bits required to access the device 34 /// to the number of address bits required to access the device.
35 /// When using indirect mode, [`TransferConfig::address`] + the length of the data being read
36 /// or written must fit within the configured `device_size`, otherwise an error is returned.
34 pub device_size: MemorySize, 37 pub device_size: MemorySize,
35 /// Sets the minimum number of clock cycles that the chip select signal must be held high 38 /// Sets the minimum number of clock cycles that the chip select signal must be held high
36 /// between commands 39 /// between commands
@@ -83,6 +86,8 @@ impl Default for Config {
83} 86}
84 87
85/// OSPI transfer configuration. 88/// OSPI transfer configuration.
89#[derive(Clone, Copy)]
90#[cfg_attr(feature = "defmt", derive(defmt::Format))]
86pub struct TransferConfig { 91pub struct TransferConfig {
87 /// Instruction width (IMODE) 92 /// Instruction width (IMODE)
88 pub iwidth: OspiWidth, 93 pub iwidth: OspiWidth,
@@ -92,10 +97,11 @@ pub struct TransferConfig {
92 pub isize: AddressSize, 97 pub isize: AddressSize,
93 /// Instruction Double Transfer rate enable 98 /// Instruction Double Transfer rate enable
94 pub idtr: bool, 99 pub idtr: bool,
95
96 /// Address width (ADMODE) 100 /// Address width (ADMODE)
97 pub adwidth: OspiWidth, 101 pub adwidth: OspiWidth,
98 /// Device memory address 102 /// Device memory address.
103 /// In indirect mode, this value + the length of the data being read or written must be within
104 /// configured [`Config::device_size`], otherwise the transfer returns an error.
99 pub address: Option<u32>, 105 pub address: Option<u32>,
100 /// Number of Address Bytes 106 /// Number of Address Bytes
101 pub adsize: AddressSize, 107 pub adsize: AddressSize,
@@ -113,7 +119,7 @@ pub struct TransferConfig {
113 119
114 /// Data width (DMODE) 120 /// Data width (DMODE)
115 pub dwidth: OspiWidth, 121 pub dwidth: OspiWidth,
116 /// Data buffer 122 /// Data Double Transfer rate enable
117 pub ddtr: bool, 123 pub ddtr: bool,
118 124
119 /// Number of dummy cycles (DCYC) 125 /// Number of dummy cycles (DCYC)
@@ -451,11 +457,6 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
451 // Configure alternate bytes 457 // Configure alternate bytes
452 if let Some(ab) = command.alternate_bytes { 458 if let Some(ab) = command.alternate_bytes {
453 T::REGS.abr().write(|v| v.set_alternate(ab)); 459 T::REGS.abr().write(|v| v.set_alternate(ab));
454 T::REGS.ccr().modify(|w| {
455 w.set_abmode(PhaseMode::from_bits(command.abwidth.into()));
456 w.set_abdtr(command.abdtr);
457 w.set_absize(SizeInBits::from_bits(command.absize.into()));
458 })
459 } 460 }
460 461
461 // Configure dummy cycles 462 // Configure dummy cycles
@@ -467,14 +468,14 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
467 if let Some(data_length) = data_len { 468 if let Some(data_length) = data_len {
468 T::REGS.dlr().write(|v| { 469 T::REGS.dlr().write(|v| {
469 v.set_dl((data_length - 1) as u32); 470 v.set_dl((data_length - 1) as u32);
470 }) 471 });
471 } else { 472 } else {
472 T::REGS.dlr().write(|v| { 473 T::REGS.dlr().write(|v| {
473 v.set_dl((0) as u32); 474 v.set_dl((0) as u32);
474 }) 475 });
475 } 476 }
476 477
477 // Configure instruction/address/data/communication modes 478 // Configure instruction/address/alternate bytes/data/communication modes
478 T::REGS.ccr().modify(|w| { 479 T::REGS.ccr().modify(|w| {
479 w.set_imode(PhaseMode::from_bits(command.iwidth.into())); 480 w.set_imode(PhaseMode::from_bits(command.iwidth.into()));
480 w.set_idtr(command.idtr); 481 w.set_idtr(command.idtr);
@@ -484,6 +485,10 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
484 w.set_addtr(command.addtr); 485 w.set_addtr(command.addtr);
485 w.set_adsize(SizeInBits::from_bits(command.adsize.into())); 486 w.set_adsize(SizeInBits::from_bits(command.adsize.into()));
486 487
488 w.set_abmode(PhaseMode::from_bits(command.abwidth.into()));
489 w.set_abdtr(command.abdtr);
490 w.set_absize(SizeInBits::from_bits(command.absize.into()));
491
487 w.set_dmode(PhaseMode::from_bits(command.dwidth.into())); 492 w.set_dmode(PhaseMode::from_bits(command.dwidth.into()));
488 w.set_ddtr(command.ddtr); 493 w.set_ddtr(command.ddtr);
489 494
@@ -491,7 +496,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
491 w.set_sioo(command.sioo); 496 w.set_sioo(command.sioo);
492 }); 497 });
493 498
494 // Set informationrequired to initiate transaction 499 // Set information required to initiate transaction
495 if let Some(instruction) = command.instruction { 500 if let Some(instruction) = command.instruction {
496 if let Some(address) = command.address { 501 if let Some(address) = command.address {
497 T::REGS.ir().write(|v| { 502 T::REGS.ir().write(|v| {
@@ -526,6 +531,18 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
526 } 531 }
527 } 532 }
528 533
534 // The following errors set the TEF flag in OCTOSPI_SR register:
535 // - in indirect or automatic status-polling mode, when a wrong address has been programmed
536 // in OCTOSPI_AR (according to the device size defined by DEVSIZE[4:0])
537 // - in indirect mode, if the address plus the data length exceed the device size: TEF is
538 // set as soon as the access is triggered.
539 if T::REGS.sr().read().tef() {
540 // Clear the TEF register to make it ready for the next transfer.
541 T::REGS.fcr().write(|w| w.set_ctef(true));
542
543 return Err(OspiError::InvalidCommand);
544 }
545
529 Ok(()) 546 Ok(())
530 } 547 }
531 548
@@ -1181,16 +1198,19 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
1181 .cr() 1198 .cr()
1182 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE)); 1199 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE));
1183 1200
1184 let transfer = unsafe { 1201 // TODO: implement this using a LinkedList DMA to offload the whole transfer off the CPU.
1185 self.dma 1202 for chunk in buf.chunks(0xFFFF) {
1186 .as_mut() 1203 let transfer = unsafe {
1187 .unwrap() 1204 self.dma
1188 .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default()) 1205 .as_mut()
1189 }; 1206 .unwrap()
1207 .write(chunk, T::REGS.dr().as_ptr() as *mut W, Default::default())
1208 };
1190 1209
1191 T::REGS.cr().modify(|w| w.set_dmaen(true)); 1210 T::REGS.cr().modify(|w| w.set_dmaen(true));
1192 1211
1193 transfer.blocking_wait(); 1212 transfer.blocking_wait();
1213 }
1194 1214
1195 finish_dma(T::REGS); 1215 finish_dma(T::REGS);
1196 1216
@@ -1251,16 +1271,19 @@ impl<'d, T: Instance> Ospi<'d, T, Async> {
1251 .cr() 1271 .cr()
1252 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE)); 1272 .modify(|v| v.set_fmode(vals::FunctionalMode::INDIRECT_WRITE));
1253 1273
1254 let transfer = unsafe { 1274 // TODO: implement this using a LinkedList DMA to offload the whole transfer off the CPU.
1255 self.dma 1275 for chunk in buf.chunks(0xFFFF) {
1256 .as_mut() 1276 let transfer = unsafe {
1257 .unwrap() 1277 self.dma
1258 .write(buf, T::REGS.dr().as_ptr() as *mut W, Default::default()) 1278 .as_mut()
1259 }; 1279 .unwrap()
1280 .write(chunk, T::REGS.dr().as_ptr() as *mut W, Default::default())
1281 };
1260 1282
1261 T::REGS.cr().modify(|w| w.set_dmaen(true)); 1283 T::REGS.cr().modify(|w| w.set_dmaen(true));
1262 1284
1263 transfer.await; 1285 transfer.await;
1286 }
1264 1287
1265 finish_dma(T::REGS); 1288 finish_dma(T::REGS);
1266 1289
diff --git a/embassy-stm32/src/qspi/enums.rs b/embassy-stm32/src/qspi/enums.rs
index fa5e36d06..8a8420127 100644
--- a/embassy-stm32/src/qspi/enums.rs
+++ b/embassy-stm32/src/qspi/enums.rs
@@ -23,6 +23,7 @@ impl From<QspiMode> for u8 {
23/// QSPI lane width 23/// QSPI lane width
24#[allow(dead_code)] 24#[allow(dead_code)]
25#[derive(Copy, Clone)] 25#[derive(Copy, Clone)]
26#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26pub enum QspiWidth { 27pub enum QspiWidth {
27 /// None 28 /// None
28 NONE, 29 NONE,
@@ -67,6 +68,7 @@ impl From<FlashSelection> for bool {
67/// QSPI memory size. 68/// QSPI memory size.
68#[allow(missing_docs)] 69#[allow(missing_docs)]
69#[derive(Copy, Clone)] 70#[derive(Copy, Clone)]
71#[cfg_attr(feature = "defmt", derive(defmt::Format))]
70pub enum MemorySize { 72pub enum MemorySize {
71 _1KiB, 73 _1KiB,
72 _2KiB, 74 _2KiB,
@@ -127,6 +129,7 @@ impl From<MemorySize> for u8 {
127 129
128/// QSPI Address size 130/// QSPI Address size
129#[derive(Copy, Clone)] 131#[derive(Copy, Clone)]
132#[cfg_attr(feature = "defmt", derive(defmt::Format))]
130pub enum AddressSize { 133pub enum AddressSize {
131 /// 8-bit address 134 /// 8-bit address
132 _8Bit, 135 _8Bit,
@@ -152,6 +155,7 @@ impl From<AddressSize> for u8 {
152/// Time the Chip Select line stays high. 155/// Time the Chip Select line stays high.
153#[allow(missing_docs)] 156#[allow(missing_docs)]
154#[derive(Copy, Clone)] 157#[derive(Copy, Clone)]
158#[cfg_attr(feature = "defmt", derive(defmt::Format))]
155pub enum ChipSelectHighTime { 159pub enum ChipSelectHighTime {
156 _1Cycle, 160 _1Cycle,
157 _2Cycle, 161 _2Cycle,
@@ -181,6 +185,7 @@ impl From<ChipSelectHighTime> for u8 {
181/// FIFO threshold. 185/// FIFO threshold.
182#[allow(missing_docs)] 186#[allow(missing_docs)]
183#[derive(Copy, Clone)] 187#[derive(Copy, Clone)]
188#[cfg_attr(feature = "defmt", derive(defmt::Format))]
184pub enum FIFOThresholdLevel { 189pub enum FIFOThresholdLevel {
185 _1Bytes, 190 _1Bytes,
186 _2Bytes, 191 _2Bytes,
@@ -258,6 +263,7 @@ impl From<FIFOThresholdLevel> for u8 {
258/// Dummy cycle count 263/// Dummy cycle count
259#[allow(missing_docs)] 264#[allow(missing_docs)]
260#[derive(Copy, Clone)] 265#[derive(Copy, Clone)]
266#[cfg_attr(feature = "defmt", derive(defmt::Format))]
261pub enum DummyCycles { 267pub enum DummyCycles {
262 _0, 268 _0,
263 _1, 269 _1,
@@ -334,6 +340,7 @@ impl From<DummyCycles> for u8 {
334 340
335#[allow(missing_docs)] 341#[allow(missing_docs)]
336#[derive(Copy, Clone)] 342#[derive(Copy, Clone)]
343#[cfg_attr(feature = "defmt", derive(defmt::Format))]
337pub enum SampleShifting { 344pub enum SampleShifting {
338 None, 345 None,
339 HalfCycle, 346 HalfCycle,
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs
index c0cd216f0..b03cd9009 100644
--- a/embassy-stm32/src/qspi/mod.rs
+++ b/embassy-stm32/src/qspi/mod.rs
@@ -18,6 +18,7 @@ use crate::{peripherals, Peri};
18 18
19/// QSPI transfer configuration. 19/// QSPI transfer configuration.
20#[derive(Clone, Copy)] 20#[derive(Clone, Copy)]
21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
21pub struct TransferConfig { 22pub struct TransferConfig {
22 /// Instruction width (IMODE) 23 /// Instruction width (IMODE)
23 pub iwidth: QspiWidth, 24 pub iwidth: QspiWidth,
@@ -48,6 +49,8 @@ impl Default for TransferConfig {
48 49
49/// QSPI driver configuration. 50/// QSPI driver configuration.
50#[derive(Clone, Copy)] 51#[derive(Clone, Copy)]
52#[cfg_attr(feature = "defmt", derive(defmt::Format))]
53#[non_exhaustive]
51pub struct Config { 54pub struct Config {
52 /// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen. 55 /// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen.
53 /// If you need other value the whose predefined use `Other` variant. 56 /// If you need other value the whose predefined use `Other` variant.
@@ -62,6 +65,8 @@ pub struct Config {
62 pub cs_high_time: ChipSelectHighTime, 65 pub cs_high_time: ChipSelectHighTime,
63 /// Shift sampling point of input data (none, or half-cycle) 66 /// Shift sampling point of input data (none, or half-cycle)
64 pub sample_shifting: SampleShifting, 67 pub sample_shifting: SampleShifting,
68 /// GPIO Speed
69 pub gpio_speed: Speed,
65} 70}
66 71
67impl Default for Config { 72impl Default for Config {
@@ -73,6 +78,7 @@ impl Default for Config {
73 fifo_threshold: FIFOThresholdLevel::_17Bytes, 78 fifo_threshold: FIFOThresholdLevel::_17Bytes,
74 cs_high_time: ChipSelectHighTime::_5Cycle, 79 cs_high_time: ChipSelectHighTime::_5Cycle,
75 sample_shifting: SampleShifting::None, 80 sample_shifting: SampleShifting::None,
81 gpio_speed: Speed::VeryHigh,
76 } 82 }
77 } 83 }
78} 84}
@@ -286,14 +292,14 @@ impl<'d, T: Instance> Qspi<'d, T, Blocking> {
286 ) -> Self { 292 ) -> Self {
287 Self::new_inner( 293 Self::new_inner(
288 peri, 294 peri,
289 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 295 new_pin!(d0, AfType::output(OutputType::PushPull, config.gpio_speed)),
290 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 296 new_pin!(d1, AfType::output(OutputType::PushPull, config.gpio_speed)),
291 new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 297 new_pin!(d2, AfType::output(OutputType::PushPull, config.gpio_speed)),
292 new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 298 new_pin!(d3, AfType::output(OutputType::PushPull, config.gpio_speed)),
293 new_pin!(sck, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 299 new_pin!(sck, AfType::output(OutputType::PushPull, config.gpio_speed)),
294 new_pin!( 300 new_pin!(
295 nss, 301 nss,
296 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) 302 AfType::output_pull(OutputType::PushPull, config.gpio_speed, Pull::Up)
297 ), 303 ),
298 None, 304 None,
299 config, 305 config,
@@ -314,14 +320,14 @@ impl<'d, T: Instance> Qspi<'d, T, Blocking> {
314 ) -> Self { 320 ) -> Self {
315 Self::new_inner( 321 Self::new_inner(
316 peri, 322 peri,
317 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 323 new_pin!(d0, AfType::output(OutputType::PushPull, config.gpio_speed)),
318 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 324 new_pin!(d1, AfType::output(OutputType::PushPull, config.gpio_speed)),
319 new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 325 new_pin!(d2, AfType::output(OutputType::PushPull, config.gpio_speed)),
320 new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 326 new_pin!(d3, AfType::output(OutputType::PushPull, config.gpio_speed)),
321 new_pin!(sck, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 327 new_pin!(sck, AfType::output(OutputType::PushPull, config.gpio_speed)),
322 new_pin!( 328 new_pin!(
323 nss, 329 nss,
324 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) 330 AfType::output_pull(OutputType::PushPull, config.gpio_speed, Pull::Up)
325 ), 331 ),
326 None, 332 None,
327 config, 333 config,
@@ -345,14 +351,14 @@ impl<'d, T: Instance> Qspi<'d, T, Async> {
345 ) -> Self { 351 ) -> Self {
346 Self::new_inner( 352 Self::new_inner(
347 peri, 353 peri,
348 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 354 new_pin!(d0, AfType::output(OutputType::PushPull, config.gpio_speed)),
349 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 355 new_pin!(d1, AfType::output(OutputType::PushPull, config.gpio_speed)),
350 new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 356 new_pin!(d2, AfType::output(OutputType::PushPull, config.gpio_speed)),
351 new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 357 new_pin!(d3, AfType::output(OutputType::PushPull, config.gpio_speed)),
352 new_pin!(sck, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 358 new_pin!(sck, AfType::output(OutputType::PushPull, config.gpio_speed)),
353 new_pin!( 359 new_pin!(
354 nss, 360 nss,
355 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) 361 AfType::output_pull(OutputType::PushPull, config.gpio_speed, Pull::Up)
356 ), 362 ),
357 new_dma!(dma), 363 new_dma!(dma),
358 config, 364 config,
@@ -374,14 +380,14 @@ impl<'d, T: Instance> Qspi<'d, T, Async> {
374 ) -> Self { 380 ) -> Self {
375 Self::new_inner( 381 Self::new_inner(
376 peri, 382 peri,
377 new_pin!(d0, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 383 new_pin!(d0, AfType::output(OutputType::PushPull, config.gpio_speed)),
378 new_pin!(d1, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 384 new_pin!(d1, AfType::output(OutputType::PushPull, config.gpio_speed)),
379 new_pin!(d2, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 385 new_pin!(d2, AfType::output(OutputType::PushPull, config.gpio_speed)),
380 new_pin!(d3, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 386 new_pin!(d3, AfType::output(OutputType::PushPull, config.gpio_speed)),
381 new_pin!(sck, AfType::output(OutputType::PushPull, Speed::VeryHigh)), 387 new_pin!(sck, AfType::output(OutputType::PushPull, config.gpio_speed)),
382 new_pin!( 388 new_pin!(
383 nss, 389 nss,
384 AfType::output_pull(OutputType::PushPull, Speed::VeryHigh, Pull::Up) 390 AfType::output_pull(OutputType::PushPull, config.gpio_speed, Pull::Up)
385 ), 391 ),
386 new_dma!(dma), 392 new_dma!(dma),
387 config, 393 config,
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index 890c8a80e..c734eed49 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -692,6 +692,8 @@ impl<'d> BufferedUartTx<'d> {
692 fn blocking_write(&self, buf: &[u8]) -> Result<usize, Error> { 692 fn blocking_write(&self, buf: &[u8]) -> Result<usize, Error> {
693 loop { 693 loop {
694 let state = self.state; 694 let state = self.state;
695 state.tx_done.store(false, Ordering::Release);
696
695 let empty = state.tx_buf.is_empty(); 697 let empty = state.tx_buf.is_empty();
696 698
697 let mut tx_writer = unsafe { state.tx_buf.writer() }; 699 let mut tx_writer = unsafe { state.tx_buf.writer() };
@@ -713,7 +715,7 @@ impl<'d> BufferedUartTx<'d> {
713 fn blocking_flush(&self) -> Result<(), Error> { 715 fn blocking_flush(&self) -> Result<(), Error> {
714 loop { 716 loop {
715 let state = self.state; 717 let state = self.state;
716 if state.tx_buf.is_empty() { 718 if state.tx_done.load(Ordering::Acquire) {
717 return Ok(()); 719 return Ok(());
718 } 720 }
719 } 721 }
diff --git a/embassy-stm32/src/xspi/enums.rs b/embassy-stm32/src/xspi/enums.rs
index c96641180..2e510fada 100644
--- a/embassy-stm32/src/xspi/enums.rs
+++ b/embassy-stm32/src/xspi/enums.rs
@@ -22,6 +22,7 @@ impl Into<u8> for XspiMode {
22 22
23/// Xspi lane width 23/// Xspi lane width
24#[derive(Copy, Clone)] 24#[derive(Copy, Clone)]
25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
25pub enum XspiWidth { 26pub enum XspiWidth {
26 /// None 27 /// None
27 NONE, 28 NONE,
@@ -50,6 +51,7 @@ impl Into<u8> for XspiWidth {
50/// Wrap Size 51/// Wrap Size
51#[allow(missing_docs)] 52#[allow(missing_docs)]
52#[derive(Copy, Clone)] 53#[derive(Copy, Clone)]
54#[cfg_attr(feature = "defmt", derive(defmt::Format))]
53pub enum WrapSize { 55pub enum WrapSize {
54 None, 56 None,
55 _16Bytes, 57 _16Bytes,
@@ -73,6 +75,7 @@ impl Into<u8> for WrapSize {
73/// Memory Type 75/// Memory Type
74#[allow(missing_docs)] 76#[allow(missing_docs)]
75#[derive(Copy, Clone)] 77#[derive(Copy, Clone)]
78#[cfg_attr(feature = "defmt", derive(defmt::Format))]
76pub enum MemoryType { 79pub enum MemoryType {
77 Micron, 80 Micron,
78 Macronix, 81 Macronix,
@@ -98,6 +101,7 @@ impl Into<u8> for MemoryType {
98/// Xspi memory size. 101/// Xspi memory size.
99#[allow(missing_docs)] 102#[allow(missing_docs)]
100#[derive(Copy, Clone)] 103#[derive(Copy, Clone)]
104#[cfg_attr(feature = "defmt", derive(defmt::Format))]
101pub enum MemorySize { 105pub enum MemorySize {
102 _1KiB, 106 _1KiB,
103 _2KiB, 107 _2KiB,
@@ -158,6 +162,7 @@ impl Into<u8> for MemorySize {
158 162
159/// Xspi Address size 163/// Xspi Address size
160#[derive(Copy, Clone)] 164#[derive(Copy, Clone)]
165#[cfg_attr(feature = "defmt", derive(defmt::Format))]
161pub enum AddressSize { 166pub enum AddressSize {
162 /// 8-bit address 167 /// 8-bit address
163 _8bit, 168 _8bit,
@@ -183,6 +188,7 @@ impl Into<u8> for AddressSize {
183/// Time the Chip Select line stays high. 188/// Time the Chip Select line stays high.
184#[allow(missing_docs)] 189#[allow(missing_docs)]
185#[derive(Copy, Clone)] 190#[derive(Copy, Clone)]
191#[cfg_attr(feature = "defmt", derive(defmt::Format))]
186pub enum ChipSelectHighTime { 192pub enum ChipSelectHighTime {
187 _1Cycle, 193 _1Cycle,
188 _2Cycle, 194 _2Cycle,
@@ -212,6 +218,7 @@ impl Into<u8> for ChipSelectHighTime {
212/// FIFO threshold. 218/// FIFO threshold.
213#[allow(missing_docs)] 219#[allow(missing_docs)]
214#[derive(Copy, Clone)] 220#[derive(Copy, Clone)]
221#[cfg_attr(feature = "defmt", derive(defmt::Format))]
215pub enum FIFOThresholdLevel { 222pub enum FIFOThresholdLevel {
216 _1Bytes, 223 _1Bytes,
217 _2Bytes, 224 _2Bytes,
@@ -289,6 +296,7 @@ impl Into<u8> for FIFOThresholdLevel {
289/// Dummy cycle count 296/// Dummy cycle count
290#[allow(missing_docs)] 297#[allow(missing_docs)]
291#[derive(Copy, Clone)] 298#[derive(Copy, Clone)]
299#[cfg_attr(feature = "defmt", derive(defmt::Format))]
292pub enum DummyCycles { 300pub enum DummyCycles {
293 _0, 301 _0,
294 _1, 302 _1,
diff --git a/embassy-stm32/src/xspi/mod.rs b/embassy-stm32/src/xspi/mod.rs
index 60ccf3c97..901569f64 100644
--- a/embassy-stm32/src/xspi/mod.rs
+++ b/embassy-stm32/src/xspi/mod.rs
@@ -23,6 +23,7 @@ use crate::{peripherals, Peri};
23 23
24/// XPSI driver config. 24/// XPSI driver config.
25#[derive(Clone, Copy)] 25#[derive(Clone, Copy)]
26#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26pub struct Config { 27pub struct Config {
27 /// Fifo threshold used by the peripheral to generate the interrupt indicating data 28 /// Fifo threshold used by the peripheral to generate the interrupt indicating data
28 /// or space is available in the FIFO 29 /// or space is available in the FIFO
@@ -80,6 +81,8 @@ impl Default for Config {
80} 81}
81 82
82/// XSPI transfer configuration. 83/// XSPI transfer configuration.
84#[derive(Clone, Copy)]
85#[cfg_attr(feature = "defmt", derive(defmt::Format))]
83pub struct TransferConfig { 86pub struct TransferConfig {
84 /// Instruction width (IMODE) 87 /// Instruction width (IMODE)
85 pub iwidth: XspiWidth, 88 pub iwidth: XspiWidth,
@@ -110,7 +113,7 @@ pub struct TransferConfig {
110 113
111 /// Data width (DMODE) 114 /// Data width (DMODE)
112 pub dwidth: XspiWidth, 115 pub dwidth: XspiWidth,
113 /// Data buffer 116 /// Data Double Transfer rate enable
114 pub ddtr: bool, 117 pub ddtr: bool,
115 118
116 /// Number of dummy cycles (DCYC) 119 /// Number of dummy cycles (DCYC)
@@ -424,11 +427,6 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> {
424 // Configure alternate bytes 427 // Configure alternate bytes
425 if let Some(ab) = command.alternate_bytes { 428 if let Some(ab) = command.alternate_bytes {
426 T::REGS.abr().write(|v| v.set_alternate(ab)); 429 T::REGS.abr().write(|v| v.set_alternate(ab));
427 T::REGS.ccr().modify(|w| {
428 w.set_abmode(CcrAbmode::from_bits(command.abwidth.into()));
429 w.set_abdtr(command.abdtr);
430 w.set_absize(CcrAbsize::from_bits(command.absize.into()));
431 })
432 } else { 430 } else {
433 T::REGS.ccr().modify(|w| { 431 T::REGS.ccr().modify(|w| {
434 // disable alternate bytes 432 // disable alternate bytes
@@ -445,14 +443,14 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> {
445 if let Some(data_length) = data_len { 443 if let Some(data_length) = data_len {
446 T::REGS.dlr().write(|v| { 444 T::REGS.dlr().write(|v| {
447 v.set_dl((data_length - 1) as u32); 445 v.set_dl((data_length - 1) as u32);
448 }) 446 });
449 } else { 447 } else {
450 T::REGS.dlr().write(|v| { 448 T::REGS.dlr().write(|v| {
451 v.set_dl((0) as u32); 449 v.set_dl((0) as u32);
452 }) 450 });
453 } 451 }
454 452
455 // Configure instruction/address/data modes 453 // Configure instruction/address/alternate bytes/data modes
456 T::REGS.ccr().modify(|w| { 454 T::REGS.ccr().modify(|w| {
457 w.set_imode(CcrImode::from_bits(command.iwidth.into())); 455 w.set_imode(CcrImode::from_bits(command.iwidth.into()));
458 w.set_idtr(command.idtr); 456 w.set_idtr(command.idtr);
@@ -462,6 +460,10 @@ impl<'d, T: Instance, M: PeriMode> Xspi<'d, T, M> {
462 w.set_addtr(command.addtr); 460 w.set_addtr(command.addtr);
463 w.set_adsize(CcrAdsize::from_bits(command.adsize.into())); 461 w.set_adsize(CcrAdsize::from_bits(command.adsize.into()));
464 462
463 w.set_abmode(CcrAbmode::from_bits(command.abwidth.into()));
464 w.set_abdtr(command.abdtr);
465 w.set_absize(CcrAbsize::from_bits(command.absize.into()));
466
465 w.set_dmode(CcrDmode::from_bits(command.dwidth.into())); 467 w.set_dmode(CcrDmode::from_bits(command.dwidth.into()));
466 w.set_ddtr(command.ddtr); 468 w.set_ddtr(command.ddtr);
467 }); 469 });
diff --git a/embassy-sync/CHANGELOG.md b/embassy-sync/CHANGELOG.md
index a53d5f5b1..242b8b7ab 100644
--- a/embassy-sync/CHANGELOG.md
+++ b/embassy-sync/CHANGELOG.md
@@ -8,6 +8,7 @@ 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- Fix wakers getting dropped by `Signal::reset` 10- Fix wakers getting dropped by `Signal::reset`
11- Remove `Sized` trait bound from `MutexGuard::map`
11 12
12## 0.7.2 - 2025-08-26 13## 0.7.2 - 2025-08-26
13 14
diff --git a/embassy-sync/Cargo.toml b/embassy-sync/Cargo.toml
index 30a27c13f..6494da727 100644
--- a/embassy-sync/Cargo.toml
+++ b/embassy-sync/Cargo.toml
@@ -17,6 +17,8 @@ categories = [
17[package.metadata.embassy] 17[package.metadata.embassy]
18build = [ 18build = [
19 {target = "thumbv6m-none-eabi", features = ["defmt"]}, 19 {target = "thumbv6m-none-eabi", features = ["defmt"]},
20 # Xtensa builds
21 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32s2-none-elf", features = ["defmt"]},
20] 22]
21 23
22[package.metadata.embassy_docs] 24[package.metadata.embassy_docs]
diff --git a/embassy-sync/src/mutex.rs b/embassy-sync/src/mutex.rs
index 4ce6dd987..aea682899 100644
--- a/embassy-sync/src/mutex.rs
+++ b/embassy-sync/src/mutex.rs
@@ -187,7 +187,7 @@ where
187 T: ?Sized, 187 T: ?Sized,
188{ 188{
189 /// Returns a locked view over a portion of the locked data. 189 /// Returns a locked view over a portion of the locked data.
190 pub fn map<U>(this: Self, fun: impl FnOnce(&mut T) -> &mut U) -> MappedMutexGuard<'a, M, U> { 190 pub fn map<U: ?Sized>(this: Self, fun: impl FnOnce(&mut T) -> &mut U) -> MappedMutexGuard<'a, M, U> {
191 let mutex = this.mutex; 191 let mutex = this.mutex;
192 let value = fun(unsafe { &mut *this.mutex.inner.get() }); 192 let value = fun(unsafe { &mut *this.mutex.inner.get() });
193 // Don't run the `drop` method for MutexGuard. The ownership of the underlying 193 // Don't run the `drop` method for MutexGuard. The ownership of the underlying
@@ -279,7 +279,7 @@ where
279 T: ?Sized, 279 T: ?Sized,
280{ 280{
281 /// Returns a locked view over a portion of the locked data. 281 /// Returns a locked view over a portion of the locked data.
282 pub fn map<U>(this: Self, fun: impl FnOnce(&mut T) -> &mut U) -> MappedMutexGuard<'a, M, U> { 282 pub fn map<U: ?Sized>(this: Self, fun: impl FnOnce(&mut T) -> &mut U) -> MappedMutexGuard<'a, M, U> {
283 let state = this.state; 283 let state = this.state;
284 let value = fun(unsafe { &mut *this.value }); 284 let value = fun(unsafe { &mut *this.value });
285 // Don't run the `drop` method for MutexGuard. The ownership of the underlying 285 // Don't run the `drop` method for MutexGuard. The ownership of the underlying
diff --git a/embassy-time-queue-utils/Cargo.toml b/embassy-time-queue-utils/Cargo.toml
index e1abf1cd8..13da62874 100644
--- a/embassy-time-queue-utils/Cargo.toml
+++ b/embassy-time-queue-utils/Cargo.toml
@@ -56,6 +56,9 @@ _generic-queue = []
56build = [ 56build = [
57 {target = "thumbv6m-none-eabi", features = []}, 57 {target = "thumbv6m-none-eabi", features = []},
58 {target = "thumbv6m-none-eabi", features = ["generic-queue-8"]}, 58 {target = "thumbv6m-none-eabi", features = ["generic-queue-8"]},
59 # Xtensa builds
60 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32s2-none-elf", features = []},
61 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32s2-none-elf", features = ["generic-queue-8"]},
59] 62]
60 63
61[package.metadata.embassy_docs] 64[package.metadata.embassy_docs]
diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml
index 6ebf0a468..2d7c3c1fa 100644
--- a/embassy-time/Cargo.toml
+++ b/embassy-time/Cargo.toml
@@ -17,6 +17,8 @@ categories = [
17[package.metadata.embassy] 17[package.metadata.embassy]
18build = [ 18build = [
19 {target = "thumbv6m-none-eabi", features = ["defmt", "defmt-timestamp-uptime", "mock-driver"]}, 19 {target = "thumbv6m-none-eabi", features = ["defmt", "defmt-timestamp-uptime", "mock-driver"]},
20 # Xtensa builds
21 {group = "xtensa", build-std = ["core", "alloc"], target = "xtensa-esp32s2-none-elf", features = ["defmt", "defmt-timestamp-uptime", "mock-driver"]},
20] 22]
21 23
22[package.metadata.embassy_docs] 24[package.metadata.embassy_docs]
diff --git a/embassy-usb-dfu/CHANGELOG.md b/embassy-usb-dfu/CHANGELOG.md
index 466eff211..ef842945d 100644
--- a/embassy-usb-dfu/CHANGELOG.md
+++ b/embassy-usb-dfu/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- Allow enabling the `application` and `dfu` feature at the same time
12
11## 0.2.0 - 2025-08-27 13## 0.2.0 - 2025-08-27
12 14
13- First release with changelog. 15- First release with changelog.
diff --git a/embassy-usb-dfu/src/application.rs b/embassy-usb-dfu/src/application.rs
index 4b7b72073..78eb2c083 100644
--- a/embassy-usb-dfu/src/application.rs
+++ b/embassy-usb-dfu/src/application.rs
@@ -1,3 +1,4 @@
1//! Application part of DFU logic
1use embassy_boot::BlockingFirmwareState; 2use embassy_boot::BlockingFirmwareState;
2use embassy_time::{Duration, Instant}; 3use embassy_time::{Duration, Instant};
3use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; 4use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType};
diff --git a/embassy-usb-dfu/src/dfu.rs b/embassy-usb-dfu/src/dfu.rs
index 9a2f125fb..be28890bb 100644
--- a/embassy-usb-dfu/src/dfu.rs
+++ b/embassy-usb-dfu/src/dfu.rs
@@ -1,3 +1,4 @@
1//! DFU bootloader part of DFU logic
1use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterError}; 2use embassy_boot::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterError};
2use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType}; 3use embassy_usb::control::{InResponse, OutResponse, Recipient, RequestType};
3use embassy_usb::driver::Driver; 4use embassy_usb::driver::Driver;
diff --git a/embassy-usb-dfu/src/lib.rs b/embassy-usb-dfu/src/lib.rs
index 54ffa7276..e9f4278b6 100644
--- a/embassy-usb-dfu/src/lib.rs
+++ b/embassy-usb-dfu/src/lib.rs
@@ -6,21 +6,15 @@ mod fmt;
6pub mod consts; 6pub mod consts;
7 7
8#[cfg(feature = "dfu")] 8#[cfg(feature = "dfu")]
9mod dfu; 9pub mod dfu;
10#[cfg(feature = "dfu")] 10#[cfg(all(feature = "dfu", not(feature = "application")))]
11pub use self::dfu::*; 11pub use self::dfu::*;
12 12
13#[cfg(feature = "application")] 13#[cfg(feature = "application")]
14mod application; 14pub mod application;
15#[cfg(feature = "application")] 15#[cfg(all(feature = "application", not(feature = "dfu")))]
16pub use self::application::*; 16pub use self::application::*;
17 17
18#[cfg(any(
19 all(feature = "dfu", feature = "application"),
20 not(any(feature = "dfu", feature = "application"))
21))]
22compile_error!("usb-dfu must be compiled with exactly one of `dfu`, or `application` features");
23
24/// Provides a platform-agnostic interface for initiating a system reset. 18/// Provides a platform-agnostic interface for initiating a system reset.
25/// 19///
26/// This crate exposes `ResetImmediate` when compiled with cortex-m or esp32c3 support, which immediately issues a 20/// This crate exposes `ResetImmediate` when compiled with cortex-m or esp32c3 support, which immediately issues a
diff --git a/examples/lpc55s69/Cargo.toml b/examples/lpc55s69/Cargo.toml
index 79b27f269..579748595 100644
--- a/examples/lpc55s69/Cargo.toml
+++ b/examples/lpc55s69/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
7publish = false 7publish = false
8 8
9[dependencies] 9[dependencies]
10embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["lpc55", "rt", "defmt", "time-driver-rtc"] } 10embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["lpc55-core0", "rt", "defmt", "time-driver-rtc"] }
11embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } 11embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] }
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", "tick-hz-32_768"] } 13embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768"] }
diff --git a/examples/mspm0c1104/Cargo.toml b/examples/mspm0c1104/Cargo.toml
index 4daddbbb4..21434106a 100644
--- a/examples/mspm0c1104/Cargo.toml
+++ b/examples/mspm0c1104/Cargo.toml
@@ -33,7 +33,6 @@ lto = true
33codegen-units = 1 33codegen-units = 1
34 34
35[package.metadata.embassy] 35[package.metadata.embassy]
36skip = true # TODO: remove when we find a way to decrease the defmt buffer size in ci.
37build = [ 36build = [
38 { target = "thumbv6m-none-eabi", artifact-dir = "out/examples/mspm0c1104" } 37 { target = "thumbv6m-none-eabi", artifact-dir = "out/examples/mspm0c1104", env = { DEFMT_RTT_BUFFER_SIZE = "72" }}
39] 38]
diff --git a/examples/nrf52840-edf/.cargo/config.toml b/examples/nrf52840-edf/.cargo/config.toml
new file mode 100644
index 000000000..e0b9ce59e
--- /dev/null
+++ b/examples/nrf52840-edf/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip nRF52840_xxAA"
4
5[build]
6target = "thumbv7em-none-eabi"
7
8[env]
9DEFMT_LOG = "debug"
diff --git a/examples/nrf52840-edf/Cargo.toml b/examples/nrf52840-edf/Cargo.toml
new file mode 100644
index 000000000..1e8803233
--- /dev/null
+++ b/examples/nrf52840-edf/Cargo.toml
@@ -0,0 +1,27 @@
1[package]
2edition = "2021"
3name = "embassy-nrf52840-edf-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6publish = false
7
8[dependencies]
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"] }
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"] }
13
14defmt = "1.0.1"
15defmt-rtt = "1.0.0"
16
17cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
18cortex-m-rt = "0.7.0"
19panic-probe = { version = "1.0.0", features = ["print-defmt"] }
20
21[profile.release]
22debug = 2
23
24[package.metadata.embassy]
25build = [
26 { target = "thumbv7em-none-eabi", artifact-dir = "out/examples/nrf52840-edf" }
27]
diff --git a/examples/nrf52840-edf/build.rs b/examples/nrf52840-edf/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/nrf52840-edf/build.rs
@@ -0,0 +1,35 @@
1//! This build script copies the `memory.x` file from the crate root into
2//! a directory where the linker can always find it at build time.
3//! For many projects this is optional, as the linker always searches the
4//! project root directory -- wherever `Cargo.toml` is. However, if you
5//! are using a workspace or have a more complicated build setup, this
6//! build script becomes required. Additionally, by requesting that
7//! Cargo re-run the build script whenever `memory.x` is changed,
8//! updating `memory.x` ensures a rebuild of the application with the
9//! new memory settings.
10
11use std::env;
12use std::fs::File;
13use std::io::Write;
14use std::path::PathBuf;
15
16fn main() {
17 // Put `memory.x` in our output directory and ensure it's
18 // on the linker search path.
19 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20 File::create(out.join("memory.x"))
21 .unwrap()
22 .write_all(include_bytes!("memory.x"))
23 .unwrap();
24 println!("cargo:rustc-link-search={}", out.display());
25
26 // By default, Cargo will re-run a build script whenever
27 // any file in the project changes. By specifying `memory.x`
28 // here, we ensure the build script is only re-run when
29 // `memory.x` is changed.
30 println!("cargo:rerun-if-changed=memory.x");
31
32 println!("cargo:rustc-link-arg-bins=--nmagic");
33 println!("cargo:rustc-link-arg-bins=-Tlink.x");
34 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
35}
diff --git a/examples/nrf52840-edf/memory.x b/examples/nrf52840-edf/memory.x
new file mode 100644
index 000000000..15b492bce
--- /dev/null
+++ b/examples/nrf52840-edf/memory.x
@@ -0,0 +1,12 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 FLASH : ORIGIN = 0x00000000, LENGTH = 1024K
5 RAM : ORIGIN = 0x20000000, LENGTH = 256K
6
7 /* These values correspond to the NRF52840 with Softdevices S140 7.3.0 */
8 /*
9 FLASH : ORIGIN = 0x00027000, LENGTH = 868K
10 RAM : ORIGIN = 0x20020000, LENGTH = 128K
11 */
12}
diff --git a/examples/nrf52840-edf/src/bin/basic.rs b/examples/nrf52840-edf/src/bin/basic.rs
new file mode 100644
index 000000000..d888e17d1
--- /dev/null
+++ b/examples/nrf52840-edf/src/bin/basic.rs
@@ -0,0 +1,194 @@
1//! Basic side-by-side example of the Earliest Deadline First scheduler
2//!
3//! This test spawns a number of background "ambient system load" workers
4//! that are constantly working, and runs two sets of trials.
5//!
6//! The first trial runs with no deadline set, so our trial task is at the
7//! same prioritization level as the background worker tasks.
8//!
9//! The second trial sets a deadline, meaning that it will be given higher
10//! scheduling priority than background tasks, that have no deadline set
11
12#![no_std]
13#![no_main]
14
15use core::sync::atomic::{compiler_fence, Ordering};
16
17use defmt::unwrap;
18use embassy_executor::Spawner;
19use embassy_time::{Duration, Instant, Timer};
20use {defmt_rtt as _, panic_probe as _};
21
22#[embassy_executor::main]
23async fn main(spawner: Spawner) {
24 embassy_nrf::init(Default::default());
25
26 // Enable flash cache to remove some flash latency jitter
27 compiler_fence(Ordering::SeqCst);
28 embassy_nrf::pac::NVMC.icachecnf().write(|w| {
29 w.set_cacheen(true);
30 });
31 compiler_fence(Ordering::SeqCst);
32
33 //
34 // Baseline system load tunables
35 //
36
37 // how many load tasks? More load tasks means more tasks contending
38 // for the runqueue
39 let tasks = 32;
40 // how long should each task work for? The longer the working time,
41 // the longer the max jitter possible, even when a task is prioritized,
42 // as EDF is still cooperative and not pre-emptive
43 //
44 // 33 ticks ~= 1ms
45 let work_time_ticks = 33;
46 // what fraction, 1/denominator, should the system be busy?
47 // bigger number means **less** busy
48 //
49 // 2 => 50%
50 // 4 => 25%
51 // 10 => 10%
52 let denominator = 2;
53
54 // Total time window, so each worker is working 1/denominator
55 // amount of the total time
56 let time_window = work_time_ticks * u64::from(tasks) * denominator;
57
58 // Spawn all of our load workers!
59 for i in 0..tasks {
60 spawner.spawn(unwrap!(load_task(i, work_time_ticks, time_window)));
61 }
62
63 // Let all the tasks spin up
64 defmt::println!("Spinning up load tasks...");
65 Timer::after_secs(1).await;
66
67 //
68 // Trial task worker tunables
69 //
70
71 // How many steps should the workers under test run?
72 // More steps means more chances to have to wait for other tasks
73 // in line ahead of us.
74 let num_steps = 100;
75
76 // How many ticks should the worker take working on each step?
77 //
78 // 33 ticks ~= 1ms
79 let work_ticks = 33;
80 // How many ticks should the worker wait on each step?
81 //
82 // 66 ticks ~= 2ms
83 let idle_ticks = 66;
84
85 // How many times to repeat each trial?
86 let trials = 3;
87
88 // The total time a trial would take, in a perfect unloaded system
89 let theoretical = (num_steps * work_ticks) + (num_steps * idle_ticks);
90
91 defmt::println!("");
92 defmt::println!("Starting UNPRIORITIZED worker trials");
93 for _ in 0..trials {
94 //
95 // UNPRIORITIZED worker
96 //
97 defmt::println!("");
98 defmt::println!("Starting unprioritized worker");
99 let start = Instant::now();
100 for _ in 0..num_steps {
101 let now = Instant::now();
102 while now.elapsed().as_ticks() < work_ticks {}
103 Timer::after_ticks(idle_ticks).await;
104 }
105 let elapsed = start.elapsed().as_ticks();
106 defmt::println!(
107 "Trial complete, theoretical ticks: {=u64}, actual ticks: {=u64}",
108 theoretical,
109 elapsed
110 );
111 let ratio = ((elapsed as f32) / (theoretical as f32)) * 100.0;
112 defmt::println!("Took {=f32}% of ideal time", ratio);
113 Timer::after_millis(500).await;
114 }
115
116 Timer::after_secs(1).await;
117
118 defmt::println!("");
119 defmt::println!("Starting PRIORITIZED worker trials");
120 for _ in 0..trials {
121 //
122 // PRIORITIZED worker
123 //
124 defmt::println!("");
125 defmt::println!("Starting prioritized worker");
126 let start = Instant::now();
127 // Set the deadline to ~2x the theoretical time. In practice, setting any deadline
128 // here elevates the current task above all other worker tasks.
129 let meta = embassy_executor::Metadata::for_current_task().await;
130 meta.set_deadline_after(theoretical * 2);
131
132 // Perform the trial
133 for _ in 0..num_steps {
134 let now = Instant::now();
135 while now.elapsed().as_ticks() < work_ticks {}
136 Timer::after_ticks(idle_ticks).await;
137 }
138
139 let elapsed = start.elapsed().as_ticks();
140 defmt::println!(
141 "Trial complete, theoretical ticks: {=u64}, actual ticks: {=u64}",
142 theoretical,
143 elapsed
144 );
145 let ratio = ((elapsed as f32) / (theoretical as f32)) * 100.0;
146 defmt::println!("Took {=f32}% of ideal time", ratio);
147
148 // Unset the deadline, deadlines are not automatically cleared, and if our
149 // deadline is in the past, then we get very high priority!
150 meta.unset_deadline();
151
152 Timer::after_millis(500).await;
153 }
154
155 defmt::println!("");
156 defmt::println!("Trials Complete.");
157}
158
159#[embassy_executor::task(pool_size = 32)]
160async fn load_task(id: u32, ticks_on: u64, ttl_ticks: u64) {
161 let mut last_print = Instant::now();
162 let mut last_tick = last_print;
163 let mut variance = 0;
164 let mut max_variance = 0;
165 loop {
166 let tgt = last_tick + Duration::from_ticks(ttl_ticks);
167 assert!(tgt > Instant::now(), "fell too behind!");
168
169 Timer::at(tgt).await;
170 let now = Instant::now();
171 // How late are we from the target?
172 let var = now.duration_since(tgt).as_ticks();
173 max_variance = max_variance.max(var);
174 variance += var;
175
176 // blocking work
177 while now.elapsed().as_ticks() < ticks_on {}
178
179 if last_print.elapsed() >= Duration::from_secs(1) {
180 defmt::trace!(
181 "Task {=u32} variance ticks (1s): {=u64}, max: {=u64}, act: {=u64}",
182 id,
183 variance,
184 max_variance,
185 ticks_on,
186 );
187 max_variance = 0;
188 variance = 0;
189 last_print = Instant::now();
190 }
191
192 last_tick = tgt;
193 }
194}
diff --git a/examples/nrf52840-rtic/src/bin/blinky.rs b/examples/nrf52840-rtic/src/bin/blinky.rs
index 719e22729..2adac7e0a 100644
--- a/examples/nrf52840-rtic/src/bin/blinky.rs
+++ b/examples/nrf52840-rtic/src/bin/blinky.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use {defmt_rtt as _, panic_probe as _}; 4use {defmt_rtt as _, panic_probe as _};
6 5
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml
index a9339bcd3..452e83b7e 100644
--- a/examples/nrf52840/Cargo.toml
+++ b/examples/nrf52840/Cargo.toml
@@ -10,8 +10,8 @@ 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"] } 13embassy-nrf = { version = "0.7.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"] } 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"] }
17embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } 17embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
diff --git a/examples/nrf52840/src/bin/sixlowpan.rs b/examples/nrf52840/src/bin/sixlowpan.rs
new file mode 100644
index 000000000..00a597366
--- /dev/null
+++ b/examples/nrf52840/src/bin/sixlowpan.rs
@@ -0,0 +1,120 @@
1#![no_std]
2#![no_main]
3
4use core::net::Ipv6Addr;
5
6use defmt::{info, unwrap, warn};
7use embassy_executor::Spawner;
8use embassy_net::udp::{PacketMetadata, UdpMetadata, UdpSocket};
9use embassy_net::{IpAddress, IpEndpoint, IpListenEndpoint, Ipv6Cidr, StackResources, StaticConfigV6};
10use embassy_nrf::config::{Config, HfclkSource};
11use embassy_nrf::rng::Rng;
12use embassy_nrf::{bind_interrupts, embassy_net_802154_driver as net, peripherals, radio};
13use embassy_time::Delay;
14use embedded_hal_async::delay::DelayNs;
15use static_cell::StaticCell;
16use {defmt_rtt as _, panic_probe as _};
17
18bind_interrupts!(struct Irqs {
19 RADIO => radio::InterruptHandler<peripherals::RADIO>;
20 RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>;
21});
22
23#[embassy_executor::task]
24async fn ieee802154_task(runner: net::Runner<'static, peripherals::RADIO>) -> ! {
25 runner.run().await
26}
27
28#[embassy_executor::task]
29async fn net_task(mut runner: embassy_net::Runner<'static, net::Device<'static>>) -> ! {
30 runner.run().await
31}
32
33#[embassy_executor::main]
34async fn main(spawner: Spawner) {
35 let mut config = Config::default();
36 // Necessary to run the radio nrf52840 v1.11 5.4.1
37 config.hfclk_source = HfclkSource::ExternalXtal;
38 let p = embassy_nrf::init(config);
39
40 let mac_addr: [u8; 8] = [2, 3, 4, 5, 6, 7, 8, 9];
41 static NRF802154_STATE: StaticCell<net::State<20, 20>> = StaticCell::new();
42 let (device, runner) = net::new(mac_addr, p.RADIO, Irqs, NRF802154_STATE.init(net::State::new()))
43 .await
44 .unwrap();
45
46 spawner.spawn(unwrap!(ieee802154_task(runner)));
47
48 // Swap these when flashing a second board
49 let peer = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xd701, 0xda3f, 0x3955, 0x82a4);
50 let local = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xd701, 0xda3f, 0x3955, 0x82a5);
51
52 let config = embassy_net::Config::ipv6_static(StaticConfigV6 {
53 address: Ipv6Cidr::new(local, 64),
54 gateway: None,
55 dns_servers: Default::default(),
56 });
57
58 // Generate random seed
59 let mut rng = Rng::new(p.RNG, Irqs);
60 let mut seed = [0; 8];
61 rng.blocking_fill_bytes(&mut seed);
62 let seed = u64::from_le_bytes(seed);
63
64 // Init network stack
65 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
66 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
67
68 spawner.spawn(unwrap!(net_task(runner)));
69
70 let mut rx_buffer = [0; 2096];
71 let mut tx_buffer = [0; 2096];
72 let mut tx_m_buffer = [PacketMetadata::EMPTY; 5];
73 let mut rx_m_buffer = [PacketMetadata::EMPTY; 5];
74
75 let mut delay = Delay;
76 loop {
77 let mut socket = UdpSocket::new(
78 stack,
79 &mut tx_m_buffer,
80 &mut rx_buffer,
81 &mut rx_m_buffer,
82 &mut tx_buffer,
83 );
84 socket
85 .bind(IpListenEndpoint {
86 addr: Some(IpAddress::Ipv6(local)),
87 port: 1234,
88 })
89 .unwrap();
90 let rep = UdpMetadata {
91 endpoint: IpEndpoint {
92 addr: IpAddress::Ipv6(peer),
93 port: 1234,
94 },
95 local_address: Some(IpAddress::Ipv6(local)),
96 meta: Default::default(),
97 };
98
99 info!("Listening on {:?} UDP:1234...", local);
100
101 let mut recv_buf = [0; 12];
102 loop {
103 delay.delay_ms(2000).await;
104 if socket.may_recv() {
105 let n = match socket.recv_from(&mut recv_buf).await {
106 Ok((0, _)) => panic!(),
107 Ok((n, _)) => n,
108 Err(e) => {
109 warn!("read error: {:?}", e);
110 break;
111 }
112 };
113 info!("Received {:02x}", &recv_buf[..n]);
114 }
115
116 info!("Sending");
117 socket.send_to(b"Hello World", rep).await.unwrap();
118 }
119 }
120}
diff --git a/examples/rp/src/bin/ethernet_w55rp20_tcp_server.rs b/examples/rp/src/bin/ethernet_w55rp20_tcp_server.rs
new file mode 100644
index 000000000..f51df2df9
--- /dev/null
+++ b/examples/rp/src/bin/ethernet_w55rp20_tcp_server.rs
@@ -0,0 +1,155 @@
1//! This example implements a TCP echo server on port 1234 and using DHCP.
2//! Send it some data, you should see it echoed back and printed in the console.
3//!
4//! Example written for the [`WIZnet W55RP20-EVB-Pico`](https://docs.wiznet.io/Product/ioNIC/W55RP20/w55rp20-evb-pico) board.
5//! Note: the W55RP20 is a single package that contains both a RP2040 and the Wiznet W5500 ethernet
6//! controller
7
8#![no_std]
9#![no_main]
10
11use defmt::*;
12use embassy_executor::Spawner;
13use embassy_futures::yield_now;
14use embassy_net::{Stack, StackResources};
15use embassy_net_wiznet::chip::W5500;
16use embassy_net_wiznet::*;
17use embassy_rp::clocks::RoscRng;
18use embassy_rp::gpio::{Input, Level, Output, Pull};
19use embassy_rp::peripherals::PIO0;
20use embassy_rp::pio_programs::spi::Spi;
21use embassy_rp::spi::{Async, Config as SpiConfig};
22use embassy_rp::{bind_interrupts, pio};
23use embassy_time::{Delay, Duration};
24use embedded_hal_bus::spi::ExclusiveDevice;
25use embedded_io_async::Write;
26use static_cell::StaticCell;
27use {defmt_rtt as _, panic_probe as _};
28
29bind_interrupts!(struct Irqs {
30 PIO0_IRQ_0 => pio::InterruptHandler<PIO0>;
31});
32
33#[embassy_executor::task]
34async fn ethernet_task(
35 runner: Runner<
36 'static,
37 W5500,
38 ExclusiveDevice<Spi<'static, PIO0, 0, Async>, Output<'static>, Delay>,
39 Input<'static>,
40 Output<'static>,
41 >,
42) -> ! {
43 runner.run().await
44}
45
46#[embassy_executor::task]
47async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
48 runner.run().await
49}
50
51#[embassy_executor::main]
52async fn main(spawner: Spawner) {
53 let p = embassy_rp::init(Default::default());
54 let mut rng = RoscRng;
55 let mut led = Output::new(p.PIN_19, Level::Low);
56
57 // The W55RP20 uses a PIO unit for SPI communication, once the SPI bus has been formed using a
58 // PIO statemachine everything else is generally unchanged from the other examples that use the W5500
59 let mosi = p.PIN_23;
60 let miso = p.PIN_22;
61 let clk = p.PIN_21;
62
63 let pio::Pio { mut common, sm0, .. } = pio::Pio::new(p.PIO0, Irqs);
64
65 // Construct an SPI driver backed by a PIO state machine
66 let mut spi_cfg = SpiConfig::default();
67 spi_cfg.frequency = 12_500_000; // The PIO SPI program is much less stable than the actual SPI
68 // peripheral, use higher speeds at your peril
69 let spi = Spi::new(&mut common, sm0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, spi_cfg);
70
71 // Further control pins
72 let cs = Output::new(p.PIN_20, Level::High);
73 let w5500_int = Input::new(p.PIN_24, Pull::Up);
74 let w5500_reset = Output::new(p.PIN_25, Level::High);
75
76 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
77 static STATE: StaticCell<State<8, 8>> = StaticCell::new();
78 let state = STATE.init(State::<8, 8>::new());
79 let (device, runner) = embassy_net_wiznet::new(
80 mac_addr,
81 state,
82 ExclusiveDevice::new(spi, cs, Delay),
83 w5500_int,
84 w5500_reset,
85 )
86 .await
87 .unwrap();
88 spawner.spawn(unwrap!(ethernet_task(runner)));
89
90 // Generate random seed
91 let seed = rng.next_u64();
92
93 // Init network stack
94 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
95 let (stack, runner) = embassy_net::new(
96 device,
97 embassy_net::Config::dhcpv4(Default::default()),
98 RESOURCES.init(StackResources::new()),
99 seed,
100 );
101
102 // Launch network task
103 spawner.spawn(unwrap!(net_task(runner)));
104
105 info!("Waiting for DHCP...");
106 let cfg = wait_for_config(stack).await;
107 let local_addr = cfg.address.address();
108 info!("IP address: {:?}", local_addr);
109
110 let mut rx_buffer = [0; 4096];
111 let mut tx_buffer = [0; 4096];
112 let mut buf = [0; 4096];
113 loop {
114 let mut socket = embassy_net::tcp::TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
115 socket.set_timeout(Some(Duration::from_secs(10)));
116
117 led.set_low();
118 info!("Listening on TCP:1234...");
119 if let Err(e) = socket.accept(1234).await {
120 warn!("accept error: {:?}", e);
121 continue;
122 }
123 info!("Received connection from {:?}", socket.remote_endpoint());
124 led.set_high();
125
126 loop {
127 let n = match socket.read(&mut buf).await {
128 Ok(0) => {
129 warn!("read EOF");
130 break;
131 }
132 Ok(n) => n,
133 Err(e) => {
134 warn!("{:?}", e);
135 break;
136 }
137 };
138 info!("rxd {}", core::str::from_utf8(&buf[..n]).unwrap());
139
140 if let Err(e) = socket.write_all(&buf[..n]).await {
141 warn!("write error: {:?}", e);
142 break;
143 }
144 }
145 }
146}
147
148async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 {
149 loop {
150 if let Some(config) = stack.config_v4() {
151 return config.clone();
152 }
153 yield_now().await;
154 }
155}
diff --git a/examples/rp/src/bin/pio_onewire.rs b/examples/rp/src/bin/pio_onewire.rs
index 379e2b8f9..102f13c45 100644
--- a/examples/rp/src/bin/pio_onewire.rs
+++ b/examples/rp/src/bin/pio_onewire.rs
@@ -1,4 +1,5 @@
1//! This example shows how you can use PIO to read one or more `DS18B20` one-wire temperature sensors. 1//! This example shows how you can use PIO to read one or more `DS18B20` one-wire temperature sensors.
2//! This uses externally powered sensors. For parasite power, see the pio_onewire_parasite.rs example.
2 3
3#![no_std] 4#![no_std]
4#![no_main] 5#![no_main]
diff --git a/examples/rp/src/bin/pio_onewire_parasite.rs b/examples/rp/src/bin/pio_onewire_parasite.rs
new file mode 100644
index 000000000..fd076dee0
--- /dev/null
+++ b/examples/rp/src/bin/pio_onewire_parasite.rs
@@ -0,0 +1,89 @@
1//! This example shows how you can use PIO to read one or more `DS18B20`
2//! one-wire temperature sensors using parasite power.
3//! It applies a strong pullup during conversion, see "Powering the DS18B20" in the datasheet.
4//! For externally powered sensors, use the pio_onewire.rs example.
5
6#![no_std]
7#![no_main]
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::bind_interrupts;
11use embassy_rp::peripherals::PIO0;
12use embassy_rp::pio::{InterruptHandler, Pio};
13use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram, PioOneWireSearch};
14use embassy_time::Duration;
15use heapless::Vec;
16use {defmt_rtt as _, panic_probe as _};
17
18bind_interrupts!(struct Irqs {
19 PIO0_IRQ_0 => InterruptHandler<PIO0>;
20});
21
22#[embassy_executor::main]
23async fn main(_spawner: Spawner) {
24 let p = embassy_rp::init(Default::default());
25 let mut pio = Pio::new(p.PIO0, Irqs);
26
27 let prg = PioOneWireProgram::new(&mut pio.common);
28 let mut onewire = PioOneWire::new(&mut pio.common, pio.sm0, p.PIN_2, &prg);
29
30 info!("Starting onewire search");
31
32 let mut devices = Vec::<u64, 10>::new();
33 let mut search = PioOneWireSearch::new();
34 for _ in 0..10 {
35 if !search.is_finished() {
36 if let Some(address) = search.next(&mut onewire).await {
37 if crc8(&address.to_le_bytes()) == 0 {
38 info!("Found address: {:x}", address);
39 let _ = devices.push(address);
40 } else {
41 warn!("Found invalid address: {:x}", address);
42 }
43 }
44 }
45 }
46
47 info!("Search done, found {} devices", devices.len());
48
49 loop {
50 // Read all devices one by one
51 for device in &devices {
52 onewire.reset().await;
53 onewire.write_bytes(&[0x55]).await; // Match rom
54 onewire.write_bytes(&device.to_le_bytes()).await;
55 // 750 ms delay required for default 12-bit resolution.
56 onewire.write_bytes_pullup(&[0x44], Duration::from_millis(750)).await;
57
58 onewire.reset().await;
59 onewire.write_bytes(&[0x55]).await; // Match rom
60 onewire.write_bytes(&device.to_le_bytes()).await;
61 onewire.write_bytes(&[0xBE]).await; // Read scratchpad
62
63 let mut data = [0; 9];
64 onewire.read_bytes(&mut data).await;
65 if crc8(&data) == 0 {
66 let temp = ((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.;
67 info!("Read device {:x}: {} deg C", device, temp);
68 } else {
69 warn!("Reading device {:x} failed. {:02x}", device, data);
70 }
71 }
72 }
73}
74
75fn crc8(data: &[u8]) -> u8 {
76 let mut crc = 0;
77 for b in data {
78 let mut data_byte = *b;
79 for _ in 0..8 {
80 let temp = (crc ^ data_byte) & 0x01;
81 crc >>= 1;
82 if temp != 0 {
83 crc ^= 0x8C;
84 }
85 data_byte >>= 1;
86 }
87 }
88 crc
89}
diff --git a/examples/rp235x/src/bin/pio_onewire.rs b/examples/rp235x/src/bin/pio_onewire.rs
index 991510851..102f13c45 100644
--- a/examples/rp235x/src/bin/pio_onewire.rs
+++ b/examples/rp235x/src/bin/pio_onewire.rs
@@ -1,4 +1,5 @@
1//! This example shows how you can use PIO to read a `DS18B20` one-wire temperature sensor. 1//! This example shows how you can use PIO to read one or more `DS18B20` one-wire temperature sensors.
2//! This uses externally powered sensors. For parasite power, see the pio_onewire_parasite.rs example.
2 3
3#![no_std] 4#![no_std]
4#![no_main] 5#![no_main]
@@ -6,9 +7,10 @@ use defmt::*;
6use embassy_executor::Spawner; 7use embassy_executor::Spawner;
7use embassy_rp::bind_interrupts; 8use embassy_rp::bind_interrupts;
8use embassy_rp::peripherals::PIO0; 9use embassy_rp::peripherals::PIO0;
9use embassy_rp::pio::{self, InterruptHandler, Pio}; 10use embassy_rp::pio::{InterruptHandler, Pio};
10use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram}; 11use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram, PioOneWireSearch};
11use embassy_time::Timer; 12use embassy_time::Timer;
13use heapless::Vec;
12use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
13 15
14bind_interrupts!(struct Irqs { 16bind_interrupts!(struct Irqs {
@@ -21,63 +23,66 @@ async fn main(_spawner: Spawner) {
21 let mut pio = Pio::new(p.PIO0, Irqs); 23 let mut pio = Pio::new(p.PIO0, Irqs);
22 24
23 let prg = PioOneWireProgram::new(&mut pio.common); 25 let prg = PioOneWireProgram::new(&mut pio.common);
24 let onewire = PioOneWire::new(&mut pio.common, pio.sm0, p.PIN_2, &prg); 26 let mut onewire = PioOneWire::new(&mut pio.common, pio.sm0, p.PIN_2, &prg);
25 27
26 let mut sensor = Ds18b20::new(onewire); 28 info!("Starting onewire search");
27 29
28 loop { 30 let mut devices = Vec::<u64, 10>::new();
29 sensor.start().await; // Start a new measurement 31 let mut search = PioOneWireSearch::new();
30 Timer::after_secs(1).await; // Allow 1s for the measurement to finish 32 for _ in 0..10 {
31 match sensor.temperature().await { 33 if !search.is_finished() {
32 Ok(temp) => info!("temp = {:?} deg C", temp), 34 if let Some(address) = search.next(&mut onewire).await {
33 _ => error!("sensor error"), 35 if crc8(&address.to_le_bytes()) == 0 {
36 info!("Found addres: {:x}", address);
37 let _ = devices.push(address);
38 } else {
39 warn!("Found invalid address: {:x}", address);
40 }
41 }
34 } 42 }
35 Timer::after_secs(1).await;
36 } 43 }
37}
38 44
39/// DS18B20 temperature sensor driver 45 info!("Search done, found {} devices", devices.len());
40pub struct Ds18b20<'d, PIO: pio::Instance, const SM: usize> {
41 wire: PioOneWire<'d, PIO, SM>,
42}
43 46
44impl<'d, PIO: pio::Instance, const SM: usize> Ds18b20<'d, PIO, SM> { 47 loop {
45 pub fn new(wire: PioOneWire<'d, PIO, SM>) -> Self { 48 onewire.reset().await;
46 Self { wire } 49 // Skip rom and trigger conversion, we can trigger all devices on the bus immediately
47 } 50 onewire.write_bytes(&[0xCC, 0x44]).await;
48 51
49 /// Calculate CRC8 of the data 52 Timer::after_secs(1).await; // Allow 1s for the measurement to finish
50 fn crc8(data: &[u8]) -> u8 { 53
51 let mut temp; 54 // Read all devices one by one
52 let mut data_byte; 55 for device in &devices {
53 let mut crc = 0; 56 onewire.reset().await;
54 for b in data { 57 onewire.write_bytes(&[0x55]).await; // Match rom
55 data_byte = *b; 58 onewire.write_bytes(&device.to_le_bytes()).await;
56 for _ in 0..8 { 59 onewire.write_bytes(&[0xBE]).await; // Read scratchpad
57 temp = (crc ^ data_byte) & 0x01; 60
58 crc >>= 1; 61 let mut data = [0; 9];
59 if temp != 0 { 62 onewire.read_bytes(&mut data).await;
60 crc ^= 0x8C; 63 if crc8(&data) == 0 {
61 } 64 let temp = ((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.;
62 data_byte >>= 1; 65 info!("Read device {:x}: {} deg C", device, temp);
66 } else {
67 warn!("Reading device {:x} failed", device);
63 } 68 }
64 } 69 }
65 crc 70 Timer::after_secs(1).await;
66 }
67
68 /// Start a new measurement. Allow at least 1000ms before getting `temperature`.
69 pub async fn start(&mut self) {
70 self.wire.write_bytes(&[0xCC, 0x44]).await;
71 } 71 }
72}
72 73
73 /// Read the temperature. Ensure >1000ms has passed since `start` before calling this. 74fn crc8(data: &[u8]) -> u8 {
74 pub async fn temperature(&mut self) -> Result<f32, ()> { 75 let mut crc = 0;
75 self.wire.write_bytes(&[0xCC, 0xBE]).await; 76 for b in data {
76 let mut data = [0; 9]; 77 let mut data_byte = *b;
77 self.wire.read_bytes(&mut data).await; 78 for _ in 0..8 {
78 match Self::crc8(&data) == 0 { 79 let temp = (crc ^ data_byte) & 0x01;
79 true => Ok(((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.), 80 crc >>= 1;
80 false => Err(()), 81 if temp != 0 {
82 crc ^= 0x8C;
83 }
84 data_byte >>= 1;
81 } 85 }
82 } 86 }
87 crc
83} 88}
diff --git a/examples/rp235x/src/bin/pio_onewire_parasite.rs b/examples/rp235x/src/bin/pio_onewire_parasite.rs
new file mode 100644
index 000000000..fd076dee0
--- /dev/null
+++ b/examples/rp235x/src/bin/pio_onewire_parasite.rs
@@ -0,0 +1,89 @@
1//! This example shows how you can use PIO to read one or more `DS18B20`
2//! one-wire temperature sensors using parasite power.
3//! It applies a strong pullup during conversion, see "Powering the DS18B20" in the datasheet.
4//! For externally powered sensors, use the pio_onewire.rs example.
5
6#![no_std]
7#![no_main]
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::bind_interrupts;
11use embassy_rp::peripherals::PIO0;
12use embassy_rp::pio::{InterruptHandler, Pio};
13use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram, PioOneWireSearch};
14use embassy_time::Duration;
15use heapless::Vec;
16use {defmt_rtt as _, panic_probe as _};
17
18bind_interrupts!(struct Irqs {
19 PIO0_IRQ_0 => InterruptHandler<PIO0>;
20});
21
22#[embassy_executor::main]
23async fn main(_spawner: Spawner) {
24 let p = embassy_rp::init(Default::default());
25 let mut pio = Pio::new(p.PIO0, Irqs);
26
27 let prg = PioOneWireProgram::new(&mut pio.common);
28 let mut onewire = PioOneWire::new(&mut pio.common, pio.sm0, p.PIN_2, &prg);
29
30 info!("Starting onewire search");
31
32 let mut devices = Vec::<u64, 10>::new();
33 let mut search = PioOneWireSearch::new();
34 for _ in 0..10 {
35 if !search.is_finished() {
36 if let Some(address) = search.next(&mut onewire).await {
37 if crc8(&address.to_le_bytes()) == 0 {
38 info!("Found address: {:x}", address);
39 let _ = devices.push(address);
40 } else {
41 warn!("Found invalid address: {:x}", address);
42 }
43 }
44 }
45 }
46
47 info!("Search done, found {} devices", devices.len());
48
49 loop {
50 // Read all devices one by one
51 for device in &devices {
52 onewire.reset().await;
53 onewire.write_bytes(&[0x55]).await; // Match rom
54 onewire.write_bytes(&device.to_le_bytes()).await;
55 // 750 ms delay required for default 12-bit resolution.
56 onewire.write_bytes_pullup(&[0x44], Duration::from_millis(750)).await;
57
58 onewire.reset().await;
59 onewire.write_bytes(&[0x55]).await; // Match rom
60 onewire.write_bytes(&device.to_le_bytes()).await;
61 onewire.write_bytes(&[0xBE]).await; // Read scratchpad
62
63 let mut data = [0; 9];
64 onewire.read_bytes(&mut data).await;
65 if crc8(&data) == 0 {
66 let temp = ((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.;
67 info!("Read device {:x}: {} deg C", device, temp);
68 } else {
69 warn!("Reading device {:x} failed. {:02x}", device, data);
70 }
71 }
72 }
73}
74
75fn crc8(data: &[u8]) -> u8 {
76 let mut crc = 0;
77 for b in data {
78 let mut data_byte = *b;
79 for _ in 0..8 {
80 let temp = (crc ^ data_byte) & 0x01;
81 crc >>= 1;
82 if temp != 0 {
83 crc ^= 0x8C;
84 }
85 data_byte >>= 1;
86 }
87 }
88 crc
89}
diff --git a/examples/stm32f7/src/bin/qspi.rs b/examples/stm32f7/src/bin/qspi.rs
index ab29ddeff..80652b865 100644
--- a/examples/stm32f7/src/bin/qspi.rs
+++ b/examples/stm32f7/src/bin/qspi.rs
@@ -273,14 +273,14 @@ async fn main(_spawner: Spawner) -> ! {
273 let p = embassy_stm32::init(config); 273 let p = embassy_stm32::init(config);
274 info!("Embassy initialized"); 274 info!("Embassy initialized");
275 275
276 let config = QspiCfg { 276 let mut config = QspiCfg::default();
277 memory_size: MemorySize::_8MiB, 277 config.memory_size = MemorySize::_8MiB;
278 address_size: AddressSize::_24bit, 278 config.address_size = AddressSize::_24bit;
279 prescaler: 16, 279 config.prescaler = 16;
280 cs_high_time: ChipSelectHighTime::_1Cycle, 280 config.cs_high_time = ChipSelectHighTime::_1Cycle;
281 fifo_threshold: FIFOThresholdLevel::_16Bytes, 281 config.fifo_threshold = FIFOThresholdLevel::_16Bytes;
282 sample_shifting: SampleShifting::None, 282 config.sample_shifting = SampleShifting::None;
283 }; 283
284 let driver = Qspi::new_bank1( 284 let driver = Qspi::new_bank1(
285 p.QUADSPI, p.PF8, p.PF9, p.PE2, p.PF6, p.PF10, p.PB10, p.DMA2_CH7, config, 285 p.QUADSPI, p.PF8, p.PF9, p.PE2, p.PF6, p.PF10, p.PB10, p.DMA2_CH7, config,
286 ); 286 );
diff --git a/examples/stm32h742/src/bin/qspi.rs b/examples/stm32h742/src/bin/qspi.rs
index 50e37ec52..9e79d7089 100644
--- a/examples/stm32h742/src/bin/qspi.rs
+++ b/examples/stm32h742/src/bin/qspi.rs
@@ -266,14 +266,14 @@ async fn main(_spawner: Spawner) -> ! {
266 let p = embassy_stm32::init(config); 266 let p = embassy_stm32::init(config);
267 info!("Embassy initialized"); 267 info!("Embassy initialized");
268 268
269 let config = QspiCfg { 269 let mut config = QspiCfg::default();
270 memory_size: MemorySize::_8MiB, 270 config.memory_size = MemorySize::_8MiB;
271 address_size: AddressSize::_24bit, 271 config.address_size = AddressSize::_24bit;
272 prescaler: 16, 272 config.prescaler = 16;
273 cs_high_time: ChipSelectHighTime::_1Cycle, 273 config.cs_high_time = ChipSelectHighTime::_1Cycle;
274 fifo_threshold: FIFOThresholdLevel::_16Bytes, 274 config.fifo_threshold = FIFOThresholdLevel::_16Bytes;
275 sample_shifting: SampleShifting::None, 275 config.sample_shifting = SampleShifting::None;
276 }; 276
277 let driver = Qspi::new_blocking_bank1(p.QUADSPI, p.PD11, p.PD12, p.PE2, p.PD13, p.PB2, p.PB10, config); 277 let driver = Qspi::new_blocking_bank1(p.QUADSPI, p.PD11, p.PD12, p.PE2, p.PD13, p.PB2, p.PB10, config);
278 let mut flash = FlashMemory::new(driver); 278 let mut flash = FlashMemory::new(driver);
279 let flash_id = flash.read_id(); 279 let flash_id = flash.read_id();
diff --git a/examples/stm32l432/src/bin/qspi_mmap.rs b/examples/stm32l432/src/bin/qspi_mmap.rs
index 075458fe5..feabdd532 100644
--- a/examples/stm32l432/src/bin/qspi_mmap.rs
+++ b/examples/stm32l432/src/bin/qspi_mmap.rs
@@ -246,14 +246,14 @@ const MEMORY_ADDR: u32 = 0x00000000 as u32;
246async fn main(_spawner: Spawner) { 246async fn main(_spawner: Spawner) {
247 let p = embassy_stm32::init(Default::default()); 247 let p = embassy_stm32::init(Default::default());
248 248
249 let config = qspi::Config { 249 let mut config = qspi::Config::default();
250 memory_size: MemorySize::_16MiB, 250 config.memory_size = MemorySize::_16MiB;
251 address_size: AddressSize::_24bit, 251 config.address_size = AddressSize::_24bit;
252 prescaler: 200, 252 config.prescaler = 200;
253 cs_high_time: ChipSelectHighTime::_1Cycle, 253 config.cs_high_time = ChipSelectHighTime::_1Cycle;
254 fifo_threshold: FIFOThresholdLevel::_16Bytes, 254 config.fifo_threshold = FIFOThresholdLevel::_16Bytes;
255 sample_shifting: SampleShifting::None, 255 config.sample_shifting = SampleShifting::None;
256 }; 256
257 let driver = qspi::Qspi::new_bank1(p.QUADSPI, p.PB1, p.PB0, p.PA7, p.PA6, p.PA3, p.PA2, p.DMA2_CH7, config); 257 let driver = qspi::Qspi::new_bank1(p.QUADSPI, p.PB1, p.PB0, p.PA7, p.PA6, p.PA3, p.PA2, p.DMA2_CH7, config);
258 let mut flash = FlashMemory::new(driver); 258 let mut flash = FlashMemory::new(driver);
259 let mut wr_buf = [0u8; 256]; 259 let mut wr_buf = [0u8; 256];