aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.github/ci/test.sh2
-rwxr-xr-xci-nightly.sh9
-rwxr-xr-xci-xtensa.sh15
-rwxr-xr-xci.sh16
-rw-r--r--docs/examples/basic/Cargo.toml2
-rw-r--r--docs/pages/new_project.adoc4
-rw-r--r--embassy-executor/CHANGELOG.md4
-rw-r--r--embassy-executor/Cargo.toml6
-rw-r--r--embassy-executor/src/arch/avr.rs4
-rw-r--r--embassy-executor/src/arch/cortex_m.rs6
-rw-r--r--embassy-executor/src/arch/riscv32.rs4
-rw-r--r--embassy-executor/src/arch/spin.rs4
-rw-r--r--embassy-executor/src/arch/std.rs4
-rw-r--r--embassy-executor/src/arch/wasm.rs4
-rw-r--r--embassy-executor/src/raw/mod.rs197
-rw-r--r--embassy-executor/src/raw/state_atomics.rs30
-rw-r--r--embassy-executor/src/raw/state_atomics_arm.rs27
-rw-r--r--embassy-executor/src/raw/state_critical_section.rs20
-rw-r--r--embassy-executor/src/raw/timer_queue.rs91
-rw-r--r--embassy-executor/src/raw/trace.rs22
-rw-r--r--embassy-executor/tests/test.rs7
-rw-r--r--embassy-nrf/Cargo.toml3
-rw-r--r--embassy-nrf/src/time_driver.rs194
-rw-r--r--embassy-rp/Cargo.toml3
-rw-r--r--embassy-rp/src/time_driver.rs174
-rw-r--r--embassy-stm32/Cargo.toml3
-rw-r--r--embassy-stm32/src/low_power.rs3
-rw-r--r--embassy-stm32/src/time_driver.rs210
-rw-r--r--embassy-time-driver/CHANGELOG.md15
-rw-r--r--embassy-time-driver/src/lib.rs215
-rw-r--r--embassy-time-queue-driver/CHANGELOG.md15
-rw-r--r--embassy-time-queue-driver/Cargo.toml32
-rw-r--r--embassy-time-queue-driver/src/lib.rs75
-rw-r--r--embassy-time-queue-driver/src/queue_generic.rs146
-rw-r--r--embassy-time-queue-driver/src/queue_integrated.rs90
-rw-r--r--embassy-time/CHANGELOG.md5
-rw-r--r--embassy-time/Cargo.toml24
-rw-r--r--embassy-time/src/driver_mock.rs146
-rw-r--r--embassy-time/src/driver_std.rs208
-rw-r--r--embassy-time/src/driver_wasm.rs142
-rw-r--r--embassy-time/src/lib.rs2
-rw-r--r--embassy-time/src/queue_generic.rs346
-rw-r--r--examples/boot/application/nrf/Cargo.toml2
-rw-r--r--examples/boot/application/rp/Cargo.toml2
-rw-r--r--examples/boot/application/stm32f3/Cargo.toml2
-rw-r--r--examples/boot/application/stm32f7/Cargo.toml2
-rw-r--r--examples/boot/application/stm32h7/Cargo.toml2
-rw-r--r--examples/boot/application/stm32l0/Cargo.toml2
-rw-r--r--examples/boot/application/stm32l1/Cargo.toml2
-rw-r--r--examples/boot/application/stm32l4/Cargo.toml2
-rw-r--r--examples/boot/application/stm32wb-dfu/Cargo.toml2
-rw-r--r--examples/boot/application/stm32wl/Cargo.toml2
-rw-r--r--examples/nrf-rtos-trace/Cargo.toml2
-rw-r--r--examples/nrf51/Cargo.toml2
-rw-r--r--examples/nrf52810/Cargo.toml2
-rw-r--r--examples/nrf52840-rtic/Cargo.toml3
-rw-r--r--examples/nrf52840/Cargo.toml2
-rw-r--r--examples/nrf5340/Cargo.toml2
-rw-r--r--examples/nrf54l15/Cargo.toml2
-rw-r--r--examples/nrf9151/ns/Cargo.toml2
-rw-r--r--examples/nrf9151/s/Cargo.toml2
-rw-r--r--examples/nrf9160/Cargo.toml2
-rw-r--r--examples/rp/Cargo.toml2
-rw-r--r--examples/rp23/Cargo.toml2
-rw-r--r--examples/std/Cargo.toml2
-rw-r--r--examples/stm32c0/Cargo.toml2
-rw-r--r--examples/stm32f0/Cargo.toml2
-rw-r--r--examples/stm32f1/Cargo.toml2
-rw-r--r--examples/stm32f2/Cargo.toml2
-rw-r--r--examples/stm32f3/Cargo.toml2
-rw-r--r--examples/stm32f334/Cargo.toml2
-rw-r--r--examples/stm32f4/Cargo.toml2
-rw-r--r--examples/stm32f469/Cargo.toml2
-rw-r--r--examples/stm32f7/Cargo.toml2
-rw-r--r--examples/stm32g0/Cargo.toml2
-rw-r--r--examples/stm32g4/Cargo.toml2
-rw-r--r--examples/stm32h5/Cargo.toml2
-rw-r--r--examples/stm32h7/Cargo.toml2
-rw-r--r--examples/stm32h723/Cargo.toml2
-rw-r--r--examples/stm32h735/Cargo.toml2
-rw-r--r--examples/stm32h755cm4/Cargo.toml2
-rw-r--r--examples/stm32h755cm7/Cargo.toml2
-rw-r--r--examples/stm32h7b0/Cargo.toml2
-rw-r--r--examples/stm32h7rs/Cargo.toml2
-rw-r--r--examples/stm32l0/Cargo.toml2
-rw-r--r--examples/stm32l1/Cargo.toml2
-rw-r--r--examples/stm32l4/Cargo.toml2
-rw-r--r--examples/stm32l5/Cargo.toml2
-rw-r--r--examples/stm32u0/Cargo.toml2
-rw-r--r--examples/stm32u5/Cargo.toml2
-rw-r--r--examples/stm32wb/Cargo.toml2
-rw-r--r--examples/stm32wba/Cargo.toml2
-rw-r--r--examples/stm32wl/Cargo.toml2
-rw-r--r--examples/wasm/Cargo.toml2
-rw-r--r--tests/nrf/Cargo.toml2
-rw-r--r--tests/rp/Cargo.toml2
-rw-r--r--tests/stm32/Cargo.toml2
97 files changed, 1012 insertions, 1628 deletions
diff --git a/.github/ci/test.sh b/.github/ci/test.sh
index 0fe088bfe..0fd6820d2 100755
--- a/.github/ci/test.sh
+++ b/.github/ci/test.sh
@@ -17,7 +17,7 @@ cargo test --manifest-path ./embassy-futures/Cargo.toml
17cargo test --manifest-path ./embassy-sync/Cargo.toml 17cargo test --manifest-path ./embassy-sync/Cargo.toml
18cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml 18cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml
19cargo test --manifest-path ./embassy-hal-internal/Cargo.toml 19cargo test --manifest-path ./embassy-hal-internal/Cargo.toml
20cargo test --manifest-path ./embassy-time/Cargo.toml --features generic-queue,mock-driver 20cargo test --manifest-path ./embassy-time/Cargo.toml --features mock-driver,embassy-time-queue-driver/generic-queue-8
21cargo test --manifest-path ./embassy-time-driver/Cargo.toml 21cargo test --manifest-path ./embassy-time-driver/Cargo.toml
22 22
23cargo test --manifest-path ./embassy-boot/Cargo.toml 23cargo test --manifest-path ./embassy-boot/Cargo.toml
diff --git a/ci-nightly.sh b/ci-nightly.sh
index bdb364f53..1b69cc18e 100755
--- a/ci-nightly.sh
+++ b/ci-nightly.sh
@@ -13,20 +13,13 @@ cargo batch \
13 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,log \ 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 \ 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 \ 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,integrated-timers \ 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 \ 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,integrated-timers \
19 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread \ 18 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread \
20 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,integrated-timers \
21 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt \ 19 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt \
22 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt,integrated-timers \
23 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt \ 20 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt \
24 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \
25 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32 \ 21 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32 \
26 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,integrated-timers \
27 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread \ 22 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread \
28 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread,integrated-timers \
29 --- build --release --manifest-path examples/nrf52840-rtic/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840-rtic \ 23 --- build --release --manifest-path examples/nrf52840-rtic/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840-rtic \
30 24
31cargo build --release --manifest-path embassy-executor/Cargo.toml --target avr-unknown-gnu-atmega328 -Z build-std=core,alloc --features nightly,arch-avr,avr-device/atmega328p 25cargo build --release --manifest-path embassy-executor/Cargo.toml --target avr-unknown-gnu-atmega328 -Z build-std=core,alloc --features nightly,arch-avr,avr-device/atmega328p
32cargo build --release --manifest-path embassy-executor/Cargo.toml --target avr-unknown-gnu-atmega328 -Z build-std=core,alloc --features nightly,arch-avr,integrated-timers,avr-device/atmega328p
diff --git a/ci-xtensa.sh b/ci-xtensa.sh
index 32d362def..056e85d48 100755
--- a/ci-xtensa.sh
+++ b/ci-xtensa.sh
@@ -14,17 +14,16 @@ cargo batch \
14 --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features log \ 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 \ 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 \ 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,integrated-timers \ 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,integrated-timers \ 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,integrated-timers \ 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 \ 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,integrated-timers \
22 --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin,rtos-trace \ 21 --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin,rtos-trace \
23 --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin,integrated-timers,rtos-trace \
24 --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin,executor-thread \ 22 --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin,executor-thread \
25 --- build --release --manifest-path embassy-executor/Cargo.toml --target xtensa-esp32-none-elf --features arch-spin,executor-thread,integrated-timers \
26 --- build --release --manifest-path embassy-sync/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt \ 23 --- build --release --manifest-path embassy-sync/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt \
27 --- build --release --manifest-path embassy-time/Cargo.toml --target xtensa-esp32s2-none-elf --features defmt,defmt-timestamp-uptime,generic-queue-8,mock-driver \ 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-driver/Cargo.toml --target xtensa-esp32s2-none-elf \
26 --- build --release --manifest-path embassy-time-queue-driver/Cargo.toml --target xtensa-esp32s2-none-elf --features generic-queue-8 \
28 --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet,packet-trace \ 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 \
29 --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,multicast,medium-ethernet \ 28 --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,multicast,medium-ethernet \
30 --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \ 29 --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \
@@ -36,4 +35,4 @@ cargo batch \
36 --- build --release --manifest-path embassy-net/Cargo.toml --target xtensa-esp32-none-elf --features defmt,tcp,udp,dns,proto-ipv4,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 \
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 \ 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 \
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 \ 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 \
39 --- 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 \ \ No newline at end of file 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 307e268c4..6b523193c 100755
--- a/ci.sh
+++ b/ci.sh
@@ -29,23 +29,18 @@ cargo batch \
29 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features log \ 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 \ 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 \ 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,integrated-timers \ 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 \ 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,integrated-timers \
35 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,rtos-trace \ 34 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,rtos-trace \
36 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,integrated-timers,rtos-trace \
37 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread \ 35 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread \
38 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread,integrated-timers \
39 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-interrupt \ 36 --- 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-interrupt,integrated-timers \
41 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread,executor-interrupt \ 37 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread,executor-interrupt \
42 --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \
43 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32 \ 38 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32 \
44 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,integrated-timers \
45 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,executor-thread \ 39 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,executor-thread \
46 --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,executor-thread,integrated-timers \
47 --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features defmt \ 40 --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features defmt \
48 --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features defmt,defmt-timestamp-uptime,generic-queue-8,mock-driver \ 41 --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features defmt,defmt-timestamp-uptime,mock-driver \
42 --- build --release --manifest-path embassy-time-queue-driver/Cargo.toml --target thumbv6m-none-eabi \
43 --- build --release --manifest-path embassy-time-queue-driver/Cargo.toml --target thumbv6m-none-eabi --features generic-queue-8 \
49 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet,packet-trace \ 44 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet,packet-trace \
50 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,multicast,medium-ethernet \ 45 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,multicast,medium-ethernet \
51 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \ 46 --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \
@@ -307,6 +302,9 @@ rm out/tests/stm32wb55rg/wpan_ble
307# unstable, I think it's running out of RAM? 302# unstable, I think it's running out of RAM?
308rm out/tests/stm32f207zg/eth 303rm out/tests/stm32f207zg/eth
309 304
305# temporarily disabled, hard faults for unknown reasons
306rm out/tests/stm32f207zg/usart_rx_ringbuffered
307
310# doesn't work, gives "noise error", no idea why. usart_dma does pass. 308# doesn't work, gives "noise error", no idea why. usart_dma does pass.
311rm out/tests/stm32u5a5zj/usart 309rm out/tests/stm32u5a5zj/usart
312 310
diff --git a/docs/examples/basic/Cargo.toml b/docs/examples/basic/Cargo.toml
index d46431b9a..daf83873d 100644
--- a/docs/examples/basic/Cargo.toml
+++ b/docs/examples/basic/Cargo.toml
@@ -6,7 +6,7 @@ version = "0.1.0"
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7 7
8[dependencies] 8[dependencies]
9embassy-executor = { version = "0.6.3", path = "../../../embassy-executor", features = ["defmt", "integrated-timers", "arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.6.3", path = "../../../embassy-executor", features = ["defmt", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt"] } 10embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt"] }
11embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } 11embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] }
12 12
diff --git a/docs/pages/new_project.adoc b/docs/pages/new_project.adoc
index f8dd848be..63340016b 100644
--- a/docs/pages/new_project.adoc
+++ b/docs/pages/new_project.adoc
@@ -80,7 +80,7 @@ At the time of writing, embassy is already published to crates.io. Therefore, de
80---- 80----
81[dependencies] 81[dependencies]
82embassy-stm32 = { version = "0.1.0", features = ["defmt", "time-driver-any", "stm32g474re", "memory-x", "unstable-pac", "exti"] } 82embassy-stm32 = { version = "0.1.0", features = ["defmt", "time-driver-any", "stm32g474re", "memory-x", "unstable-pac", "exti"] }
83embassy-executor = { version = "0.6.3", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 83embassy-executor = { version = "0.6.3", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt"] }
84embassy-time = { version = "0.3.2", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 84embassy-time = { version = "0.3.2", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
85---- 85----
86 86
@@ -100,7 +100,7 @@ An example Cargo.toml file might look as follows:
100---- 100----
101[dependencies] 101[dependencies]
102embassy-stm32 = {version = "0.1.0", features = ["defmt", "time-driver-any", "stm32g474re", "memory-x", "unstable-pac", "exti"]} 102embassy-stm32 = {version = "0.1.0", features = ["defmt", "time-driver-any", "stm32g474re", "memory-x", "unstable-pac", "exti"]}
103embassy-executor = { version = "0.3.3", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 103embassy-executor = { version = "0.3.3", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt"] }
104embassy-time = { version = "0.2", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 104embassy-time = { version = "0.2", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
105 105
106[patch.crates-io] 106[patch.crates-io]
diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md
index 00b1bef28..068156210 100644
--- a/embassy-executor/CHANGELOG.md
+++ b/embassy-executor/CHANGELOG.md
@@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7 7
8## Unreleased 8## Unreleased
9 9
10- `raw::Executor` now has an `fn initialize` that must be called once before starting to poll it. 10- embassy-executor no longer provides an `embassy-time-queue-driver` implementation
11- Added `TaskRef::executor` to obtain a reference to a task's executor
12- integrated-timers are no longer processed when polling the executor.
11 13
12## 0.6.3 - 2024-11-12 14## 0.6.3 - 2024-11-12
13 15
diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml
index 0a5360e5d..60fe7087a 100644
--- a/embassy-executor/Cargo.toml
+++ b/embassy-executor/Cargo.toml
@@ -35,7 +35,6 @@ rtos-trace = { version = "0.1.3", optional = true }
35 35
36embassy-executor-macros = { version = "0.6.2", path = "../embassy-executor-macros" } 36embassy-executor-macros = { version = "0.6.2", path = "../embassy-executor-macros" }
37embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver", optional = true } 37embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver", optional = true }
38embassy-time-queue-driver = { version = "0.1.0", path = "../embassy-time-queue-driver", optional = true }
39critical-section = "1.1" 38critical-section = "1.1"
40 39
41document-features = "0.2.7" 40document-features = "0.2.7"
@@ -67,9 +66,6 @@ nightly = ["embassy-executor-macros/nightly"]
67# See: https://github.com/embassy-rs/embassy/pull/1263 66# See: https://github.com/embassy-rs/embassy/pull/1263
68turbowakers = [] 67turbowakers = []
69 68
70## Use the executor-integrated `embassy-time` timer queue.
71integrated-timers = ["dep:embassy-time-driver", "dep:embassy-time-queue-driver"]
72
73#! ### Architecture 69#! ### Architecture
74_arch = [] # some arch was picked 70_arch = [] # some arch was picked
75## std 71## std
@@ -94,7 +90,7 @@ executor-interrupt = []
94## Enable tracing support (adds some overhead) 90## Enable tracing support (adds some overhead)
95trace = [] 91trace = []
96## Enable support for rtos-trace framework 92## Enable support for rtos-trace framework
97rtos-trace = ["dep:rtos-trace", "trace"] 93rtos-trace = ["dep:rtos-trace", "trace", "dep:embassy-time-driver"]
98 94
99#! ### Task Arena Size 95#! ### Task Arena Size
100#! Sets the [task arena](#task-arena) size. Necessary if you’re not using `nightly`. 96#! Sets the [task arena](#task-arena) size. Necessary if you’re not using `nightly`.
diff --git a/embassy-executor/src/arch/avr.rs b/embassy-executor/src/arch/avr.rs
index 7f9ed4421..70085d04d 100644
--- a/embassy-executor/src/arch/avr.rs
+++ b/embassy-executor/src/arch/avr.rs
@@ -53,10 +53,6 @@ mod thread {
53 /// 53 ///
54 /// This function never returns. 54 /// This function never returns.
55 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { 55 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
56 unsafe {
57 self.inner.initialize();
58 }
59
60 init(self.inner.spawner()); 56 init(self.inner.spawner());
61 57
62 loop { 58 loop {
diff --git a/embassy-executor/src/arch/cortex_m.rs b/embassy-executor/src/arch/cortex_m.rs
index 0c2af88a6..5c517e0a2 100644
--- a/embassy-executor/src/arch/cortex_m.rs
+++ b/embassy-executor/src/arch/cortex_m.rs
@@ -98,9 +98,6 @@ mod thread {
98 /// 98 ///
99 /// This function never returns. 99 /// This function never returns.
100 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { 100 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
101 unsafe {
102 self.inner.initialize();
103 }
104 init(self.inner.spawner()); 101 init(self.inner.spawner());
105 102
106 loop { 103 loop {
@@ -210,9 +207,6 @@ mod interrupt {
210 } 207 }
211 208
212 let executor = unsafe { (&*self.executor.get()).assume_init_ref() }; 209 let executor = unsafe { (&*self.executor.get()).assume_init_ref() };
213 unsafe {
214 executor.initialize();
215 }
216 210
217 unsafe { NVIC::unmask(irq) } 211 unsafe { NVIC::unmask(irq) }
218 212
diff --git a/embassy-executor/src/arch/riscv32.rs b/embassy-executor/src/arch/riscv32.rs
index 715e5f3cf..01e63a9fd 100644
--- a/embassy-executor/src/arch/riscv32.rs
+++ b/embassy-executor/src/arch/riscv32.rs
@@ -54,10 +54,6 @@ mod thread {
54 /// 54 ///
55 /// This function never returns. 55 /// This function never returns.
56 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { 56 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
57 unsafe {
58 self.inner.initialize();
59 }
60
61 init(self.inner.spawner()); 57 init(self.inner.spawner());
62 58
63 loop { 59 loop {
diff --git a/embassy-executor/src/arch/spin.rs b/embassy-executor/src/arch/spin.rs
index 54c7458b3..340023620 100644
--- a/embassy-executor/src/arch/spin.rs
+++ b/embassy-executor/src/arch/spin.rs
@@ -48,10 +48,6 @@ mod thread {
48 /// 48 ///
49 /// This function never returns. 49 /// This function never returns.
50 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { 50 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
51 unsafe {
52 self.inner.initialize();
53 }
54
55 init(self.inner.spawner()); 51 init(self.inner.spawner());
56 52
57 loop { 53 loop {
diff --git a/embassy-executor/src/arch/std.rs b/embassy-executor/src/arch/std.rs
index 948c7711b..b02b15988 100644
--- a/embassy-executor/src/arch/std.rs
+++ b/embassy-executor/src/arch/std.rs
@@ -55,10 +55,6 @@ mod thread {
55 /// 55 ///
56 /// This function never returns. 56 /// This function never returns.
57 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { 57 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
58 unsafe {
59 self.inner.initialize();
60 }
61
62 init(self.inner.spawner()); 58 init(self.inner.spawner());
63 59
64 loop { 60 loop {
diff --git a/embassy-executor/src/arch/wasm.rs b/embassy-executor/src/arch/wasm.rs
index 35025f11f..f9d0f935c 100644
--- a/embassy-executor/src/arch/wasm.rs
+++ b/embassy-executor/src/arch/wasm.rs
@@ -71,10 +71,6 @@ mod thread {
71 /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe) 71 /// - a local variable in a function you know never returns (like `fn main() -> !`), upgrading its lifetime with `transmute`. (unsafe)
72 pub fn start(&'static mut self, init: impl FnOnce(Spawner)) { 72 pub fn start(&'static mut self, init: impl FnOnce(Spawner)) {
73 unsafe { 73 unsafe {
74 self.inner.initialize();
75 }
76
77 unsafe {
78 let executor = &self.inner; 74 let executor = &self.inner;
79 let future = Closure::new(move |_| { 75 let future = Closure::new(move |_| {
80 executor.poll(); 76 executor.poll();
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index 3f93eae6f..7da14468d 100644
--- a/embassy-executor/src/raw/mod.rs
+++ b/embassy-executor/src/raw/mod.rs
@@ -16,8 +16,7 @@ mod run_queue;
16#[cfg_attr(not(target_has_atomic = "8"), path = "state_critical_section.rs")] 16#[cfg_attr(not(target_has_atomic = "8"), path = "state_critical_section.rs")]
17mod state; 17mod state;
18 18
19#[cfg(feature = "integrated-timers")] 19pub mod timer_queue;
20mod timer_queue;
21#[cfg(feature = "trace")] 20#[cfg(feature = "trace")]
22mod trace; 21mod trace;
23pub(crate) mod util; 22pub(crate) mod util;
@@ -31,9 +30,6 @@ use core::pin::Pin;
31use core::ptr::NonNull; 30use core::ptr::NonNull;
32use core::task::{Context, Poll}; 31use core::task::{Context, Poll};
33 32
34#[cfg(feature = "integrated-timers")]
35use embassy_time_driver::AlarmHandle;
36
37use self::run_queue::{RunQueue, RunQueueItem}; 33use self::run_queue::{RunQueue, RunQueueItem};
38use self::state::State; 34use self::state::State;
39use self::util::{SyncUnsafeCell, UninitCell}; 35use self::util::{SyncUnsafeCell, UninitCell};
@@ -47,14 +43,12 @@ pub(crate) struct TaskHeader {
47 pub(crate) executor: SyncUnsafeCell<Option<&'static SyncExecutor>>, 43 pub(crate) executor: SyncUnsafeCell<Option<&'static SyncExecutor>>,
48 poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>, 44 poll_fn: SyncUnsafeCell<Option<unsafe fn(TaskRef)>>,
49 45
50 #[cfg(feature = "integrated-timers")] 46 /// Integrated timer queue storage. This field should not be accessed outside of the timer queue.
51 pub(crate) expires_at: SyncUnsafeCell<u64>,
52 #[cfg(feature = "integrated-timers")]
53 pub(crate) timer_queue_item: timer_queue::TimerQueueItem, 47 pub(crate) timer_queue_item: timer_queue::TimerQueueItem,
54} 48}
55 49
56/// This is essentially a `&'static TaskStorage<F>` where the type of the future has been erased. 50/// This is essentially a `&'static TaskStorage<F>` where the type of the future has been erased.
57#[derive(Clone, Copy)] 51#[derive(Clone, Copy, PartialEq)]
58pub struct TaskRef { 52pub struct TaskRef {
59 ptr: NonNull<TaskHeader>, 53 ptr: NonNull<TaskHeader>,
60} 54}
@@ -76,10 +70,53 @@ impl TaskRef {
76 } 70 }
77 } 71 }
78 72
73 /// # Safety
74 ///
75 /// The result of this function must only be compared
76 /// for equality, or stored, but not used.
77 pub const unsafe fn dangling() -> Self {
78 Self {
79 ptr: NonNull::dangling(),
80 }
81 }
82
79 pub(crate) fn header(self) -> &'static TaskHeader { 83 pub(crate) fn header(self) -> &'static TaskHeader {
80 unsafe { self.ptr.as_ref() } 84 unsafe { self.ptr.as_ref() }
81 } 85 }
82 86
87 /// Returns a reference to the executor that the task is currently running on.
88 pub unsafe fn executor(self) -> Option<&'static Executor> {
89 self.header().executor.get().map(|e| Executor::wrap(e))
90 }
91
92 /// Returns a reference to the timer queue item.
93 pub fn timer_queue_item(&self) -> &'static timer_queue::TimerQueueItem {
94 &self.header().timer_queue_item
95 }
96
97 /// Mark the task as timer-queued. Return whether it should be actually enqueued
98 /// using `_embassy_time_schedule_wake`.
99 ///
100 /// Entering this state prevents the task from being respawned while in a timer queue.
101 ///
102 /// Safety:
103 ///
104 /// This functions should only be called by the timer queue driver, before
105 /// enqueueing the timer item.
106 pub unsafe fn timer_enqueue(&self) -> timer_queue::TimerEnqueueOperation {
107 self.header().state.timer_enqueue()
108 }
109
110 /// Unmark the task as timer-queued.
111 ///
112 /// Safety:
113 ///
114 /// This functions should only be called by the timer queue implementation, after the task has
115 /// been removed from the timer queue.
116 pub unsafe fn timer_dequeue(&self) {
117 self.header().state.timer_dequeue()
118 }
119
83 /// The returned pointer is valid for the entire TaskStorage. 120 /// The returned pointer is valid for the entire TaskStorage.
84 pub(crate) fn as_ptr(self) -> *const TaskHeader { 121 pub(crate) fn as_ptr(self) -> *const TaskHeader {
85 self.ptr.as_ptr() 122 self.ptr.as_ptr()
@@ -120,9 +157,6 @@ impl<F: Future + 'static> TaskStorage<F> {
120 // Note: this is lazily initialized so that a static `TaskStorage` will go in `.bss` 157 // Note: this is lazily initialized so that a static `TaskStorage` will go in `.bss`
121 poll_fn: SyncUnsafeCell::new(None), 158 poll_fn: SyncUnsafeCell::new(None),
122 159
123 #[cfg(feature = "integrated-timers")]
124 expires_at: SyncUnsafeCell::new(0),
125 #[cfg(feature = "integrated-timers")]
126 timer_queue_item: timer_queue::TimerQueueItem::new(), 160 timer_queue_item: timer_queue::TimerQueueItem::new(),
127 }, 161 },
128 future: UninitCell::uninit(), 162 future: UninitCell::uninit(),
@@ -159,10 +193,25 @@ impl<F: Future + 'static> TaskStorage<F> {
159 match future.poll(&mut cx) { 193 match future.poll(&mut cx) {
160 Poll::Ready(_) => { 194 Poll::Ready(_) => {
161 this.future.drop_in_place(); 195 this.future.drop_in_place();
196
197 // Mark this task to be timer queued.
198 // We're splitting the enqueue in two parts, so that we can change task state
199 // to something that prevent re-queueing.
200 let op = this.raw.state.timer_enqueue();
201
202 // Now mark the task as not spawned, so that
203 // - it can be spawned again once it has been removed from the timer queue
204 // - it can not be timer-queued again
205 // We must do this before scheduling the wake, to prevent the task from being
206 // dequeued by the time driver while it's still SPAWNED.
162 this.raw.state.despawn(); 207 this.raw.state.despawn();
163 208
164 #[cfg(feature = "integrated-timers")] 209 // Now let's finish enqueueing. While we shouldn't get an `Ignore` here, it's
165 this.raw.expires_at.set(u64::MAX); 210 // better to be safe.
211 if op == timer_queue::TimerEnqueueOperation::Enqueue {
212 // Schedule the task in the past, so it gets dequeued ASAP.
213 unsafe { _embassy_time_schedule_wake(0, &waker) }
214 }
166 } 215 }
167 Poll::Pending => {} 216 Poll::Pending => {}
168 } 217 }
@@ -181,6 +230,10 @@ impl<F: Future + 'static> TaskStorage<F> {
181 } 230 }
182} 231}
183 232
233extern "Rust" {
234 fn _embassy_time_schedule_wake(at: u64, waker: &core::task::Waker);
235}
236
184/// An uninitialized [`TaskStorage`]. 237/// An uninitialized [`TaskStorage`].
185pub struct AvailableTask<F: Future + 'static> { 238pub struct AvailableTask<F: Future + 'static> {
186 task: &'static TaskStorage<F>, 239 task: &'static TaskStorage<F>,
@@ -316,34 +369,16 @@ impl Pender {
316pub(crate) struct SyncExecutor { 369pub(crate) struct SyncExecutor {
317 run_queue: RunQueue, 370 run_queue: RunQueue,
318 pender: Pender, 371 pender: Pender,
319
320 #[cfg(feature = "integrated-timers")]
321 pub(crate) timer_queue: timer_queue::TimerQueue,
322 #[cfg(feature = "integrated-timers")]
323 alarm: AlarmHandle,
324} 372}
325 373
326impl SyncExecutor { 374impl SyncExecutor {
327 pub(crate) fn new(pender: Pender) -> Self { 375 pub(crate) fn new(pender: Pender) -> Self {
328 #[cfg(feature = "integrated-timers")]
329 let alarm = unsafe { unwrap!(embassy_time_driver::allocate_alarm()) };
330
331 Self { 376 Self {
332 run_queue: RunQueue::new(), 377 run_queue: RunQueue::new(),
333 pender, 378 pender,
334
335 #[cfg(feature = "integrated-timers")]
336 timer_queue: timer_queue::TimerQueue::new(),
337 #[cfg(feature = "integrated-timers")]
338 alarm,
339 } 379 }
340 } 380 }
341 381
342 pub(crate) unsafe fn initialize(&'static self) {
343 #[cfg(feature = "integrated-timers")]
344 embassy_time_driver::set_alarm_callback(self.alarm, Self::alarm_callback, self as *const _ as *mut ());
345 }
346
347 /// Enqueue a task in the task queue 382 /// Enqueue a task in the task queue
348 /// 383 ///
349 /// # Safety 384 /// # Safety
@@ -360,12 +395,6 @@ impl SyncExecutor {
360 } 395 }
361 } 396 }
362 397
363 #[cfg(feature = "integrated-timers")]
364 fn alarm_callback(ctx: *mut ()) {
365 let this: &Self = unsafe { &*(ctx as *const Self) };
366 this.pender.pend();
367 }
368
369 pub(super) unsafe fn spawn(&'static self, task: TaskRef) { 398 pub(super) unsafe fn spawn(&'static self, task: TaskRef) {
370 task.header().executor.set(Some(self)); 399 task.header().executor.set(Some(self));
371 400
@@ -379,56 +408,27 @@ impl SyncExecutor {
379 /// 408 ///
380 /// Same as [`Executor::poll`], plus you must only call this on the thread this executor was created. 409 /// Same as [`Executor::poll`], plus you must only call this on the thread this executor was created.
381 pub(crate) unsafe fn poll(&'static self) { 410 pub(crate) unsafe fn poll(&'static self) {
382 #[allow(clippy::never_loop)] 411 self.run_queue.dequeue_all(|p| {
383 loop { 412 let task = p.header();
384 #[cfg(feature = "integrated-timers")] 413
385 self.timer_queue 414 if !task.state.run_dequeue() {
386 .dequeue_expired(embassy_time_driver::now(), wake_task_no_pend); 415 // If task is not running, ignore it. This can happen in the following scenario:
387 416 // - Task gets dequeued, poll starts
388 self.run_queue.dequeue_all(|p| { 417 // - While task is being polled, it gets woken. It gets placed in the queue.
389 let task = p.header(); 418 // - Task poll finishes, returning done=true
390 419 // - RUNNING bit is cleared, but the task is already in the queue.
391 #[cfg(feature = "integrated-timers")] 420 return;
392 task.expires_at.set(u64::MAX); 421 }
393
394 if !task.state.run_dequeue() {
395 // If task is not running, ignore it. This can happen in the following scenario:
396 // - Task gets dequeued, poll starts
397 // - While task is being polled, it gets woken. It gets placed in the queue.
398 // - Task poll finishes, returning done=true
399 // - RUNNING bit is cleared, but the task is already in the queue.
400 return;
401 }
402
403 #[cfg(feature = "trace")]
404 trace::task_exec_begin(self, &p);
405 422
406 // Run the task 423 #[cfg(feature = "trace")]
407 task.poll_fn.get().unwrap_unchecked()(p); 424 trace::task_exec_begin(self, &p);
408 425
409 #[cfg(feature = "trace")] 426 // Run the task
410 trace::task_exec_end(self, &p); 427 task.poll_fn.get().unwrap_unchecked()(p);
411 428
412 // Enqueue or update into timer_queue 429 #[cfg(feature = "trace")]
413 #[cfg(feature = "integrated-timers")] 430 trace::task_exec_end(self, &p);
414 self.timer_queue.update(p); 431 });
415 });
416
417 #[cfg(feature = "integrated-timers")]
418 {
419 // If this is already in the past, set_alarm might return false
420 // In that case do another poll loop iteration.
421 let next_expiration = self.timer_queue.next_expiration();
422 if embassy_time_driver::set_alarm(self.alarm, next_expiration) {
423 break;
424 }
425 }
426
427 #[cfg(not(feature = "integrated-timers"))]
428 {
429 break;
430 }
431 }
432 432
433 #[cfg(feature = "trace")] 433 #[cfg(feature = "trace")]
434 trace::executor_idle(self) 434 trace::executor_idle(self)
@@ -494,15 +494,6 @@ impl Executor {
494 } 494 }
495 } 495 }
496 496
497 /// Initializes the executor.
498 ///
499 /// # Safety
500 ///
501 /// This function must be called once before any other method is called.
502 pub unsafe fn initialize(&'static self) {
503 self.inner.initialize();
504 }
505
506 /// Spawn a task in this executor. 497 /// Spawn a task in this executor.
507 /// 498 ///
508 /// # Safety 499 /// # Safety
@@ -575,21 +566,3 @@ pub fn wake_task_no_pend(task: TaskRef) {
575 } 566 }
576 } 567 }
577} 568}
578
579#[cfg(feature = "integrated-timers")]
580struct TimerQueue;
581
582#[cfg(feature = "integrated-timers")]
583impl embassy_time_queue_driver::TimerQueue for TimerQueue {
584 fn schedule_wake(&'static self, at: u64, waker: &core::task::Waker) {
585 let task = waker::task_from_waker(waker);
586 let task = task.header();
587 unsafe {
588 let expires_at = task.expires_at.get();
589 task.expires_at.set(expires_at.min(at));
590 }
591 }
592}
593
594#[cfg(feature = "integrated-timers")]
595embassy_time_queue_driver::timer_queue_impl!(static TIMER_QUEUE: TimerQueue = TimerQueue);
diff --git a/embassy-executor/src/raw/state_atomics.rs b/embassy-executor/src/raw/state_atomics.rs
index e1279ac0b..15eb9a368 100644
--- a/embassy-executor/src/raw/state_atomics.rs
+++ b/embassy-executor/src/raw/state_atomics.rs
@@ -1,11 +1,12 @@
1use core::sync::atomic::{AtomicU32, Ordering}; 1use core::sync::atomic::{AtomicU32, Ordering};
2 2
3use super::timer_queue::TimerEnqueueOperation;
4
3/// Task is spawned (has a future) 5/// Task is spawned (has a future)
4pub(crate) const STATE_SPAWNED: u32 = 1 << 0; 6pub(crate) const STATE_SPAWNED: u32 = 1 << 0;
5/// Task is in the executor run queue 7/// Task is in the executor run queue
6pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1; 8pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1;
7/// Task is in the executor timer queue 9/// Task is in the executor timer queue
8#[cfg(feature = "integrated-timers")]
9pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2; 10pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2;
10 11
11pub(crate) struct State { 12pub(crate) struct State {
@@ -56,18 +57,31 @@ impl State {
56 state & STATE_SPAWNED != 0 57 state & STATE_SPAWNED != 0
57 } 58 }
58 59
59 /// Mark the task as timer-queued. Return whether it was newly queued (i.e. not queued before) 60 /// Mark the task as timer-queued. Return whether it can be enqueued.
60 #[cfg(feature = "integrated-timers")]
61 #[inline(always)] 61 #[inline(always)]
62 pub fn timer_enqueue(&self) -> bool { 62 pub fn timer_enqueue(&self) -> TimerEnqueueOperation {
63 let old_state = self.state.fetch_or(STATE_TIMER_QUEUED, Ordering::AcqRel); 63 if self
64 old_state & STATE_TIMER_QUEUED == 0 64 .state
65 .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |state| {
66 // If not started, ignore it
67 if state & STATE_SPAWNED == 0 {
68 None
69 } else {
70 // Mark it as enqueued
71 Some(state | STATE_TIMER_QUEUED)
72 }
73 })
74 .is_ok()
75 {
76 TimerEnqueueOperation::Enqueue
77 } else {
78 TimerEnqueueOperation::Ignore
79 }
65 } 80 }
66 81
67 /// Unmark the task as timer-queued. 82 /// Unmark the task as timer-queued.
68 #[cfg(feature = "integrated-timers")]
69 #[inline(always)] 83 #[inline(always)]
70 pub fn timer_dequeue(&self) { 84 pub fn timer_dequeue(&self) {
71 self.state.fetch_and(!STATE_TIMER_QUEUED, Ordering::AcqRel); 85 self.state.fetch_and(!STATE_TIMER_QUEUED, Ordering::Relaxed);
72 } 86 }
73} 87}
diff --git a/embassy-executor/src/raw/state_atomics_arm.rs b/embassy-executor/src/raw/state_atomics_arm.rs
index e4dfe5093..7a152e8c0 100644
--- a/embassy-executor/src/raw/state_atomics_arm.rs
+++ b/embassy-executor/src/raw/state_atomics_arm.rs
@@ -1,9 +1,12 @@
1use core::arch::asm; 1use core::arch::asm;
2use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering}; 2use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering};
3 3
4use super::timer_queue::TimerEnqueueOperation;
5
4// Must be kept in sync with the layout of `State`! 6// Must be kept in sync with the layout of `State`!
5pub(crate) const STATE_SPAWNED: u32 = 1 << 0; 7pub(crate) const STATE_SPAWNED: u32 = 1 << 0;
6pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 8; 8pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 8;
9pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 16;
7 10
8#[repr(C, align(4))] 11#[repr(C, align(4))]
9pub(crate) struct State { 12pub(crate) struct State {
@@ -87,15 +90,29 @@ impl State {
87 r 90 r
88 } 91 }
89 92
90 /// Mark the task as timer-queued. Return whether it was newly queued (i.e. not queued before) 93 /// Mark the task as timer-queued. Return whether it can be enqueued.
91 #[cfg(feature = "integrated-timers")]
92 #[inline(always)] 94 #[inline(always)]
93 pub fn timer_enqueue(&self) -> bool { 95 pub fn timer_enqueue(&self) -> TimerEnqueueOperation {
94 !self.timer_queued.swap(true, Ordering::Relaxed) 96 if self
97 .as_u32()
98 .fetch_update(Ordering::SeqCst, Ordering::SeqCst, |state| {
99 // If not started, ignore it
100 if state & STATE_SPAWNED == 0 {
101 None
102 } else {
103 // Mark it as enqueued
104 Some(state | STATE_TIMER_QUEUED)
105 }
106 })
107 .is_ok()
108 {
109 TimerEnqueueOperation::Enqueue
110 } else {
111 TimerEnqueueOperation::Ignore
112 }
95 } 113 }
96 114
97 /// Unmark the task as timer-queued. 115 /// Unmark the task as timer-queued.
98 #[cfg(feature = "integrated-timers")]
99 #[inline(always)] 116 #[inline(always)]
100 pub fn timer_dequeue(&self) { 117 pub fn timer_dequeue(&self) {
101 self.timer_queued.store(false, Ordering::Relaxed); 118 self.timer_queued.store(false, Ordering::Relaxed);
diff --git a/embassy-executor/src/raw/state_critical_section.rs b/embassy-executor/src/raw/state_critical_section.rs
index c3cc1b0b7..367162ba2 100644
--- a/embassy-executor/src/raw/state_critical_section.rs
+++ b/embassy-executor/src/raw/state_critical_section.rs
@@ -2,12 +2,13 @@ use core::cell::Cell;
2 2
3use critical_section::Mutex; 3use critical_section::Mutex;
4 4
5use super::timer_queue::TimerEnqueueOperation;
6
5/// Task is spawned (has a future) 7/// Task is spawned (has a future)
6pub(crate) const STATE_SPAWNED: u32 = 1 << 0; 8pub(crate) const STATE_SPAWNED: u32 = 1 << 0;
7/// Task is in the executor run queue 9/// Task is in the executor run queue
8pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1; 10pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1;
9/// Task is in the executor timer queue 11/// Task is in the executor timer queue
10#[cfg(feature = "integrated-timers")]
11pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2; 12pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2;
12 13
13pub(crate) struct State { 14pub(crate) struct State {
@@ -73,19 +74,22 @@ impl State {
73 }) 74 })
74 } 75 }
75 76
76 /// Mark the task as timer-queued. Return whether it was newly queued (i.e. not queued before) 77 /// Mark the task as timer-queued. Return whether it can be enqueued.
77 #[cfg(feature = "integrated-timers")]
78 #[inline(always)] 78 #[inline(always)]
79 pub fn timer_enqueue(&self) -> bool { 79 pub fn timer_enqueue(&self) -> TimerEnqueueOperation {
80 self.update(|s| { 80 self.update(|s| {
81 let ok = *s & STATE_TIMER_QUEUED == 0; 81 // FIXME: we need to split SPAWNED into two phases, to prevent enqueueing a task that is
82 *s |= STATE_TIMER_QUEUED; 82 // just being spawned, because its executor pointer may still be changing.
83 ok 83 if *s & STATE_SPAWNED == STATE_SPAWNED {
84 *s |= STATE_TIMER_QUEUED;
85 TimerEnqueueOperation::Enqueue
86 } else {
87 TimerEnqueueOperation::Ignore
88 }
84 }) 89 })
85 } 90 }
86 91
87 /// Unmark the task as timer-queued. 92 /// Unmark the task as timer-queued.
88 #[cfg(feature = "integrated-timers")]
89 #[inline(always)] 93 #[inline(always)]
90 pub fn timer_dequeue(&self) { 94 pub fn timer_dequeue(&self) {
91 self.update(|s| *s &= !STATE_TIMER_QUEUED); 95 self.update(|s| *s &= !STATE_TIMER_QUEUED);
diff --git a/embassy-executor/src/raw/timer_queue.rs b/embassy-executor/src/raw/timer_queue.rs
index 94a5f340b..2ba0e00a9 100644
--- a/embassy-executor/src/raw/timer_queue.rs
+++ b/embassy-executor/src/raw/timer_queue.rs
@@ -1,76 +1,39 @@
1use core::cmp::min; 1//! Timer queue operations.
2
3use core::cell::Cell;
2 4
3use super::TaskRef; 5use super::TaskRef;
4use crate::raw::util::SyncUnsafeCell;
5 6
6pub(crate) struct TimerQueueItem { 7/// An item in the timer queue.
7 next: SyncUnsafeCell<Option<TaskRef>>, 8pub struct TimerQueueItem {
8} 9 /// The next item in the queue.
10 ///
11 /// If this field contains `Some`, the item is in the queue. The last item in the queue has a
12 /// value of `Some(dangling_pointer)`
13 pub next: Cell<Option<TaskRef>>,
9 14
10impl TimerQueueItem { 15 /// The time at which this item expires.
11 pub const fn new() -> Self { 16 pub expires_at: Cell<u64>,
12 Self {
13 next: SyncUnsafeCell::new(None),
14 }
15 }
16} 17}
17 18
18pub(crate) struct TimerQueue { 19unsafe impl Sync for TimerQueueItem {}
19 head: SyncUnsafeCell<Option<TaskRef>>,
20}
21 20
22impl TimerQueue { 21impl TimerQueueItem {
23 pub const fn new() -> Self { 22 pub(crate) const fn new() -> Self {
24 Self { 23 Self {
25 head: SyncUnsafeCell::new(None), 24 next: Cell::new(None),
26 } 25 expires_at: Cell::new(0),
27 }
28
29 pub(crate) unsafe fn update(&self, p: TaskRef) {
30 let task = p.header();
31 if task.expires_at.get() != u64::MAX {
32 if task.state.timer_enqueue() {
33 task.timer_queue_item.next.set(self.head.get());
34 self.head.set(Some(p));
35 }
36 } 26 }
37 } 27 }
28}
38 29
39 pub(crate) unsafe fn next_expiration(&self) -> u64 { 30/// The operation to perform after `timer_enqueue` is called.
40 let mut res = u64::MAX; 31#[derive(Debug, Copy, Clone, PartialEq)]
41 self.retain(|p| { 32#[cfg_attr(feature = "defmt", derive(defmt::Format))]
42 let task = p.header(); 33#[must_use]
43 let expires = task.expires_at.get(); 34pub enum TimerEnqueueOperation {
44 res = min(res, expires); 35 /// Enqueue the task (or update its expiration time).
45 expires != u64::MAX 36 Enqueue,
46 }); 37 /// The task must not be enqueued in the timer queue.
47 res 38 Ignore,
48 }
49
50 pub(crate) unsafe fn dequeue_expired(&self, now: u64, on_task: impl Fn(TaskRef)) {
51 self.retain(|p| {
52 let task = p.header();
53 if task.expires_at.get() <= now {
54 on_task(p);
55 false
56 } else {
57 true
58 }
59 });
60 }
61
62 pub(crate) unsafe fn retain(&self, mut f: impl FnMut(TaskRef) -> bool) {
63 let mut prev = &self.head;
64 while let Some(p) = prev.get() {
65 let task = p.header();
66 if f(p) {
67 // Skip to next
68 prev = &task.timer_queue_item.next;
69 } else {
70 // Remove it
71 prev.set(task.timer_queue_item.next.get());
72 task.state.timer_dequeue();
73 }
74 }
75 }
76} 39}
diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs
index c7bcf9c11..b34387b58 100644
--- a/embassy-executor/src/raw/trace.rs
+++ b/embassy-executor/src/raw/trace.rs
@@ -61,29 +61,23 @@ pub(crate) fn executor_idle(executor: &SyncExecutor) {
61 rtos_trace::trace::system_idle(); 61 rtos_trace::trace::system_idle();
62} 62}
63 63
64#[cfg(all(feature = "rtos-trace", feature = "integrated-timers"))]
65const fn gcd(a: u64, b: u64) -> u64 {
66 if b == 0 {
67 a
68 } else {
69 gcd(b, a % b)
70 }
71}
72
73#[cfg(feature = "rtos-trace")] 64#[cfg(feature = "rtos-trace")]
74impl rtos_trace::RtosTraceOSCallbacks for crate::raw::SyncExecutor { 65impl rtos_trace::RtosTraceOSCallbacks for crate::raw::SyncExecutor {
75 fn task_list() { 66 fn task_list() {
76 // We don't know what tasks exist, so we can't send them. 67 // We don't know what tasks exist, so we can't send them.
77 } 68 }
78 #[cfg(feature = "integrated-timers")]
79 fn time() -> u64 { 69 fn time() -> u64 {
70 const fn gcd(a: u64, b: u64) -> u64 {
71 if b == 0 {
72 a
73 } else {
74 gcd(b, a % b)
75 }
76 }
77
80 const GCD_1M: u64 = gcd(embassy_time_driver::TICK_HZ, 1_000_000); 78 const GCD_1M: u64 = gcd(embassy_time_driver::TICK_HZ, 1_000_000);
81 embassy_time_driver::now() * (1_000_000 / GCD_1M) / (embassy_time_driver::TICK_HZ / GCD_1M) 79 embassy_time_driver::now() * (1_000_000 / GCD_1M) / (embassy_time_driver::TICK_HZ / GCD_1M)
82 } 80 }
83 #[cfg(not(feature = "integrated-timers"))]
84 fn time() -> u64 {
85 0
86 }
87} 81}
88 82
89#[cfg(feature = "rtos-trace")] 83#[cfg(feature = "rtos-trace")]
diff --git a/embassy-executor/tests/test.rs b/embassy-executor/tests/test.rs
index 8054bf7eb..992ab3da9 100644
--- a/embassy-executor/tests/test.rs
+++ b/embassy-executor/tests/test.rs
@@ -40,9 +40,6 @@ fn setup() -> (&'static Executor, Trace) {
40 let trace = Trace::new(); 40 let trace = Trace::new();
41 let context = Box::leak(Box::new(trace.clone())) as *mut _ as *mut (); 41 let context = Box::leak(Box::new(trace.clone())) as *mut _ as *mut ();
42 let executor = &*Box::leak(Box::new(Executor::new(context))); 42 let executor = &*Box::leak(Box::new(Executor::new(context)));
43 unsafe {
44 executor.initialize();
45 }
46 43
47 (executor, trace) 44 (executor, trace)
48} 45}
@@ -153,3 +150,7 @@ fn executor_task_cfg_args() {
153 let (_, _, _) = (a, b, c); 150 let (_, _, _) = (a, b, c);
154 } 151 }
155} 152}
153
154// We need this for the test to compile, even though we don't want to use timers at the moment.
155#[no_mangle]
156fn _embassy_time_schedule_wake(_at: u64, _waker: &core::task::Waker) {}
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml
index 9da050a22..48f80bb5e 100644
--- a/embassy-nrf/Cargo.toml
+++ b/embassy-nrf/Cargo.toml
@@ -119,7 +119,7 @@ _nrf52 = ["_ppi"]
119_nrf51 = ["_ppi"] 119_nrf51 = ["_ppi"]
120_nrf91 = [] 120_nrf91 = []
121 121
122_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768"] 122_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768", "dep:embassy-time-queue-driver"]
123 123
124# trustzone state. 124# trustzone state.
125_s = [] 125_s = []
@@ -135,6 +135,7 @@ _nrf52832_anomaly_109 = []
135 135
136[dependencies] 136[dependencies]
137embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } 137embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true }
138embassy-time-queue-driver = { version = "0.1", path = "../embassy-time-queue-driver", optional = true }
138embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true } 139embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true }
139embassy-sync = { version = "0.6.1", path = "../embassy-sync" } 140embassy-sync = { version = "0.6.1", path = "../embassy-sync" }
140embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } 141embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] }
diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs
index 9ba38ec1b..a27fae9a8 100644
--- a/embassy-nrf/src/time_driver.rs
+++ b/embassy-nrf/src/time_driver.rs
@@ -1,11 +1,11 @@
1use core::cell::Cell; 1use core::cell::{Cell, RefCell};
2use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; 2use core::sync::atomic::{compiler_fence, AtomicU32, Ordering};
3use core::{mem, ptr};
4 3
5use critical_section::CriticalSection; 4use critical_section::CriticalSection;
6use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 5use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
7use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; 6use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex;
8use embassy_time_driver::{AlarmHandle, Driver}; 7use embassy_time_driver::Driver;
8use embassy_time_queue_driver::Queue;
9 9
10use crate::interrupt::InterruptExt; 10use crate::interrupt::InterruptExt;
11use crate::{interrupt, pac}; 11use crate::{interrupt, pac};
@@ -94,11 +94,6 @@ mod test {
94 94
95struct AlarmState { 95struct AlarmState {
96 timestamp: Cell<u64>, 96 timestamp: Cell<u64>,
97
98 // This is really a Option<(fn(*mut ()), *mut ())>
99 // but fn pointers aren't allowed in const yet
100 callback: Cell<*const ()>,
101 ctx: Cell<*mut ()>,
102} 97}
103 98
104unsafe impl Send for AlarmState {} 99unsafe impl Send for AlarmState {}
@@ -107,26 +102,22 @@ impl AlarmState {
107 const fn new() -> Self { 102 const fn new() -> Self {
108 Self { 103 Self {
109 timestamp: Cell::new(u64::MAX), 104 timestamp: Cell::new(u64::MAX),
110 callback: Cell::new(ptr::null()),
111 ctx: Cell::new(ptr::null_mut()),
112 } 105 }
113 } 106 }
114} 107}
115 108
116const ALARM_COUNT: usize = 3;
117
118struct RtcDriver { 109struct RtcDriver {
119 /// Number of 2^23 periods elapsed since boot. 110 /// Number of 2^23 periods elapsed since boot.
120 period: AtomicU32, 111 period: AtomicU32,
121 alarm_count: AtomicU8,
122 /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. 112 /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
123 alarms: Mutex<[AlarmState; ALARM_COUNT]>, 113 alarms: Mutex<AlarmState>,
114 queue: Mutex<RefCell<Queue>>,
124} 115}
125 116
126embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { 117embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
127 period: AtomicU32::new(0), 118 period: AtomicU32::new(0),
128 alarm_count: AtomicU8::new(0), 119 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
129 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [const {AlarmState::new()}; ALARM_COUNT]), 120 queue: Mutex::new(RefCell::new(Queue::new())),
130}); 121});
131 122
132impl RtcDriver { 123impl RtcDriver {
@@ -169,13 +160,12 @@ impl RtcDriver {
169 self.next_period(); 160 self.next_period();
170 } 161 }
171 162
172 for n in 0..ALARM_COUNT { 163 let n = 0;
173 if r.events_compare(n).read() == 1 { 164 if r.events_compare(n).read() == 1 {
174 r.events_compare(n).write_value(0); 165 r.events_compare(n).write_value(0);
175 critical_section::with(|cs| { 166 critical_section::with(|cs| {
176 self.trigger_alarm(n, cs); 167 self.trigger_alarm(cs);
177 }) 168 });
178 }
179 } 169 }
180 } 170 }
181 171
@@ -186,38 +176,80 @@ impl RtcDriver {
186 self.period.store(period, Ordering::Relaxed); 176 self.period.store(period, Ordering::Relaxed);
187 let t = (period as u64) << 23; 177 let t = (period as u64) << 23;
188 178
189 for n in 0..ALARM_COUNT { 179 let n = 0;
190 let alarm = &self.alarms.borrow(cs)[n]; 180 let alarm = &self.alarms.borrow(cs);
191 let at = alarm.timestamp.get(); 181 let at = alarm.timestamp.get();
192 182
193 if at < t + 0xc00000 { 183 if at < t + 0xc00000 {
194 // just enable it. `set_alarm` has already set the correct CC val. 184 // just enable it. `set_alarm` has already set the correct CC val.
195 r.intenset().write(|w| w.0 = compare_n(n)); 185 r.intenset().write(|w| w.0 = compare_n(n));
196 }
197 } 186 }
198 }) 187 })
199 } 188 }
200 189
201 fn get_alarm<'a>(&'a self, cs: CriticalSection<'a>, alarm: AlarmHandle) -> &'a AlarmState { 190 fn trigger_alarm(&self, cs: CriticalSection) {
202 // safety: we're allowed to assume the AlarmState is created by us, and 191 let n = 0;
203 // we never create one that's out of bounds.
204 unsafe { self.alarms.borrow(cs).get_unchecked(alarm.id() as usize) }
205 }
206
207 fn trigger_alarm(&self, n: usize, cs: CriticalSection) {
208 let r = rtc(); 192 let r = rtc();
209 r.intenclr().write(|w| w.0 = compare_n(n)); 193 r.intenclr().write(|w| w.0 = compare_n(n));
210 194
211 let alarm = &self.alarms.borrow(cs)[n]; 195 let alarm = &self.alarms.borrow(cs);
212 alarm.timestamp.set(u64::MAX); 196 alarm.timestamp.set(u64::MAX);
213 197
214 // Call after clearing alarm, so the callback can set another alarm. 198 // Call after clearing alarm, so the callback can set another alarm.
199 let mut next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now());
200 while !self.set_alarm(cs, next) {
201 next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now());
202 }
203 }
204
205 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
206 let n = 0;
207 let alarm = &self.alarms.borrow(cs);
208 alarm.timestamp.set(timestamp);
209
210 let r = rtc();
211
212 let t = self.now();
213 if timestamp <= t {
214 // If alarm timestamp has passed the alarm will not fire.
215 // Disarm the alarm and return `false` to indicate that.
216 r.intenclr().write(|w| w.0 = compare_n(n));
217
218 alarm.timestamp.set(u64::MAX);
219
220 return false;
221 }
222
223 // If it hasn't triggered yet, setup it in the compare channel.
224
225 // Write the CC value regardless of whether we're going to enable it now or not.
226 // This way, when we enable it later, the right value is already set.
227
228 // nrf52 docs say:
229 // If the COUNTER is N, writing N or N+1 to a CC register may not trigger a COMPARE event.
230 // To workaround this, we never write a timestamp smaller than N+3.
231 // N+2 is not safe because rtc can tick from N to N+1 between calling now() and writing cc.
232 //
233 // It is impossible for rtc to tick more than once because
234 // - this code takes less time than 1 tick
235 // - it runs with interrupts disabled so nothing else can preempt it.
236 //
237 // This means that an alarm can be delayed for up to 2 ticks (from t+1 to t+3), but this is allowed
238 // by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time,
239 // and we don't do that here.
240 let safe_timestamp = timestamp.max(t + 3);
241 r.cc(n).write(|w| w.set_compare(safe_timestamp as u32 & 0xFFFFFF));
242
243 let diff = timestamp - t;
244 if diff < 0xc00000 {
245 r.intenset().write(|w| w.0 = compare_n(n));
246 } else {
247 // If it's too far in the future, don't setup the compare channel yet.
248 // It will be setup later by `next_period`.
249 r.intenclr().write(|w| w.0 = compare_n(n));
250 }
215 251
216 // safety: 252 true
217 // - we can ignore the possiblity of `f` being unset (null) because of the safety contract of `allocate_alarm`.
218 // - other than that we only store valid function pointers into alarm.callback
219 let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback.get()) };
220 f(alarm.ctx.get());
221 } 253 }
222} 254}
223 255
@@ -230,76 +262,16 @@ impl Driver for RtcDriver {
230 calc_now(period, counter) 262 calc_now(period, counter)
231 } 263 }
232 264
233 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> { 265 fn schedule_wake(&self, at: u64, waker: &core::task::Waker) {
234 critical_section::with(|_| {
235 let id = self.alarm_count.load(Ordering::Relaxed);
236 if id < ALARM_COUNT as u8 {
237 self.alarm_count.store(id + 1, Ordering::Relaxed);
238 Some(AlarmHandle::new(id))
239 } else {
240 None
241 }
242 })
243 }
244
245 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
246 critical_section::with(|cs| {
247 let alarm = self.get_alarm(cs, alarm);
248
249 alarm.callback.set(callback as *const ());
250 alarm.ctx.set(ctx);
251 })
252 }
253
254 fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool {
255 critical_section::with(|cs| { 266 critical_section::with(|cs| {
256 let n = alarm.id() as _; 267 let mut queue = self.queue.borrow(cs).borrow_mut();
257 let alarm = self.get_alarm(cs, alarm);
258 alarm.timestamp.set(timestamp);
259 268
260 let r = rtc(); 269 if queue.schedule_wake(at, waker) {
261 270 let mut next = queue.next_expiration(self.now());
262 let t = self.now(); 271 while !self.set_alarm(cs, next) {
263 if timestamp <= t { 272 next = queue.next_expiration(self.now());
264 // If alarm timestamp has passed the alarm will not fire. 273 }
265 // Disarm the alarm and return `false` to indicate that.
266 r.intenclr().write(|w| w.0 = compare_n(n));
267
268 alarm.timestamp.set(u64::MAX);
269
270 return false;
271 }
272
273 // If it hasn't triggered yet, setup it in the compare channel.
274
275 // Write the CC value regardless of whether we're going to enable it now or not.
276 // This way, when we enable it later, the right value is already set.
277
278 // nrf52 docs say:
279 // If the COUNTER is N, writing N or N+1 to a CC register may not trigger a COMPARE event.
280 // To workaround this, we never write a timestamp smaller than N+3.
281 // N+2 is not safe because rtc can tick from N to N+1 between calling now() and writing cc.
282 //
283 // It is impossible for rtc to tick more than once because
284 // - this code takes less time than 1 tick
285 // - it runs with interrupts disabled so nothing else can preempt it.
286 //
287 // This means that an alarm can be delayed for up to 2 ticks (from t+1 to t+3), but this is allowed
288 // by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time,
289 // and we don't do that here.
290 let safe_timestamp = timestamp.max(t + 3);
291 r.cc(n).write(|w| w.set_compare(safe_timestamp as u32 & 0xFFFFFF));
292
293 let diff = timestamp - t;
294 if diff < 0xc00000 {
295 r.intenset().write(|w| w.0 = compare_n(n));
296 } else {
297 // If it's too far in the future, don't setup the compare channel yet.
298 // It will be setup later by `next_period`.
299 r.intenclr().write(|w| w.0 = compare_n(n));
300 } 274 }
301
302 true
303 }) 275 })
304 } 276 }
305} 277}
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index 3809f1894..94de82fa9 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -40,7 +40,7 @@ critical-section-impl = ["critical-section/restore-state-u8"]
40unstable-pac = [] 40unstable-pac = []
41 41
42## Enable the timer for use with `embassy-time` with a 1MHz tick rate. 42## Enable the timer for use with `embassy-time` with a 1MHz tick rate.
43time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-1_000_000"] 43time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-1_000_000", "dep:embassy-time-queue-driver"]
44 44
45## Enable ROM function cache. This will store the address of a ROM function when first used, improving performance of subsequent calls. 45## Enable ROM function cache. This will store the address of a ROM function when first used, improving performance of subsequent calls.
46rom-func-cache = [] 46rom-func-cache = []
@@ -110,6 +110,7 @@ binary-info = ["rt", "dep:rp-binary-info", "rp-binary-info?/binary-info"]
110[dependencies] 110[dependencies]
111embassy-sync = { version = "0.6.1", path = "../embassy-sync" } 111embassy-sync = { version = "0.6.1", path = "../embassy-sync" }
112embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } 112embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true }
113embassy-time-queue-driver = { version = "0.1", path = "../embassy-time-queue-driver", optional = true }
113embassy-time = { version = "0.3.2", path = "../embassy-time" } 114embassy-time = { version = "0.3.2", path = "../embassy-time" }
114embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 115embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
115embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } 116embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] }
diff --git a/embassy-rp/src/time_driver.rs b/embassy-rp/src/time_driver.rs
index 40fc71bb1..a0eaec10e 100644
--- a/embassy-rp/src/time_driver.rs
+++ b/embassy-rp/src/time_driver.rs
@@ -1,11 +1,11 @@
1//! Timer driver. 1//! Timer driver.
2use core::cell::Cell; 2use core::cell::{Cell, RefCell};
3 3
4use atomic_polyfill::{AtomicU8, Ordering};
5use critical_section::CriticalSection; 4use critical_section::CriticalSection;
6use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 5use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
7use embassy_sync::blocking_mutex::Mutex; 6use embassy_sync::blocking_mutex::Mutex;
8use embassy_time_driver::{AlarmHandle, Driver}; 7use embassy_time_driver::Driver;
8use embassy_time_queue_driver::Queue;
9#[cfg(feature = "rp2040")] 9#[cfg(feature = "rp2040")]
10use pac::TIMER; 10use pac::TIMER;
11#[cfg(feature = "_rp235x")] 11#[cfg(feature = "_rp235x")]
@@ -16,23 +16,19 @@ use crate::{interrupt, pac};
16 16
17struct AlarmState { 17struct AlarmState {
18 timestamp: Cell<u64>, 18 timestamp: Cell<u64>,
19 callback: Cell<Option<(fn(*mut ()), *mut ())>>,
20} 19}
21unsafe impl Send for AlarmState {} 20unsafe impl Send for AlarmState {}
22 21
23const ALARM_COUNT: usize = 4;
24
25struct TimerDriver { 22struct TimerDriver {
26 alarms: Mutex<CriticalSectionRawMutex, [AlarmState; ALARM_COUNT]>, 23 alarms: Mutex<CriticalSectionRawMutex, AlarmState>,
27 next_alarm: AtomicU8, 24 queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>,
28} 25}
29 26
30embassy_time_driver::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{ 27embassy_time_driver::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{
31 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [const{AlarmState { 28 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState {
32 timestamp: Cell::new(0), 29 timestamp: Cell::new(0),
33 callback: Cell::new(None), 30 }),
34 }}; ALARM_COUNT]), 31 queue: Mutex::new(RefCell::new(Queue::new()))
35 next_alarm: AtomicU8::new(0),
36}); 32});
37 33
38impl Driver for TimerDriver { 34impl Driver for TimerDriver {
@@ -47,64 +43,53 @@ impl Driver for TimerDriver {
47 } 43 }
48 } 44 }
49 45
50 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> { 46 fn schedule_wake(&self, at: u64, waker: &core::task::Waker) {
51 let id = self.next_alarm.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
52 if x < ALARM_COUNT as u8 {
53 Some(x + 1)
54 } else {
55 None
56 }
57 });
58
59 match id {
60 Ok(id) => Some(AlarmHandle::new(id)),
61 Err(_) => None,
62 }
63 }
64
65 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
66 let n = alarm.id() as usize;
67 critical_section::with(|cs| {
68 let alarm = &self.alarms.borrow(cs)[n];
69 alarm.callback.set(Some((callback, ctx)));
70 })
71 }
72
73 fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool {
74 let n = alarm.id() as usize;
75 critical_section::with(|cs| { 47 critical_section::with(|cs| {
76 let alarm = &self.alarms.borrow(cs)[n]; 48 let mut queue = self.queue.borrow(cs).borrow_mut();
77 alarm.timestamp.set(timestamp);
78 49
79 // Arm it. 50 if queue.schedule_wake(at, waker) {
80 // Note that we're not checking the high bits at all. This means the irq may fire early 51 let mut next = queue.next_expiration(self.now());
81 // if the alarm is more than 72 minutes (2^32 us) in the future. This is OK, since on irq fire 52 while !self.set_alarm(cs, next) {
82 // it is checked if the alarm time has passed. 53 next = queue.next_expiration(self.now());
83 TIMER.alarm(n).write_value(timestamp as u32); 54 }
84
85 let now = self.now();
86 if timestamp <= now {
87 // If alarm timestamp has passed the alarm will not fire.
88 // Disarm the alarm and return `false` to indicate that.
89 TIMER.armed().write(|w| w.set_armed(1 << n));
90
91 alarm.timestamp.set(u64::MAX);
92
93 false
94 } else {
95 true
96 } 55 }
97 }) 56 })
98 } 57 }
99} 58}
100 59
101impl TimerDriver { 60impl TimerDriver {
102 fn check_alarm(&self, n: usize) { 61 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
62 let n = 0;
63 let alarm = &self.alarms.borrow(cs);
64 alarm.timestamp.set(timestamp);
65
66 // Arm it.
67 // Note that we're not checking the high bits at all. This means the irq may fire early
68 // if the alarm is more than 72 minutes (2^32 us) in the future. This is OK, since on irq fire
69 // it is checked if the alarm time has passed.
70 TIMER.alarm(n).write_value(timestamp as u32);
71
72 let now = self.now();
73 if timestamp <= now {
74 // If alarm timestamp has passed the alarm will not fire.
75 // Disarm the alarm and return `false` to indicate that.
76 TIMER.armed().write(|w| w.set_armed(1 << n));
77
78 alarm.timestamp.set(u64::MAX);
79
80 false
81 } else {
82 true
83 }
84 }
85
86 fn check_alarm(&self) {
87 let n = 0;
103 critical_section::with(|cs| { 88 critical_section::with(|cs| {
104 let alarm = &self.alarms.borrow(cs)[n]; 89 let alarm = &self.alarms.borrow(cs);
105 let timestamp = alarm.timestamp.get(); 90 let timestamp = alarm.timestamp.get();
106 if timestamp <= self.now() { 91 if timestamp <= self.now() {
107 self.trigger_alarm(n, cs) 92 self.trigger_alarm(cs)
108 } else { 93 } else {
109 // Not elapsed, arm it again. 94 // Not elapsed, arm it again.
110 // This can happen if it was set more than 2^32 us in the future. 95 // This can happen if it was set more than 2^32 us in the future.
@@ -116,16 +101,10 @@ impl TimerDriver {
116 TIMER.intr().write(|w| w.set_alarm(n, true)); 101 TIMER.intr().write(|w| w.set_alarm(n, true));
117 } 102 }
118 103
119 fn trigger_alarm(&self, n: usize, cs: CriticalSection) { 104 fn trigger_alarm(&self, cs: CriticalSection) {
120 // disarm 105 let mut next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now());
121 TIMER.armed().write(|w| w.set_armed(1 << n)); 106 while !self.set_alarm(cs, next) {
122 107 next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now());
123 let alarm = &self.alarms.borrow(cs)[n];
124 alarm.timestamp.set(u64::MAX);
125
126 // Call after clearing alarm, so the callback can set another alarm.
127 if let Some((f, ctx)) = alarm.callback.get() {
128 f(ctx);
129 } 108 }
130 } 109 }
131} 110}
@@ -134,79 +113,32 @@ impl TimerDriver {
134pub unsafe fn init() { 113pub unsafe fn init() {
135 // init alarms 114 // init alarms
136 critical_section::with(|cs| { 115 critical_section::with(|cs| {
137 let alarms = DRIVER.alarms.borrow(cs); 116 let alarm = DRIVER.alarms.borrow(cs);
138 for a in alarms { 117 alarm.timestamp.set(u64::MAX);
139 a.timestamp.set(u64::MAX);
140 }
141 }); 118 });
142 119
143 // enable all irqs 120 // enable irq
144 TIMER.inte().write(|w| { 121 TIMER.inte().write(|w| {
145 w.set_alarm(0, true); 122 w.set_alarm(0, true);
146 w.set_alarm(1, true);
147 w.set_alarm(2, true);
148 w.set_alarm(3, true);
149 }); 123 });
150 #[cfg(feature = "rp2040")] 124 #[cfg(feature = "rp2040")]
151 { 125 {
152 interrupt::TIMER_IRQ_0.enable(); 126 interrupt::TIMER_IRQ_0.enable();
153 interrupt::TIMER_IRQ_1.enable();
154 interrupt::TIMER_IRQ_2.enable();
155 interrupt::TIMER_IRQ_3.enable();
156 } 127 }
157 #[cfg(feature = "_rp235x")] 128 #[cfg(feature = "_rp235x")]
158 { 129 {
159 interrupt::TIMER0_IRQ_0.enable(); 130 interrupt::TIMER0_IRQ_0.enable();
160 interrupt::TIMER0_IRQ_1.enable();
161 interrupt::TIMER0_IRQ_2.enable();
162 interrupt::TIMER0_IRQ_3.enable();
163 } 131 }
164} 132}
165 133
166#[cfg(all(feature = "rt", feature = "rp2040"))] 134#[cfg(all(feature = "rt", feature = "rp2040"))]
167#[interrupt] 135#[interrupt]
168fn TIMER_IRQ_0() { 136fn TIMER_IRQ_0() {
169 DRIVER.check_alarm(0) 137 DRIVER.check_alarm()
170}
171
172#[cfg(all(feature = "rt", feature = "rp2040"))]
173#[interrupt]
174fn TIMER_IRQ_1() {
175 DRIVER.check_alarm(1)
176}
177
178#[cfg(all(feature = "rt", feature = "rp2040"))]
179#[interrupt]
180fn TIMER_IRQ_2() {
181 DRIVER.check_alarm(2)
182}
183
184#[cfg(all(feature = "rt", feature = "rp2040"))]
185#[interrupt]
186fn TIMER_IRQ_3() {
187 DRIVER.check_alarm(3)
188} 138}
189 139
190#[cfg(all(feature = "rt", feature = "_rp235x"))] 140#[cfg(all(feature = "rt", feature = "_rp235x"))]
191#[interrupt] 141#[interrupt]
192fn TIMER0_IRQ_0() { 142fn TIMER0_IRQ_0() {
193 DRIVER.check_alarm(0) 143 DRIVER.check_alarm()
194}
195
196#[cfg(all(feature = "rt", feature = "_rp235x"))]
197#[interrupt]
198fn TIMER0_IRQ_1() {
199 DRIVER.check_alarm(1)
200}
201
202#[cfg(all(feature = "rt", feature = "_rp235x"))]
203#[interrupt]
204fn TIMER0_IRQ_2() {
205 DRIVER.check_alarm(2)
206}
207
208#[cfg(all(feature = "rt", feature = "_rp235x"))]
209#[interrupt]
210fn TIMER0_IRQ_3() {
211 DRIVER.check_alarm(3)
212} 144}
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 8b4e7c929..47e9e8bb9 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -45,6 +45,7 @@ rustdoc-args = ["--cfg", "docsrs"]
45embassy-sync = { version = "0.6.1", path = "../embassy-sync" } 45embassy-sync = { version = "0.6.1", path = "../embassy-sync" }
46embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true } 46embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true }
47embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } 47embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true }
48embassy-time-queue-driver = { version = "0.1", path = "../embassy-time-queue-driver", optional = true }
48embassy-futures = { version = "0.1.0", path = "../embassy-futures" } 49embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
49embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } 50embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] }
50embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal", default-features = false } 51embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal", default-features = false }
@@ -149,7 +150,7 @@ time = ["dep:embassy-time", "embassy-embedded-hal/time"]
149 150
150# Features starting with `_` are for internal use only. They're not intended 151# Features starting with `_` are for internal use only. They're not intended
151# to be enabled by other crates, and are not covered by semver guarantees. 152# to be enabled by other crates, and are not covered by semver guarantees.
152_time-driver = ["dep:embassy-time-driver", "time"] 153_time-driver = ["dep:embassy-time-driver", "time", "dep:embassy-time-queue-driver"]
153 154
154## Use any time driver 155## Use any time driver
155time-driver-any = ["_time-driver"] 156time-driver-any = ["_time-driver"]
diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs
index 0b87bd95a..7734365f1 100644
--- a/embassy-stm32/src/low_power.rs
+++ b/embassy-stm32/src/low_power.rs
@@ -256,9 +256,6 @@ impl Executor {
256 /// This function never returns. 256 /// This function never returns.
257 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! { 257 pub fn run(&'static mut self, init: impl FnOnce(Spawner)) -> ! {
258 let executor = unsafe { EXECUTOR.as_mut().unwrap() }; 258 let executor = unsafe { EXECUTOR.as_mut().unwrap() };
259 unsafe {
260 executor.inner.initialize();
261 }
262 init(executor.inner.spawner()); 259 init(executor.inner.spawner());
263 260
264 loop { 261 loop {
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index 00aa3cfa4..a4c333d82 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -1,13 +1,13 @@
1#![allow(non_snake_case)] 1#![allow(non_snake_case)]
2 2
3use core::cell::Cell; 3use core::cell::{Cell, RefCell};
4use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; 4use core::sync::atomic::{compiler_fence, AtomicU32, Ordering};
5use core::{mem, ptr};
6 5
7use critical_section::CriticalSection; 6use critical_section::CriticalSection;
8use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 7use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
9use embassy_sync::blocking_mutex::Mutex; 8use embassy_sync::blocking_mutex::Mutex;
10use embassy_time_driver::{AlarmHandle, Driver, TICK_HZ}; 9use embassy_time_driver::{Driver, TICK_HZ};
10use embassy_time_queue_driver::Queue;
11use stm32_metapac::timer::{regs, TimGp16}; 11use stm32_metapac::timer::{regs, TimGp16};
12 12
13use crate::interrupt::typelevel::Interrupt; 13use crate::interrupt::typelevel::Interrupt;
@@ -24,18 +24,6 @@ use crate::{interrupt, peripherals};
24// additional CC capabilities to provide timer alarms to embassy-time. embassy-time requires AT LEAST 24// additional CC capabilities to provide timer alarms to embassy-time. embassy-time requires AT LEAST
25// one alarm to be allocatable, which means timers that only have CC1, such as TIM16/TIM17, are not 25// one alarm to be allocatable, which means timers that only have CC1, such as TIM16/TIM17, are not
26// candidates for use as an embassy-time driver provider. (a.k.a 1CH and 1CH_CMP are not, others are good.) 26// candidates for use as an embassy-time driver provider. (a.k.a 1CH and 1CH_CMP are not, others are good.)
27//
28// The values of ALARM_COUNT below are not the TOTAL CC registers available, but rather the number
29// available after reserving CC1 for regular time keeping. For example, TIM2 has four CC registers:
30// CC1, CC2, CC3, and CC4, so it can provide ALARM_COUNT = 3.
31
32cfg_if::cfg_if! {
33 if #[cfg(any(time_driver_tim9, time_driver_tim12, time_driver_tim15, time_driver_tim21, time_driver_tim22))] {
34 const ALARM_COUNT: usize = 1;
35 } else {
36 const ALARM_COUNT: usize = 3;
37 }
38}
39 27
40#[cfg(time_driver_tim1)] 28#[cfg(time_driver_tim1)]
41type T = peripherals::TIM1; 29type T = peripherals::TIM1;
@@ -208,11 +196,6 @@ fn calc_now(period: u32, counter: u16) -> u64 {
208 196
209struct AlarmState { 197struct AlarmState {
210 timestamp: Cell<u64>, 198 timestamp: Cell<u64>,
211
212 // This is really a Option<(fn(*mut ()), *mut ())>
213 // but fn pointers aren't allowed in const yet
214 callback: Cell<*const ()>,
215 ctx: Cell<*mut ()>,
216} 199}
217 200
218unsafe impl Send for AlarmState {} 201unsafe impl Send for AlarmState {}
@@ -221,8 +204,6 @@ impl AlarmState {
221 const fn new() -> Self { 204 const fn new() -> Self {
222 Self { 205 Self {
223 timestamp: Cell::new(u64::MAX), 206 timestamp: Cell::new(u64::MAX),
224 callback: Cell::new(ptr::null()),
225 ctx: Cell::new(ptr::null_mut()),
226 } 207 }
227 } 208 }
228} 209}
@@ -230,19 +211,18 @@ impl AlarmState {
230pub(crate) struct RtcDriver { 211pub(crate) struct RtcDriver {
231 /// Number of 2^15 periods elapsed since boot. 212 /// Number of 2^15 periods elapsed since boot.
232 period: AtomicU32, 213 period: AtomicU32,
233 alarm_count: AtomicU8, 214 alarm: Mutex<CriticalSectionRawMutex, AlarmState>,
234 /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
235 alarms: Mutex<CriticalSectionRawMutex, [AlarmState; ALARM_COUNT]>,
236 #[cfg(feature = "low-power")] 215 #[cfg(feature = "low-power")]
237 rtc: Mutex<CriticalSectionRawMutex, Cell<Option<&'static Rtc>>>, 216 rtc: Mutex<CriticalSectionRawMutex, Cell<Option<&'static Rtc>>>,
217 queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>,
238} 218}
239 219
240embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { 220embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
241 period: AtomicU32::new(0), 221 period: AtomicU32::new(0),
242 alarm_count: AtomicU8::new(0), 222 alarm: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
243 alarms: Mutex::const_new(CriticalSectionRawMutex::new(), [const{AlarmState::new()}; ALARM_COUNT]),
244 #[cfg(feature = "low-power")] 223 #[cfg(feature = "low-power")]
245 rtc: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), 224 rtc: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)),
225 queue: Mutex::new(RefCell::new(Queue::new()))
246}); 226});
247 227
248impl RtcDriver { 228impl RtcDriver {
@@ -288,7 +268,6 @@ impl RtcDriver {
288 fn on_interrupt(&self) { 268 fn on_interrupt(&self) {
289 let r = regs_gp16(); 269 let r = regs_gp16();
290 270
291 // XXX: reduce the size of this critical section ?
292 critical_section::with(|cs| { 271 critical_section::with(|cs| {
293 let sr = r.sr().read(); 272 let sr = r.sr().read();
294 let dier = r.dier().read(); 273 let dier = r.dier().read();
@@ -308,10 +287,9 @@ impl RtcDriver {
308 self.next_period(); 287 self.next_period();
309 } 288 }
310 289
311 for n in 0..ALARM_COUNT { 290 let n = 0;
312 if sr.ccif(n + 1) && dier.ccie(n + 1) { 291 if sr.ccif(n + 1) && dier.ccie(n + 1) {
313 self.trigger_alarm(n, cs); 292 self.trigger_alarm(cs);
314 }
315 } 293 }
316 }) 294 })
317 } 295 }
@@ -326,36 +304,23 @@ impl RtcDriver {
326 304
327 critical_section::with(move |cs| { 305 critical_section::with(move |cs| {
328 r.dier().modify(move |w| { 306 r.dier().modify(move |w| {
329 for n in 0..ALARM_COUNT { 307 let n = 0;
330 let alarm = &self.alarms.borrow(cs)[n]; 308 let alarm = self.alarm.borrow(cs);
331 let at = alarm.timestamp.get(); 309 let at = alarm.timestamp.get();
332 310
333 if at < t + 0xc000 { 311 if at < t + 0xc000 {
334 // just enable it. `set_alarm` has already set the correct CCR val. 312 // just enable it. `set_alarm` has already set the correct CCR val.
335 w.set_ccie(n + 1, true); 313 w.set_ccie(n + 1, true);
336 }
337 } 314 }
338 }) 315 })
339 }) 316 })
340 } 317 }
341 318
342 fn get_alarm<'a>(&'a self, cs: CriticalSection<'a>, alarm: AlarmHandle) -> &'a AlarmState { 319 fn trigger_alarm(&self, cs: CriticalSection) {
343 // safety: we're allowed to assume the AlarmState is created by us, and 320 let mut next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now());
344 // we never create one that's out of bounds. 321 while !self.set_alarm(cs, next) {
345 unsafe { self.alarms.borrow(cs).get_unchecked(alarm.id() as usize) } 322 next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now());
346 } 323 }
347
348 fn trigger_alarm(&self, n: usize, cs: CriticalSection) {
349 let alarm = &self.alarms.borrow(cs)[n];
350 alarm.timestamp.set(u64::MAX);
351
352 // Call after clearing alarm, so the callback can set another alarm.
353
354 // safety:
355 // - we can ignore the possibility of `f` being unset (null) because of the safety contract of `allocate_alarm`.
356 // - other than that we only store valid function pointers into alarm.callback
357 let f: fn(*mut ()) = unsafe { mem::transmute(alarm.callback.get()) };
358 f(alarm.ctx.get());
359 } 324 }
360 325
361 /* 326 /*
@@ -367,14 +332,7 @@ impl RtcDriver {
367 fn time_until_next_alarm(&self, cs: CriticalSection) -> embassy_time::Duration { 332 fn time_until_next_alarm(&self, cs: CriticalSection) -> embassy_time::Duration {
368 let now = self.now() + 32; 333 let now = self.now() + 32;
369 334
370 embassy_time::Duration::from_ticks( 335 embassy_time::Duration::from_ticks(self.alarm.borrow(cs).timestamp.get().saturating_sub(now))
371 self.alarms
372 .borrow(cs)
373 .iter()
374 .map(|alarm: &AlarmState| alarm.timestamp.get().saturating_sub(now))
375 .min()
376 .unwrap_or(u64::MAX),
377 )
378 } 336 }
379 337
380 #[cfg(feature = "low-power")] 338 #[cfg(feature = "low-power")]
@@ -409,15 +367,12 @@ impl RtcDriver {
409 self.period.store(period, Ordering::SeqCst); 367 self.period.store(period, Ordering::SeqCst);
410 regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16)); 368 regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16));
411 369
412 // Now, recompute all alarms 370 // Now, recompute alarm
413 for i in 0..self.alarm_count.load(Ordering::Relaxed) as usize { 371 let alarm = self.alarm.borrow(cs);
414 let alarm_handle = unsafe { AlarmHandle::new(i as u8) };
415 let alarm = self.get_alarm(cs, alarm_handle);
416 372
417 if !self.set_alarm(alarm_handle, alarm.timestamp.get()) { 373 if !self.set_alarm(cs, alarm.timestamp.get()) {
418 // If the alarm timestamp has passed, we need to trigger it 374 // If the alarm timestamp has passed, we need to trigger it
419 self.trigger_alarm(i, cs); 375 self.trigger_alarm(cs);
420 }
421 } 376 }
422 } 377 }
423 378
@@ -489,82 +444,71 @@ impl RtcDriver {
489 regs_gp16().cr1().modify(|w| w.set_cen(true)); 444 regs_gp16().cr1().modify(|w| w.set_cen(true));
490 }) 445 })
491 } 446 }
492}
493 447
494impl Driver for RtcDriver { 448 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
495 fn now(&self) -> u64 {
496 let r = regs_gp16(); 449 let r = regs_gp16();
497 450
498 let period = self.period.load(Ordering::Relaxed); 451 let n = 0;
499 compiler_fence(Ordering::Acquire); 452 self.alarm.borrow(cs).timestamp.set(timestamp);
500 let counter = r.cnt().read().cnt();
501 calc_now(period, counter)
502 }
503 453
504 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> { 454 let t = self.now();
505 critical_section::with(|_| { 455 if timestamp <= t {
506 let id = self.alarm_count.load(Ordering::Relaxed); 456 // If alarm timestamp has passed the alarm will not fire.
507 if id < ALARM_COUNT as u8 { 457 // Disarm the alarm and return `false` to indicate that.
508 self.alarm_count.store(id + 1, Ordering::Relaxed); 458 r.dier().modify(|w| w.set_ccie(n + 1, false));
509 Some(AlarmHandle::new(id))
510 } else {
511 None
512 }
513 })
514 }
515 459
516 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { 460 self.alarm.borrow(cs).timestamp.set(u64::MAX);
517 critical_section::with(|cs| {
518 let alarm = self.get_alarm(cs, alarm);
519 461
520 alarm.callback.set(callback as *const ()); 462 return false;
521 alarm.ctx.set(ctx); 463 }
522 })
523 }
524 464
525 fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { 465 // Write the CCR value regardless of whether we're going to enable it now or not.
526 critical_section::with(|cs| { 466 // This way, when we enable it later, the right value is already set.
527 let r = regs_gp16(); 467 r.ccr(n + 1).write(|w| w.set_ccr(timestamp as u16));
528 468
529 let n = alarm.id() as usize; 469 // Enable it if it'll happen soon. Otherwise, `next_period` will enable it.
530 let alarm = self.get_alarm(cs, alarm); 470 let diff = timestamp - t;
531 alarm.timestamp.set(timestamp); 471 r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000));
532 472
533 let t = self.now(); 473 // Reevaluate if the alarm timestamp is still in the future
534 if timestamp <= t { 474 let t = self.now();
535 // If alarm timestamp has passed the alarm will not fire. 475 if timestamp <= t {
536 // Disarm the alarm and return `false` to indicate that. 476 // If alarm timestamp has passed since we set it, we have a race condition and
537 r.dier().modify(|w| w.set_ccie(n + 1, false)); 477 // the alarm may or may not have fired.
478 // Disarm the alarm and return `false` to indicate that.
479 // It is the caller's responsibility to handle this ambiguity.
480 r.dier().modify(|w| w.set_ccie(n + 1, false));
538 481
539 alarm.timestamp.set(u64::MAX); 482 self.alarm.borrow(cs).timestamp.set(u64::MAX);
540 483
541 return false; 484 return false;
542 } 485 }
543 486
544 // Write the CCR value regardless of whether we're going to enable it now or not. 487 // We're confident the alarm will ring in the future.
545 // This way, when we enable it later, the right value is already set. 488 true
546 r.ccr(n + 1).write(|w| w.set_ccr(timestamp as u16)); 489 }
490}
547 491
548 // Enable it if it'll happen soon. Otherwise, `next_period` will enable it. 492impl Driver for RtcDriver {
549 let diff = timestamp - t; 493 fn now(&self) -> u64 {
550 r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)); 494 let r = regs_gp16();
551 495
552 // Reevaluate if the alarm timestamp is still in the future 496 let period = self.period.load(Ordering::Relaxed);
553 let t = self.now(); 497 compiler_fence(Ordering::Acquire);
554 if timestamp <= t { 498 let counter = r.cnt().read().cnt();
555 // If alarm timestamp has passed since we set it, we have a race condition and 499 calc_now(period, counter)
556 // the alarm may or may not have fired. 500 }
557 // Disarm the alarm and return `false` to indicate that.
558 // It is the caller's responsibility to handle this ambiguity.
559 r.dier().modify(|w| w.set_ccie(n + 1, false));
560 501
561 alarm.timestamp.set(u64::MAX); 502 fn schedule_wake(&self, at: u64, waker: &core::task::Waker) {
503 critical_section::with(|cs| {
504 let mut queue = self.queue.borrow(cs).borrow_mut();
562 505
563 return false; 506 if queue.schedule_wake(at, waker) {
507 let mut next = queue.next_expiration(self.now());
508 while !self.set_alarm(cs, next) {
509 next = queue.next_expiration(self.now());
510 }
564 } 511 }
565
566 // We're confident the alarm will ring in the future.
567 true
568 }) 512 })
569 } 513 }
570} 514}
diff --git a/embassy-time-driver/CHANGELOG.md b/embassy-time-driver/CHANGELOG.md
new file mode 100644
index 000000000..2af1dc736
--- /dev/null
+++ b/embassy-time-driver/CHANGELOG.md
@@ -0,0 +1,15 @@
1# Changelog for embassy-time-driver
2
3All notable changes to this project will be documented in this file.
4
5The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
8## Unreleased
9
10- The `allocate_alarm`, `set_alarm_callback`, `set_alarm` functions have been removed.
11- `schedule_wake` has been added to the `Driver` trait.
12
13## 0.1.0 - 2024-01-11
14
15Initial release
diff --git a/embassy-time-driver/src/lib.rs b/embassy-time-driver/src/lib.rs
index 12f40b9b9..57a9f7587 100644
--- a/embassy-time-driver/src/lib.rs
+++ b/embassy-time-driver/src/lib.rs
@@ -17,28 +17,12 @@
17//! Otherwise, don’t enable any `tick-hz-*` feature to let the user configure the tick rate themselves by 17//! Otherwise, don’t enable any `tick-hz-*` feature to let the user configure the tick rate themselves by
18//! enabling a feature on `embassy-time`. 18//! enabling a feature on `embassy-time`.
19//! 19//!
20//! # Linkage details 20//! ### Example
21//!
22//! Instead of the usual "trait + generic params" approach, calls from embassy to the driver are done via `extern` functions.
23//!
24//! `embassy` internally defines the driver functions as `extern "Rust" { fn _embassy_time_now() -> u64; }` and calls them.
25//! The driver crate defines the functions as `#[no_mangle] fn _embassy_time_now() -> u64`. The linker will resolve the
26//! calls from the `embassy` crate to call into the driver crate.
27//!
28//! If there is none or multiple drivers in the crate tree, linking will fail.
29//!
30//! This method has a few key advantages for something as foundational as timekeeping:
31//!
32//! - The time driver is available everywhere easily, without having to thread the implementation
33//! through generic parameters. This is especially helpful for libraries.
34//! - It means comparing `Instant`s will always make sense: if there were multiple drivers
35//! active, one could compare an `Instant` from driver A to an `Instant` from driver B, which
36//! would yield incorrect results.
37//!
38//! # Example
39//! 21//!
40//! ``` 22//! ```
41//! use embassy_time_driver::{Driver, AlarmHandle}; 23//! use core::task::Waker;
24//!
25//! use embassy_time_driver::Driver;
42//! 26//!
43//! struct MyDriver{} // not public! 27//! struct MyDriver{} // not public!
44//! 28//!
@@ -46,23 +30,79 @@
46//! fn now(&self) -> u64 { 30//! fn now(&self) -> u64 {
47//! todo!() 31//! todo!()
48//! } 32//! }
49//! unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> { 33//!
50//! todo!() 34//! fn schedule_wake(&self, at: u64, waker: &Waker) {
51//! }
52//! fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
53//! todo!()
54//! }
55//! fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool {
56//! todo!() 35//! todo!()
57//! } 36//! }
58//! } 37//! }
59//! 38//!
60//! embassy_time_driver::time_driver_impl!(static DRIVER: MyDriver = MyDriver{}); 39//! embassy_time_driver::time_driver_impl!(static DRIVER: MyDriver = MyDriver{});
61//! ``` 40//! ```
41//!
42//! ## Implementing the timer queue
43//!
44//! The simplest (but suboptimal) way to implement a timer queue is to define a single queue in the
45//! time driver. Declare a field protected by an appropriate mutex (e.g. `critical_section::Mutex`).
46//!
47//! Then, you'll need to adapt the `schedule_wake` method to use this queue.
48//!
49//! ```ignore
50//! use core::cell::RefCell;
51//! use core::task::Waker;
52//!
53//! use embassy_time_queue_driver::Queue;
54//! use embassy_time_driver::Driver;
55//!
56//! struct MyDriver {
57//! timer_queue: critical_section::Mutex<RefCell<Queue>>,
58//! }
59//!
60//! impl MyDriver {
61//! fn set_alarm(&self, cs: &CriticalSection, at: u64) -> bool {
62//! todo!()
63//! }
64//! }
65//!
66//! impl Driver for MyDriver {
67//! // fn now(&self) -> u64 { ... }
68//!
69//! fn schedule_wake(&self, at: u64, waker: &Waker) {
70//! critical_section::with(|cs| {
71//! let mut queue = self.queue.borrow(cs).borrow_mut();
72//! if queue.schedule_wake(at, waker) {
73//! let mut next = queue.next_expiration(self.now());
74//! while !self.set_alarm(cs, next) {
75//! next = queue.next_expiration(self.now());
76//! }
77//! }
78//! });
79//! }
80//! }
81//! ```
82//!
83//! # Linkage details
84//!
85//! Instead of the usual "trait + generic params" approach, calls from embassy to the driver are done via `extern` functions.
86//!
87//! `embassy` internally defines the driver function as `extern "Rust" { fn _embassy_time_now() -> u64; }` and calls it.
88//! The driver crate defines the function as `#[no_mangle] fn _embassy_time_now() -> u64`. The linker will resolve the
89//! calls from the `embassy` crate to call into the driver crate.
90//!
91//! If there is none or multiple drivers in the crate tree, linking will fail.
92//!
93//! This method has a few key advantages for something as foundational as timekeeping:
94//!
95//! - The time driver is available everywhere easily, without having to thread the implementation
96//! through generic parameters. This is especially helpful for libraries.
97//! - It means comparing `Instant`s will always make sense: if there were multiple drivers
98//! active, one could compare an `Instant` from driver A to an `Instant` from driver B, which
99//! would yield incorrect results.
62 100
63//! ## Feature flags 101//! ## Feature flags
64#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)] 102#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
65 103
104use core::task::Waker;
105
66mod tick; 106mod tick;
67 107
68/// Ticks per second of the global timebase. 108/// Ticks per second of the global timebase.
@@ -70,28 +110,6 @@ mod tick;
70/// This value is specified by the [`tick-*` Cargo features](crate#tick-rate) 110/// This value is specified by the [`tick-*` Cargo features](crate#tick-rate)
71pub const TICK_HZ: u64 = tick::TICK_HZ; 111pub const TICK_HZ: u64 = tick::TICK_HZ;
72 112
73/// Alarm handle, assigned by the driver.
74#[derive(Clone, Copy)]
75pub struct AlarmHandle {
76 id: u8,
77}
78
79impl AlarmHandle {
80 /// Create an AlarmHandle
81 ///
82 /// Safety: May only be called by the current global Driver impl.
83 /// The impl is allowed to rely on the fact that all `AlarmHandle` instances
84 /// are created by itself in unsafe code (e.g. indexing operations)
85 pub unsafe fn new(id: u8) -> Self {
86 Self { id }
87 }
88
89 /// Get the ID of the AlarmHandle.
90 pub fn id(&self) -> u8 {
91 self.id
92 }
93}
94
95/// Time driver 113/// Time driver
96pub trait Driver: Send + Sync + 'static { 114pub trait Driver: Send + Sync + 'static {
97 /// Return the current timestamp in ticks. 115 /// Return the current timestamp in ticks.
@@ -106,75 +124,13 @@ pub trait Driver: Send + Sync + 'static {
106 /// or chaining multiple timers together. 124 /// or chaining multiple timers together.
107 fn now(&self) -> u64; 125 fn now(&self) -> u64;
108 126
109 /// Try allocating an alarm handle. Returns None if no alarms left. 127 /// Schedules a waker to be awoken at moment `at`.
110 /// Initially the alarm has no callback set, and a null `ctx` pointer. 128 /// If this moment is in the past, the waker might be awoken immediately.
111 /// 129 fn schedule_wake(&self, at: u64, waker: &Waker);
112 /// The allocated alarm is a reusable resource and can be used multiple times.
113 /// Once the alarm has fired, it remains allocated and can be set again without needing
114 /// to be reallocated.
115 ///
116 /// # Safety
117 /// It is UB to make the alarm fire before setting a callback.
118 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle>;
119
120 /// Set the callback function to be called when the alarm triggers.
121 /// The callback may be called from any context (interrupt or thread mode).
122 ///
123 /// The callback is maintained after the alarm has fired. Callers do not need
124 /// to set a callback again before setting another alarm, unless they want to
125 /// change the callback function or context.
126 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ());
127
128 /// Set an alarm at the given timestamp.
129 ///
130 /// ## Behavior
131 ///
132 /// If `timestamp` is in the future, `set_alarm` schedules calling the callback function
133 /// at that time, and returns `true`.
134 ///
135 /// If `timestamp` is in the past, `set_alarm` has two allowed behaviors. Implementations can pick whether to:
136 ///
137 /// - Schedule calling the callback function "immediately", as if the requested timestamp was "now+epsilon" and return `true`, or
138 /// - Not schedule the callback, and return `false`.
139 ///
140 /// Callers must ensure to behave correctly with either behavior.
141 ///
142 /// When callback is called, it is guaranteed that `now()` will return a value greater than or equal to `timestamp`.
143 ///
144 /// ## Reentrancy
145 ///
146 /// Calling the callback from `set_alarm` synchronously is not allowed. If the implementation chooses the first option above,
147 /// it must still call the callback from another context (i.e. an interrupt handler or background thread), it's not allowed
148 /// to call it synchronously in the context `set_alarm` is running.
149 ///
150 /// The reason for the above is callers are explicitly permitted to do both of:
151 /// - Lock a mutex in the alarm callback.
152 /// - Call `set_alarm` while having that mutex locked.
153 ///
154 /// If `set_alarm` called the callback synchronously, it'd cause a deadlock or panic because it'd cause the
155 /// mutex to be locked twice reentrantly in the same context.
156 ///
157 /// ## Overwriting alarms
158 ///
159 /// Only one alarm can be active at a time for each `AlarmHandle`. This overwrites any previously-set alarm if any.
160 ///
161 /// ## Unsetting the alarm
162 ///
163 /// There is no `unset_alarm` API. Instead, callers can call `set_alarm` with `timestamp` set to `u64::MAX`.
164 ///
165 /// This allows for more efficient implementations, since they don't need to distinguish between the "alarm set" and
166 /// "alarm not set" cases, thanks to the fact "Alarm set for u64::MAX" is effectively equivalent for "alarm not set".
167 ///
168 /// This means implementations need to be careful to avoid timestamp overflows. The recommendation is to make `timestamp`
169 /// be in the same units as hardware ticks to avoid any conversions, which makes avoiding overflow easier.
170 fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool;
171} 130}
172 131
173extern "Rust" { 132extern "Rust" {
174 fn _embassy_time_now() -> u64; 133 fn _embassy_time_now() -> u64;
175 fn _embassy_time_allocate_alarm() -> Option<AlarmHandle>;
176 fn _embassy_time_set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ());
177 fn _embassy_time_set_alarm(alarm: AlarmHandle, timestamp: u64) -> bool;
178} 134}
179 135
180/// See [`Driver::now`] 136/// See [`Driver::now`]
@@ -182,23 +138,6 @@ pub fn now() -> u64 {
182 unsafe { _embassy_time_now() } 138 unsafe { _embassy_time_now() }
183} 139}
184 140
185/// See [`Driver::allocate_alarm`]
186///
187/// Safety: it is UB to make the alarm fire before setting a callback.
188pub unsafe fn allocate_alarm() -> Option<AlarmHandle> {
189 _embassy_time_allocate_alarm()
190}
191
192/// See [`Driver::set_alarm_callback`]
193pub fn set_alarm_callback(alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
194 unsafe { _embassy_time_set_alarm_callback(alarm, callback, ctx) }
195}
196
197/// See [`Driver::set_alarm`]
198pub fn set_alarm(alarm: AlarmHandle, timestamp: u64) -> bool {
199 unsafe { _embassy_time_set_alarm(alarm, timestamp) }
200}
201
202/// Set the time Driver implementation. 141/// Set the time Driver implementation.
203/// 142///
204/// See the module documentation for an example. 143/// See the module documentation for an example.
@@ -213,18 +152,8 @@ macro_rules! time_driver_impl {
213 } 152 }
214 153
215 #[no_mangle] 154 #[no_mangle]
216 unsafe fn _embassy_time_allocate_alarm() -> Option<$crate::AlarmHandle> { 155 fn _embassy_time_schedule_wake(at: u64, waker: &core::task::Waker) {
217 <$t as $crate::Driver>::allocate_alarm(&$name) 156 <$t as $crate::Driver>::schedule_wake(&$name, at, waker);
218 }
219
220 #[no_mangle]
221 fn _embassy_time_set_alarm_callback(alarm: $crate::AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
222 <$t as $crate::Driver>::set_alarm_callback(&$name, alarm, callback, ctx)
223 }
224
225 #[no_mangle]
226 fn _embassy_time_set_alarm(alarm: $crate::AlarmHandle, timestamp: u64) -> bool {
227 <$t as $crate::Driver>::set_alarm(&$name, alarm, timestamp)
228 } 157 }
229 }; 158 };
230} 159}
diff --git a/embassy-time-queue-driver/CHANGELOG.md b/embassy-time-queue-driver/CHANGELOG.md
new file mode 100644
index 000000000..a99f250ed
--- /dev/null
+++ b/embassy-time-queue-driver/CHANGELOG.md
@@ -0,0 +1,15 @@
1# Changelog for embassy-time-queue-driver
2
3All notable changes to this project will be documented in this file.
4
5The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
8## Unreleased
9
10- Added `generic-queue-N` features.
11- Added `embassy_time_queue_driver::Queue` struct which uses integrated or a generic storage (configured using `generic-queue-N`).
12
13## 0.1.0 - 2024-01-11
14
15Initial release
diff --git a/embassy-time-queue-driver/Cargo.toml b/embassy-time-queue-driver/Cargo.toml
index 9ce9d79bb..a104f5c39 100644
--- a/embassy-time-queue-driver/Cargo.toml
+++ b/embassy-time-queue-driver/Cargo.toml
@@ -20,6 +20,38 @@ categories = [
20# This is especially common when mixing crates from crates.io and git. 20# This is especially common when mixing crates from crates.io and git.
21links = "embassy-time-queue" 21links = "embassy-time-queue"
22 22
23[dependencies]
24heapless = "0.8"
25embassy-executor = { version = "0.6.3", path = "../embassy-executor" }
26
27[features]
28#! ### Generic Queue
29
30#! By default this crate uses a timer queue implementation that is faster but depends on `embassy-executor`.
31#! It will panic if you try to await any timer when using another executor.
32#!
33#! Alternatively, you can choose to use a "generic" timer queue implementation that works on any executor.
34#! To enable it, enable any of the features below.
35#!
36#! The features also set how many timers are used for the generic queue. At most one
37#! `generic-queue-*` feature can be enabled. If none is enabled, a default of 64 timers is used.
38#!
39#! When using embassy-time from libraries, you should *not* enable any `generic-queue-*` feature, to allow the
40#! end user to pick.
41
42## Generic Queue with 8 timers
43generic-queue-8 = ["_generic-queue"]
44## Generic Queue with 16 timers
45generic-queue-16 = ["_generic-queue"]
46## Generic Queue with 32 timers
47generic-queue-32 = ["_generic-queue"]
48## Generic Queue with 64 timers
49generic-queue-64 = ["_generic-queue"]
50## Generic Queue with 128 timers
51generic-queue-128 = ["_generic-queue"]
52
53_generic-queue = []
54
23[package.metadata.embassy_docs] 55[package.metadata.embassy_docs]
24src_base = "https://github.com/embassy-rs/embassy/blob/embassy-time-queue-driver-v$VERSION/embassy-time-queue-driver/src/" 56src_base = "https://github.com/embassy-rs/embassy/blob/embassy-time-queue-driver-v$VERSION/embassy-time-queue-driver/src/"
25src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-time-queue-driver/src/" 57src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-time-queue-driver/src/"
diff --git a/embassy-time-queue-driver/src/lib.rs b/embassy-time-queue-driver/src/lib.rs
index 50736e8c7..97c81a124 100644
--- a/embassy-time-queue-driver/src/lib.rs
+++ b/embassy-time-queue-driver/src/lib.rs
@@ -2,38 +2,25 @@
2#![doc = include_str!("../README.md")] 2#![doc = include_str!("../README.md")]
3#![warn(missing_docs)] 3#![warn(missing_docs)]
4 4
5//! ## Implementing a timer queue 5//! This crate is an implementation detail of `embassy-time-driver`.
6//! 6//!
7//! - Define a struct `MyTimerQueue` 7//! As a HAL user, you should only depend on this crate if your application does not use
8//! - Implement [`TimerQueue`] for it 8//! `embassy-executor` and your HAL does not configure a generic queue by itself.
9//! - Register it as the global timer queue with [`timer_queue_impl`](crate::timer_queue_impl).
10//! 9//!
11//! ## Example 10//! As a HAL implementer, you need to depend on this crate if you want to implement a time driver,
12//! 11//! but how you should do so is documented in `embassy-time-driver`.
13//! ``` 12
14//! use core::task::Waker;
15//!
16//! use embassy_time::Instant;
17//! use embassy_time::queue::{TimerQueue};
18//!
19//! struct MyTimerQueue{}; // not public!
20//!
21//! impl TimerQueue for MyTimerQueue {
22//! fn schedule_wake(&'static self, at: u64, waker: &Waker) {
23//! todo!()
24//! }
25//! }
26//!
27//! embassy_time_queue_driver::timer_queue_impl!(static QUEUE: MyTimerQueue = MyTimerQueue{});
28//! ```
29use core::task::Waker; 13use core::task::Waker;
30 14
31/// Timer queue 15#[cfg(feature = "_generic-queue")]
32pub trait TimerQueue { 16pub mod queue_generic;
33 /// Schedules a waker in the queue to be awoken at moment `at`. 17#[cfg(not(feature = "_generic-queue"))]
34 /// If this moment is in the past, the waker might be awoken immediately. 18pub mod queue_integrated;
35 fn schedule_wake(&'static self, at: u64, waker: &Waker); 19
36} 20#[cfg(feature = "_generic-queue")]
21pub use queue_generic::Queue;
22#[cfg(not(feature = "_generic-queue"))]
23pub use queue_integrated::Queue;
37 24
38extern "Rust" { 25extern "Rust" {
39 fn _embassy_time_schedule_wake(at: u64, waker: &Waker); 26 fn _embassy_time_schedule_wake(at: u64, waker: &Waker);
@@ -41,20 +28,22 @@ extern "Rust" {
41 28
42/// Schedule the given waker to be woken at `at`. 29/// Schedule the given waker to be woken at `at`.
43pub fn schedule_wake(at: u64, waker: &Waker) { 30pub fn schedule_wake(at: u64, waker: &Waker) {
44 unsafe { _embassy_time_schedule_wake(at, waker) } 31 // This function is not implemented in embassy-time-driver because it needs access to executor
45} 32 // internals. The function updates task state, then delegates to the implementation provided
46 33 // by the time driver.
47/// Set the TimerQueue implementation. 34 #[cfg(not(feature = "_generic-queue"))]
48/// 35 {
49/// See the module documentation for an example. 36 use embassy_executor::raw::task_from_waker;
50#[macro_export] 37 use embassy_executor::raw::timer_queue::TimerEnqueueOperation;
51macro_rules! timer_queue_impl { 38 // The very first thing we must do, before we even access the timer queue, is to
52 (static $name:ident: $t: ty = $val:expr) => { 39 // mark the task a TIMER_QUEUED. This ensures that the task that is being scheduled
53 static $name: $t = $val; 40 // can not be respawn while we are accessing the timer queue.
54 41 let task = task_from_waker(waker);
55 #[no_mangle] 42 if unsafe { task.timer_enqueue() } == TimerEnqueueOperation::Ignore {
56 fn _embassy_time_schedule_wake(at: u64, waker: &core::task::Waker) { 43 // We are not allowed to enqueue the task in the timer queue. This is because the
57 <$t as $crate::TimerQueue>::schedule_wake(&$name, at, waker); 44 // task is not spawned, and so it makes no sense to schedule it.
45 return;
58 } 46 }
59 }; 47 }
48 unsafe { _embassy_time_schedule_wake(at, waker) }
60} 49}
diff --git a/embassy-time-queue-driver/src/queue_generic.rs b/embassy-time-queue-driver/src/queue_generic.rs
new file mode 100644
index 000000000..232035bc6
--- /dev/null
+++ b/embassy-time-queue-driver/src/queue_generic.rs
@@ -0,0 +1,146 @@
1//! Generic timer queue implementations.
2//!
3//! Time queue drivers may use this to simplify their implementation.
4
5use core::cmp::{min, Ordering};
6use core::task::Waker;
7
8use heapless::Vec;
9
10#[derive(Debug)]
11struct Timer {
12 at: u64,
13 waker: Waker,
14}
15
16impl PartialEq for Timer {
17 fn eq(&self, other: &Self) -> bool {
18 self.at == other.at
19 }
20}
21
22impl Eq for Timer {}
23
24impl PartialOrd for Timer {
25 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
26 self.at.partial_cmp(&other.at)
27 }
28}
29
30impl Ord for Timer {
31 fn cmp(&self, other: &Self) -> Ordering {
32 self.at.cmp(&other.at)
33 }
34}
35
36/// A timer queue with a pre-determined capacity.
37pub struct ConstGenericQueue<const QUEUE_SIZE: usize> {
38 queue: Vec<Timer, QUEUE_SIZE>,
39}
40
41impl<const QUEUE_SIZE: usize> ConstGenericQueue<QUEUE_SIZE> {
42 /// Creates a new timer queue.
43 pub const fn new() -> Self {
44 Self { queue: Vec::new() }
45 }
46
47 /// Schedules a task to run at a specific time, and returns whether any changes were made.
48 ///
49 /// If this function returns `true`, the called should find the next expiration time and set
50 /// a new alarm for that time.
51 pub fn schedule_wake(&mut self, at: u64, waker: &Waker) -> bool {
52 self.queue
53 .iter_mut()
54 .find(|timer| timer.waker.will_wake(waker))
55 .map(|timer| {
56 if timer.at > at {
57 timer.at = at;
58 true
59 } else {
60 false
61 }
62 })
63 .unwrap_or_else(|| {
64 let mut timer = Timer {
65 waker: waker.clone(),
66 at,
67 };
68
69 loop {
70 match self.queue.push(timer) {
71 Ok(()) => break,
72 Err(e) => timer = e,
73 }
74
75 self.queue.pop().unwrap().waker.wake();
76 }
77
78 true
79 })
80 }
81
82 /// Dequeues expired timers and returns the next alarm time.
83 pub fn next_expiration(&mut self, now: u64) -> u64 {
84 let mut next_alarm = u64::MAX;
85
86 let mut i = 0;
87 while i < self.queue.len() {
88 let timer = &self.queue[i];
89 if timer.at <= now {
90 let timer = self.queue.swap_remove(i);
91 timer.waker.wake();
92 } else {
93 next_alarm = min(next_alarm, timer.at);
94 i += 1;
95 }
96 }
97
98 next_alarm
99 }
100}
101
102#[cfg(feature = "generic-queue-8")]
103const QUEUE_SIZE: usize = 8;
104#[cfg(feature = "generic-queue-16")]
105const QUEUE_SIZE: usize = 16;
106#[cfg(feature = "generic-queue-32")]
107const QUEUE_SIZE: usize = 32;
108#[cfg(feature = "generic-queue-64")]
109const QUEUE_SIZE: usize = 64;
110#[cfg(feature = "generic-queue-128")]
111const QUEUE_SIZE: usize = 128;
112#[cfg(not(any(
113 feature = "generic-queue-8",
114 feature = "generic-queue-16",
115 feature = "generic-queue-32",
116 feature = "generic-queue-64",
117 feature = "generic-queue-128"
118)))]
119const QUEUE_SIZE: usize = 64;
120
121/// A timer queue with a pre-determined capacity.
122pub struct Queue {
123 queue: ConstGenericQueue<QUEUE_SIZE>,
124}
125
126impl Queue {
127 /// Creates a new timer queue.
128 pub const fn new() -> Self {
129 Self {
130 queue: ConstGenericQueue::new(),
131 }
132 }
133
134 /// Schedules a task to run at a specific time, and returns whether any changes were made.
135 ///
136 /// If this function returns `true`, the called should find the next expiration time and set
137 /// a new alarm for that time.
138 pub fn schedule_wake(&mut self, at: u64, waker: &Waker) -> bool {
139 self.queue.schedule_wake(at, waker)
140 }
141
142 /// Dequeues expired timers and returns the next alarm time.
143 pub fn next_expiration(&mut self, now: u64) -> u64 {
144 self.queue.next_expiration(now)
145 }
146}
diff --git a/embassy-time-queue-driver/src/queue_integrated.rs b/embassy-time-queue-driver/src/queue_integrated.rs
new file mode 100644
index 000000000..6bb4c0c1a
--- /dev/null
+++ b/embassy-time-queue-driver/src/queue_integrated.rs
@@ -0,0 +1,90 @@
1//! Timer queue operations.
2use core::cell::Cell;
3use core::cmp::min;
4use core::task::Waker;
5
6use embassy_executor::raw::TaskRef;
7
8/// A timer queue, with items integrated into tasks.
9pub struct Queue {
10 head: Cell<Option<TaskRef>>,
11}
12
13impl Queue {
14 /// Creates a new timer queue.
15 pub const fn new() -> Self {
16 Self { head: Cell::new(None) }
17 }
18
19 /// Schedules a task to run at a specific time.
20 ///
21 /// If this function returns `true`, the called should find the next expiration time and set
22 /// a new alarm for that time.
23 pub fn schedule_wake(&mut self, at: u64, waker: &Waker) -> bool {
24 let task = embassy_executor::raw::task_from_waker(waker);
25 let item = task.timer_queue_item();
26 if item.next.get().is_none() {
27 // If not in the queue, add it and update.
28 let prev = self.head.replace(Some(task));
29 item.next.set(if prev.is_none() {
30 Some(unsafe { TaskRef::dangling() })
31 } else {
32 prev
33 });
34 item.expires_at.set(at);
35 true
36 } else if at <= item.expires_at.get() {
37 // If expiration is sooner than previously set, update.
38 item.expires_at.set(at);
39 true
40 } else {
41 // Task does not need to be updated.
42 false
43 }
44 }
45
46 /// Dequeues expired timers and returns the next alarm time.
47 ///
48 /// The provided callback will be called for each expired task. Tasks that never expire
49 /// will be removed, but the callback will not be called.
50 pub fn next_expiration(&mut self, now: u64) -> u64 {
51 let mut next_expiration = u64::MAX;
52
53 self.retain(|p| {
54 let item = p.timer_queue_item();
55 let expires = item.expires_at.get();
56
57 if expires <= now {
58 // Timer expired, process task.
59 embassy_executor::raw::wake_task(p);
60 false
61 } else {
62 // Timer didn't yet expire, or never expires.
63 next_expiration = min(next_expiration, expires);
64 expires != u64::MAX
65 }
66 });
67
68 next_expiration
69 }
70
71 fn retain(&self, mut f: impl FnMut(TaskRef) -> bool) {
72 let mut prev = &self.head;
73 while let Some(p) = prev.get() {
74 if unsafe { p == TaskRef::dangling() } {
75 // prev was the last item, stop
76 break;
77 }
78 let item = p.timer_queue_item();
79 if f(p) {
80 // Skip to next
81 prev = &item.next;
82 } else {
83 // Remove it
84 prev.set(item.next.get());
85 item.next.set(None);
86 unsafe { p.timer_dequeue() };
87 }
88 }
89 }
90}
diff --git a/embassy-time/CHANGELOG.md b/embassy-time/CHANGELOG.md
index 3b4d93387..a6acb1ad6 100644
--- a/embassy-time/CHANGELOG.md
+++ b/embassy-time/CHANGELOG.md
@@ -7,10 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7 7
8## Unreleased 8## Unreleased
9 9
10- The `generic-queue` and related features have been removed (moved to embassy-time-queue-driver)
11- embassy-time no longer provides an `embassy-time-queue-driver` implementation
12
10## 0.3.2 - 2024-08-05 13## 0.3.2 - 2024-08-05
11 14
12- Implement with_timeout()/with_deadline() method style call on Future 15- Implement with_timeout()/with_deadline() method style call on Future
13- Add collapse_debuginfo to fmt.rs macros. 16- Add collapse_debuginfo to fmt.rs macros.
14 17
15## 0.3.1 - 2024-01-11 18## 0.3.1 - 2024-01-11
16 19
diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml
index 8c7de9840..e3074119f 100644
--- a/embassy-time/Cargo.toml
+++ b/embassy-time/Cargo.toml
@@ -42,29 +42,6 @@ defmt-timestamp-uptime-tus = ["defmt"]
42## Create a `MockDriver` that can be manually advanced for testing purposes. 42## Create a `MockDriver` that can be manually advanced for testing purposes.
43mock-driver = ["tick-hz-1_000_000"] 43mock-driver = ["tick-hz-1_000_000"]
44 44
45#! ### Generic Queue
46
47## Create a global, generic queue that can be used with any executor.
48## To use this you must have a time driver provided.
49generic-queue = []
50
51#! The following features set how many timers are used for the generic queue. At most one
52#! `generic-queue-*` feature can be enabled. If none is enabled, a default of 64 timers is used.
53#!
54#! When using embassy-time from libraries, you should *not* enable any `generic-queue-*` feature, to allow the
55#! end user to pick.
56
57## Generic Queue with 8 timers
58generic-queue-8 = ["generic-queue"]
59## Generic Queue with 16 timers
60generic-queue-16 = ["generic-queue"]
61## Generic Queue with 32 timers
62generic-queue-32 = ["generic-queue"]
63## Generic Queue with 64 timers
64generic-queue-64 = ["generic-queue"]
65## Generic Queue with 128 timers
66generic-queue-128 = ["generic-queue"]
67
68#! ### Tick Rate 45#! ### Tick Rate
69#! 46#!
70#! At most 1 `tick-*` feature can be enabled. If none is enabled, a default of 1MHz is used. 47#! At most 1 `tick-*` feature can be enabled. If none is enabled, a default of 1MHz is used.
@@ -419,7 +396,6 @@ embedded-hal-async = { version = "1.0" }
419futures-util = { version = "0.3.17", default-features = false } 396futures-util = { version = "0.3.17", default-features = false }
420critical-section = "1.1" 397critical-section = "1.1"
421cfg-if = "1.0.0" 398cfg-if = "1.0.0"
422heapless = "0.8"
423 399
424document-features = "0.2.7" 400document-features = "0.2.7"
425 401
diff --git a/embassy-time/src/driver_mock.rs b/embassy-time/src/driver_mock.rs
index 8587f9172..138d60499 100644
--- a/embassy-time/src/driver_mock.rs
+++ b/embassy-time/src/driver_mock.rs
@@ -1,7 +1,9 @@
1use core::cell::RefCell; 1use core::cell::RefCell;
2use core::task::Waker;
2 3
3use critical_section::Mutex as CsMutex; 4use critical_section::Mutex as CsMutex;
4use embassy_time_driver::{AlarmHandle, Driver}; 5use embassy_time_driver::Driver;
6use embassy_time_queue_driver::Queue;
5 7
6use crate::{Duration, Instant}; 8use crate::{Duration, Instant};
7 9
@@ -52,29 +54,13 @@ impl MockDriver {
52 /// Advances the time by the specified [`Duration`]. 54 /// Advances the time by the specified [`Duration`].
53 /// Calling any alarm callbacks that are due. 55 /// Calling any alarm callbacks that are due.
54 pub fn advance(&self, duration: Duration) { 56 pub fn advance(&self, duration: Duration) {
55 let notify = { 57 critical_section::with(|cs| {
56 critical_section::with(|cs| { 58 let inner = &mut *self.0.borrow_ref_mut(cs);
57 let mut inner = self.0.borrow_ref_mut(cs);
58
59 inner.now += duration;
60
61 let now = inner.now.as_ticks();
62
63 inner
64 .alarm
65 .as_mut()
66 .filter(|alarm| alarm.timestamp <= now)
67 .map(|alarm| {
68 alarm.timestamp = u64::MAX;
69
70 (alarm.callback, alarm.ctx)
71 })
72 })
73 };
74 59
75 if let Some((callback, ctx)) = notify { 60 inner.now += duration;
76 (callback)(ctx); 61 // wake expired tasks.
77 } 62 inner.queue.next_expiration(inner.now.as_ticks());
63 })
78 } 64 }
79} 65}
80 66
@@ -83,87 +69,37 @@ impl Driver for MockDriver {
83 critical_section::with(|cs| self.0.borrow_ref(cs).now).as_ticks() 69 critical_section::with(|cs| self.0.borrow_ref(cs).now).as_ticks()
84 } 70 }
85 71
86 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> { 72 fn schedule_wake(&self, at: u64, waker: &Waker) {
87 critical_section::with(|cs| { 73 critical_section::with(|cs| {
88 let mut inner = self.0.borrow_ref_mut(cs); 74 let inner = &mut *self.0.borrow_ref_mut(cs);
89 75 // enqueue it
90 if inner.alarm.is_some() { 76 inner.queue.schedule_wake(at, waker);
91 None 77 // wake it if it's in the past.
92 } else { 78 inner.queue.next_expiration(inner.now.as_ticks());
93 inner.alarm.replace(AlarmState::new());
94
95 Some(AlarmHandle::new(0))
96 }
97 })
98 }
99
100 fn set_alarm_callback(&self, _alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
101 critical_section::with(|cs| {
102 let mut inner = self.0.borrow_ref_mut(cs);
103
104 let Some(alarm) = inner.alarm.as_mut() else {
105 panic!("Alarm not allocated");
106 };
107
108 alarm.callback = callback;
109 alarm.ctx = ctx;
110 });
111 }
112
113 fn set_alarm(&self, _alarm: AlarmHandle, timestamp: u64) -> bool {
114 critical_section::with(|cs| {
115 let mut inner = self.0.borrow_ref_mut(cs);
116
117 if timestamp <= inner.now.as_ticks() {
118 false
119 } else {
120 let Some(alarm) = inner.alarm.as_mut() else {
121 panic!("Alarm not allocated");
122 };
123
124 alarm.timestamp = timestamp;
125 true
126 }
127 }) 79 })
128 } 80 }
129} 81}
130 82
131struct InnerMockDriver { 83struct InnerMockDriver {
132 now: Instant, 84 now: Instant,
133 alarm: Option<AlarmState>, 85 queue: Queue,
134} 86}
135 87
136impl InnerMockDriver { 88impl InnerMockDriver {
137 const fn new() -> Self { 89 const fn new() -> Self {
138 Self { 90 Self {
139 now: Instant::from_ticks(0), 91 now: Instant::from_ticks(0),
140 alarm: None, 92 queue: Queue::new(),
141 }
142 }
143}
144
145struct AlarmState {
146 timestamp: u64,
147 callback: fn(*mut ()),
148 ctx: *mut (),
149}
150
151impl AlarmState {
152 const fn new() -> Self {
153 Self {
154 timestamp: u64::MAX,
155 callback: Self::noop,
156 ctx: core::ptr::null_mut(),
157 } 93 }
158 } 94 }
159
160 fn noop(_ctx: *mut ()) {}
161} 95}
162 96
163unsafe impl Send for AlarmState {}
164
165#[cfg(test)] 97#[cfg(test)]
166mod tests { 98mod tests {
99 use core::sync::atomic::{AtomicBool, Ordering};
100 use std::sync::Arc;
101 use std::task::Wake;
102
167 use serial_test::serial; 103 use serial_test::serial;
168 104
169 use super::*; 105 use super::*;
@@ -185,37 +121,25 @@ mod tests {
185 121
186 #[test] 122 #[test]
187 #[serial] 123 #[serial]
188 fn test_set_alarm_not_in_future() { 124 fn test_schedule_wake() {
189 setup(); 125 setup();
190 126
191 let driver = MockDriver::get(); 127 static CALLBACK_CALLED: AtomicBool = AtomicBool::new(false);
192 let alarm = unsafe { AlarmHandle::new(0) };
193 assert_eq!(false, driver.set_alarm(alarm, driver.now()));
194 }
195 128
196 #[test] 129 struct MockWaker;
197 #[serial]
198 fn test_alarm() {
199 setup();
200
201 let driver = MockDriver::get();
202 let alarm = unsafe { driver.allocate_alarm() }.expect("No alarms available");
203 static mut CALLBACK_CALLED: bool = false;
204 let ctx = &mut () as *mut ();
205 driver.set_alarm_callback(alarm, |_| unsafe { CALLBACK_CALLED = true }, ctx);
206 driver.set_alarm(alarm, driver.now() + 1);
207 assert_eq!(false, unsafe { CALLBACK_CALLED });
208 driver.advance(Duration::from_secs(1));
209 assert_eq!(true, unsafe { CALLBACK_CALLED });
210 }
211 130
212 #[test] 131 impl Wake for MockWaker {
213 #[serial] 132 fn wake(self: Arc<Self>) {
214 fn test_allocate_alarm() { 133 CALLBACK_CALLED.store(true, Ordering::Relaxed);
215 setup(); 134 }
135 }
136 let waker = Arc::new(MockWaker).into();
216 137
217 let driver = MockDriver::get(); 138 let driver = MockDriver::get();
218 assert!(unsafe { driver.allocate_alarm() }.is_some()); 139
219 assert!(unsafe { driver.allocate_alarm() }.is_none()); 140 driver.schedule_wake(driver.now() + 1, &waker);
141 assert_eq!(false, CALLBACK_CALLED.load(Ordering::Relaxed));
142 driver.advance(Duration::from_secs(1));
143 assert_eq!(true, CALLBACK_CALLED.load(Ordering::Relaxed));
220 } 144 }
221} 145}
diff --git a/embassy-time/src/driver_std.rs b/embassy-time/src/driver_std.rs
index cbef7aae1..35888fddd 100644
--- a/embassy-time/src/driver_std.rs
+++ b/embassy-time/src/driver_std.rs
@@ -1,160 +1,66 @@
1use core::sync::atomic::{AtomicU8, Ordering}; 1use std::sync::{Condvar, Mutex};
2use std::cell::{RefCell, UnsafeCell}; 2use std::thread;
3use std::mem::MaybeUninit;
4use std::sync::{Condvar, Mutex, Once};
5use std::time::{Duration as StdDuration, Instant as StdInstant}; 3use std::time::{Duration as StdDuration, Instant as StdInstant};
6use std::{mem, ptr, thread};
7 4
8use critical_section::Mutex as CsMutex; 5use embassy_time_driver::Driver;
9use embassy_time_driver::{AlarmHandle, Driver}; 6use embassy_time_queue_driver::Queue;
10 7
11const ALARM_COUNT: usize = 4; 8struct TimeDriver {
12 9 signaler: Signaler,
13struct AlarmState { 10 inner: Mutex<Inner>,
14 timestamp: u64,
15
16 // This is really a Option<(fn(*mut ()), *mut ())>
17 // but fn pointers aren't allowed in const yet
18 callback: *const (),
19 ctx: *mut (),
20} 11}
21 12
22unsafe impl Send for AlarmState {} 13struct Inner {
23 14 zero_instant: Option<StdInstant>,
24impl AlarmState { 15 queue: Queue,
25 const fn new() -> Self {
26 Self {
27 timestamp: u64::MAX,
28 callback: ptr::null(),
29 ctx: ptr::null_mut(),
30 }
31 }
32}
33
34struct TimeDriver {
35 alarm_count: AtomicU8,
36
37 once: Once,
38 // The STD Driver implementation requires the alarms' mutex to be reentrant, which the STD Mutex isn't
39 // Fortunately, mutexes based on the `critical-section` crate are reentrant, because the critical sections
40 // themselves are reentrant
41 alarms: UninitCell<CsMutex<RefCell<[AlarmState; ALARM_COUNT]>>>,
42 zero_instant: UninitCell<StdInstant>,
43 signaler: UninitCell<Signaler>,
44} 16}
45 17
46embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { 18embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver {
47 alarm_count: AtomicU8::new(0), 19 inner: Mutex::new(Inner{
48 20 zero_instant: None,
49 once: Once::new(), 21 queue: Queue::new(),
50 alarms: UninitCell::uninit(), 22 }),
51 zero_instant: UninitCell::uninit(), 23 signaler: Signaler::new(),
52 signaler: UninitCell::uninit(),
53}); 24});
54 25
55impl TimeDriver { 26impl Inner {
56 fn init(&self) { 27 fn init(&mut self) -> StdInstant {
57 self.once.call_once(|| unsafe { 28 *self.zero_instant.get_or_insert_with(|| {
58 self.alarms 29 thread::spawn(alarm_thread);
59 .write(CsMutex::new(RefCell::new([const { AlarmState::new() }; ALARM_COUNT]))); 30 StdInstant::now()
60 self.zero_instant.write(StdInstant::now()); 31 })
61 self.signaler.write(Signaler::new());
62
63 thread::spawn(Self::alarm_thread);
64 });
65 }
66
67 fn alarm_thread() {
68 let zero = unsafe { DRIVER.zero_instant.read() };
69 loop {
70 let now = DRIVER.now();
71
72 let next_alarm = critical_section::with(|cs| {
73 let alarms = unsafe { DRIVER.alarms.as_ref() }.borrow(cs);
74 loop {
75 let pending = alarms
76 .borrow_mut()
77 .iter_mut()
78 .find(|alarm| alarm.timestamp <= now)
79 .map(|alarm| {
80 alarm.timestamp = u64::MAX;
81
82 (alarm.callback, alarm.ctx)
83 });
84
85 if let Some((callback, ctx)) = pending {
86 // safety:
87 // - we can ignore the possiblity of `f` being unset (null) because of the safety contract of `allocate_alarm`.
88 // - other than that we only store valid function pointers into alarm.callback
89 let f: fn(*mut ()) = unsafe { mem::transmute(callback) };
90 f(ctx);
91 } else {
92 // No alarm due
93 break;
94 }
95 }
96
97 alarms
98 .borrow()
99 .iter()
100 .map(|alarm| alarm.timestamp)
101 .min()
102 .unwrap_or(u64::MAX)
103 });
104
105 // Ensure we don't overflow
106 let until = zero
107 .checked_add(StdDuration::from_micros(next_alarm))
108 .unwrap_or_else(|| StdInstant::now() + StdDuration::from_secs(1));
109
110 unsafe { DRIVER.signaler.as_ref() }.wait_until(until);
111 }
112 } 32 }
113} 33}
114 34
115impl Driver for TimeDriver { 35impl Driver for TimeDriver {
116 fn now(&self) -> u64 { 36 fn now(&self) -> u64 {
117 self.init(); 37 let mut inner = self.inner.lock().unwrap();
118 38 let zero = inner.init();
119 let zero = unsafe { self.zero_instant.read() };
120 StdInstant::now().duration_since(zero).as_micros() as u64 39 StdInstant::now().duration_since(zero).as_micros() as u64
121 } 40 }
122 41
123 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> { 42 fn schedule_wake(&self, at: u64, waker: &core::task::Waker) {
124 let id = self.alarm_count.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| { 43 let mut inner = self.inner.lock().unwrap();
125 if x < ALARM_COUNT as u8 { 44 inner.init();
126 Some(x + 1) 45 if inner.queue.schedule_wake(at, waker) {
127 } else { 46 self.signaler.signal();
128 None
129 }
130 });
131
132 match id {
133 Ok(id) => Some(AlarmHandle::new(id)),
134 Err(_) => None,
135 } 47 }
136 } 48 }
49}
137 50
138 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { 51fn alarm_thread() {
139 self.init(); 52 let zero = DRIVER.inner.lock().unwrap().zero_instant.unwrap();
140 critical_section::with(|cs| { 53 loop {
141 let mut alarms = unsafe { self.alarms.as_ref() }.borrow_ref_mut(cs); 54 let now = DRIVER.now();
142 let alarm = &mut alarms[alarm.id() as usize]; 55
143 alarm.callback = callback as *const (); 56 let next_alarm = DRIVER.inner.lock().unwrap().queue.next_expiration(now);
144 alarm.ctx = ctx;
145 });
146 }
147 57
148 fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { 58 // Ensure we don't overflow
149 self.init(); 59 let until = zero
150 critical_section::with(|cs| { 60 .checked_add(StdDuration::from_micros(next_alarm))
151 let mut alarms = unsafe { self.alarms.as_ref() }.borrow_ref_mut(cs); 61 .unwrap_or_else(|| StdInstant::now() + StdDuration::from_secs(1));
152 let alarm = &mut alarms[alarm.id() as usize];
153 alarm.timestamp = timestamp;
154 unsafe { self.signaler.as_ref() }.signal();
155 });
156 62
157 true 63 DRIVER.signaler.wait_until(until);
158 } 64 }
159} 65}
160 66
@@ -164,7 +70,7 @@ struct Signaler {
164} 70}
165 71
166impl Signaler { 72impl Signaler {
167 fn new() -> Self { 73 const fn new() -> Self {
168 Self { 74 Self {
169 mutex: Mutex::new(false), 75 mutex: Mutex::new(false),
170 condvar: Condvar::new(), 76 condvar: Condvar::new(),
@@ -196,35 +102,3 @@ impl Signaler {
196 self.condvar.notify_one(); 102 self.condvar.notify_one();
197 } 103 }
198} 104}
199
200pub(crate) struct UninitCell<T>(MaybeUninit<UnsafeCell<T>>);
201unsafe impl<T> Send for UninitCell<T> {}
202unsafe impl<T> Sync for UninitCell<T> {}
203
204impl<T> UninitCell<T> {
205 pub const fn uninit() -> Self {
206 Self(MaybeUninit::uninit())
207 }
208
209 pub unsafe fn as_ptr(&self) -> *const T {
210 (*self.0.as_ptr()).get()
211 }
212
213 pub unsafe fn as_mut_ptr(&self) -> *mut T {
214 (*self.0.as_ptr()).get()
215 }
216
217 pub unsafe fn as_ref(&self) -> &T {
218 &*self.as_ptr()
219 }
220
221 pub unsafe fn write(&self, val: T) {
222 ptr::write(self.as_mut_ptr(), val)
223 }
224}
225
226impl<T: Copy> UninitCell<T> {
227 pub unsafe fn read(&self) -> T {
228 ptr::read(self.as_mut_ptr())
229 }
230}
diff --git a/embassy-time/src/driver_wasm.rs b/embassy-time/src/driver_wasm.rs
index d65629e49..bcdd1670b 100644
--- a/embassy-time/src/driver_wasm.rs
+++ b/embassy-time/src/driver_wasm.rs
@@ -1,28 +1,17 @@
1use core::sync::atomic::{AtomicU8, Ordering}; 1use std::sync::Mutex;
2use std::cell::UnsafeCell;
3use std::mem::MaybeUninit;
4use std::ptr;
5use std::sync::{Mutex, Once};
6 2
7use embassy_time_driver::{AlarmHandle, Driver}; 3use embassy_time_driver::Driver;
4use embassy_time_queue_driver::Queue;
8use wasm_bindgen::prelude::*; 5use wasm_bindgen::prelude::*;
9use wasm_timer::Instant as StdInstant; 6use wasm_timer::Instant as StdInstant;
10 7
11const ALARM_COUNT: usize = 4;
12
13struct AlarmState { 8struct AlarmState {
14 token: Option<f64>, 9 token: Option<f64>,
15 closure: Option<Closure<dyn FnMut() + 'static>>,
16} 10}
17 11
18unsafe impl Send for AlarmState {}
19
20impl AlarmState { 12impl AlarmState {
21 const fn new() -> Self { 13 const fn new() -> Self {
22 Self { 14 Self { token: None }
23 token: None,
24 closure: None,
25 }
26 } 15 }
27} 16}
28 17
@@ -33,67 +22,38 @@ extern "C" {
33} 22}
34 23
35struct TimeDriver { 24struct TimeDriver {
36 alarm_count: AtomicU8, 25 inner: Mutex<Inner>,
37
38 once: Once,
39 alarms: UninitCell<Mutex<[AlarmState; ALARM_COUNT]>>,
40 zero_instant: UninitCell<StdInstant>,
41} 26}
42 27
43embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { 28struct Inner {
44 alarm_count: AtomicU8::new(0), 29 alarm: AlarmState,
45 once: Once::new(), 30 zero_instant: Option<StdInstant>,
46 alarms: UninitCell::uninit(), 31 queue: Queue,
47 zero_instant: UninitCell::uninit(), 32 closure: Option<Closure<dyn FnMut()>>,
48});
49
50impl TimeDriver {
51 fn init(&self) {
52 self.once.call_once(|| unsafe {
53 self.alarms
54 .write(Mutex::new([const { AlarmState::new() }; ALARM_COUNT]));
55 self.zero_instant.write(StdInstant::now());
56 });
57 }
58} 33}
59 34
60impl Driver for TimeDriver { 35unsafe impl Send for Inner {}
61 fn now(&self) -> u64 {
62 self.init();
63 36
64 let zero = unsafe { self.zero_instant.read() }; 37embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver {
65 StdInstant::now().duration_since(zero).as_micros() as u64 38 inner: Mutex::new(Inner{
66 } 39 zero_instant: None,
67 40 queue: Queue::new(),
68 unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> { 41 alarm: AlarmState::new(),
69 let id = self.alarm_count.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| { 42 closure: None,
70 if x < ALARM_COUNT as u8 { 43 }),
71 Some(x + 1) 44});
72 } else {
73 None
74 }
75 });
76 45
77 match id { 46impl Inner {
78 Ok(id) => Some(AlarmHandle::new(id)), 47 fn init(&mut self) -> StdInstant {
79 Err(_) => None, 48 *self.zero_instant.get_or_insert_with(StdInstant::now)
80 }
81 } 49 }
82 50
83 fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { 51 fn now(&mut self) -> u64 {
84 self.init(); 52 StdInstant::now().duration_since(self.zero_instant.unwrap()).as_micros() as u64
85 let mut alarms = unsafe { self.alarms.as_ref() }.lock().unwrap();
86 let alarm = &mut alarms[alarm.id() as usize];
87 alarm.closure.replace(Closure::new(move || {
88 callback(ctx);
89 }));
90 } 53 }
91 54
92 fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { 55 fn set_alarm(&mut self, timestamp: u64) -> bool {
93 self.init(); 56 if let Some(token) = self.alarm.token {
94 let mut alarms = unsafe { self.alarms.as_ref() }.lock().unwrap();
95 let alarm = &mut alarms[alarm.id() as usize];
96 if let Some(token) = alarm.token {
97 clearTimeout(token); 57 clearTimeout(token);
98 } 58 }
99 59
@@ -102,40 +62,42 @@ impl Driver for TimeDriver {
102 false 62 false
103 } else { 63 } else {
104 let timeout = (timestamp - now) as u32; 64 let timeout = (timestamp - now) as u32;
105 alarm.token = Some(setTimeout(alarm.closure.as_ref().unwrap(), timeout / 1000)); 65 let closure = self.closure.get_or_insert_with(|| Closure::new(dispatch));
66 self.alarm.token = Some(setTimeout(closure, timeout / 1000));
106 67
107 true 68 true
108 } 69 }
109 } 70 }
110} 71}
111 72
112pub(crate) struct UninitCell<T>(MaybeUninit<UnsafeCell<T>>); 73impl Driver for TimeDriver {
113unsafe impl<T> Send for UninitCell<T> {} 74 fn now(&self) -> u64 {
114unsafe impl<T> Sync for UninitCell<T> {} 75 let mut inner = self.inner.lock().unwrap();
115 76 let zero = inner.init();
116impl<T> UninitCell<T> { 77 StdInstant::now().duration_since(zero).as_micros() as u64
117 pub const fn uninit() -> Self {
118 Self(MaybeUninit::uninit())
119 }
120 unsafe fn as_ptr(&self) -> *const T {
121 (*self.0.as_ptr()).get()
122 }
123
124 pub unsafe fn as_mut_ptr(&self) -> *mut T {
125 (*self.0.as_ptr()).get()
126 }
127
128 pub unsafe fn as_ref(&self) -> &T {
129 &*self.as_ptr()
130 } 78 }
131 79
132 pub unsafe fn write(&self, val: T) { 80 fn schedule_wake(&self, at: u64, waker: &core::task::Waker) {
133 ptr::write(self.as_mut_ptr(), val) 81 let mut inner = self.inner.lock().unwrap();
82 inner.init();
83 if inner.queue.schedule_wake(at, waker) {
84 let now = inner.now();
85 let mut next = inner.queue.next_expiration(now);
86 while !inner.set_alarm(next) {
87 let now = inner.now();
88 next = inner.queue.next_expiration(now);
89 }
90 }
134 } 91 }
135} 92}
136 93
137impl<T: Copy> UninitCell<T> { 94fn dispatch() {
138 pub unsafe fn read(&self) -> T { 95 let inner = &mut *DRIVER.inner.lock().unwrap();
139 ptr::read(self.as_mut_ptr()) 96
97 let now = inner.now();
98 let mut next = inner.queue.next_expiration(now);
99 while !inner.set_alarm(next) {
100 let now = inner.now();
101 next = inner.queue.next_expiration(now);
140 } 102 }
141} 103}
diff --git a/embassy-time/src/lib.rs b/embassy-time/src/lib.rs
index 8d0648ce5..80a359413 100644
--- a/embassy-time/src/lib.rs
+++ b/embassy-time/src/lib.rs
@@ -25,8 +25,6 @@ pub use driver_mock::MockDriver;
25mod driver_std; 25mod driver_std;
26#[cfg(feature = "wasm")] 26#[cfg(feature = "wasm")]
27mod driver_wasm; 27mod driver_wasm;
28#[cfg(feature = "generic-queue")]
29mod queue_generic;
30 28
31pub use delay::{block_for, Delay}; 29pub use delay::{block_for, Delay};
32pub use duration::Duration; 30pub use duration::Duration;
diff --git a/embassy-time/src/queue_generic.rs b/embassy-time/src/queue_generic.rs
deleted file mode 100644
index 0068edae8..000000000
--- a/embassy-time/src/queue_generic.rs
+++ /dev/null
@@ -1,346 +0,0 @@
1use core::cell::RefCell;
2use core::cmp::{min, Ordering};
3use core::task::Waker;
4
5use critical_section::Mutex;
6use embassy_time_driver::{allocate_alarm, set_alarm, set_alarm_callback, AlarmHandle};
7use embassy_time_queue_driver::TimerQueue;
8use heapless::Vec;
9
10use crate::Instant;
11
12#[cfg(feature = "generic-queue-8")]
13const QUEUE_SIZE: usize = 8;
14#[cfg(feature = "generic-queue-16")]
15const QUEUE_SIZE: usize = 16;
16#[cfg(feature = "generic-queue-32")]
17const QUEUE_SIZE: usize = 32;
18#[cfg(feature = "generic-queue-64")]
19const QUEUE_SIZE: usize = 64;
20#[cfg(feature = "generic-queue-128")]
21const QUEUE_SIZE: usize = 128;
22#[cfg(not(any(
23 feature = "generic-queue-8",
24 feature = "generic-queue-16",
25 feature = "generic-queue-32",
26 feature = "generic-queue-64",
27 feature = "generic-queue-128"
28)))]
29const QUEUE_SIZE: usize = 64;
30
31#[derive(Debug)]
32struct Timer {
33 at: Instant,
34 waker: Waker,
35}
36
37impl PartialEq for Timer {
38 fn eq(&self, other: &Self) -> bool {
39 self.at == other.at
40 }
41}
42
43impl Eq for Timer {}
44
45impl PartialOrd for Timer {
46 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
47 self.at.partial_cmp(&other.at)
48 }
49}
50
51impl Ord for Timer {
52 fn cmp(&self, other: &Self) -> Ordering {
53 self.at.cmp(&other.at)
54 }
55}
56
57struct InnerQueue {
58 queue: Vec<Timer, QUEUE_SIZE>,
59 alarm: AlarmHandle,
60}
61
62impl InnerQueue {
63 fn schedule_wake(&mut self, at: Instant, waker: &Waker) {
64 self.queue
65 .iter_mut()
66 .find(|timer| timer.waker.will_wake(waker))
67 .map(|timer| {
68 timer.at = min(timer.at, at);
69 })
70 .unwrap_or_else(|| {
71 let mut timer = Timer {
72 waker: waker.clone(),
73 at,
74 };
75
76 loop {
77 match self.queue.push(timer) {
78 Ok(()) => break,
79 Err(e) => timer = e,
80 }
81
82 self.queue.pop().unwrap().waker.wake();
83 }
84 });
85
86 // Don't wait for the alarm callback to trigger and directly
87 // dispatch all timers that are already due
88 //
89 // Then update the alarm if necessary
90 self.dispatch();
91 }
92
93 fn dispatch(&mut self) {
94 loop {
95 let now = Instant::now();
96
97 let mut next_alarm = Instant::MAX;
98
99 let mut i = 0;
100 while i < self.queue.len() {
101 let timer = &self.queue[i];
102 if timer.at <= now {
103 let timer = self.queue.swap_remove(i);
104 timer.waker.wake();
105 } else {
106 next_alarm = min(next_alarm, timer.at);
107 i += 1;
108 }
109 }
110
111 if self.update_alarm(next_alarm) {
112 break;
113 }
114 }
115 }
116
117 fn update_alarm(&mut self, next_alarm: Instant) -> bool {
118 if next_alarm == Instant::MAX {
119 true
120 } else {
121 set_alarm(self.alarm, next_alarm.as_ticks())
122 }
123 }
124
125 fn handle_alarm(&mut self) {
126 self.dispatch();
127 }
128}
129
130struct Queue {
131 inner: Mutex<RefCell<Option<InnerQueue>>>,
132}
133
134impl Queue {
135 const fn new() -> Self {
136 Self {
137 inner: Mutex::new(RefCell::new(None)),
138 }
139 }
140
141 fn schedule_wake(&'static self, at: Instant, waker: &Waker) {
142 critical_section::with(|cs| {
143 let mut inner = self.inner.borrow_ref_mut(cs);
144
145 inner
146 .get_or_insert_with(|| {
147 let handle = unsafe { allocate_alarm() }.unwrap();
148 set_alarm_callback(handle, Self::handle_alarm_callback, self as *const _ as _);
149 InnerQueue {
150 queue: Vec::new(),
151 alarm: handle,
152 }
153 })
154 .schedule_wake(at, waker)
155 });
156 }
157
158 fn handle_alarm(&self) {
159 critical_section::with(|cs| self.inner.borrow_ref_mut(cs).as_mut().unwrap().handle_alarm())
160 }
161
162 fn handle_alarm_callback(ctx: *mut ()) {
163 unsafe { (ctx as *const Self).as_ref().unwrap() }.handle_alarm();
164 }
165}
166
167impl TimerQueue for Queue {
168 fn schedule_wake(&'static self, at: u64, waker: &Waker) {
169 Queue::schedule_wake(self, Instant::from_ticks(at), waker);
170 }
171}
172
173embassy_time_queue_driver::timer_queue_impl!(static QUEUE: Queue = Queue::new());
174
175#[cfg(test)]
176#[cfg(feature = "mock-driver")]
177mod tests {
178 use core::sync::atomic::{AtomicBool, Ordering};
179 use core::task::Waker;
180 use std::sync::Arc;
181 use std::task::Wake;
182
183 use serial_test::serial;
184
185 use crate::driver_mock::MockDriver;
186 use crate::queue_generic::QUEUE;
187 use crate::{Duration, Instant};
188
189 struct TestWaker {
190 pub awoken: AtomicBool,
191 }
192
193 impl Wake for TestWaker {
194 fn wake(self: Arc<Self>) {
195 self.awoken.store(true, Ordering::Relaxed);
196 }
197
198 fn wake_by_ref(self: &Arc<Self>) {
199 self.awoken.store(true, Ordering::Relaxed);
200 }
201 }
202
203 fn test_waker() -> (Arc<TestWaker>, Waker) {
204 let arc = Arc::new(TestWaker {
205 awoken: AtomicBool::new(false),
206 });
207 let waker = Waker::from(arc.clone());
208
209 (arc, waker)
210 }
211
212 fn setup() {
213 MockDriver::get().reset();
214 critical_section::with(|cs| *QUEUE.inner.borrow_ref_mut(cs) = None);
215 }
216
217 fn queue_len() -> usize {
218 critical_section::with(|cs| {
219 QUEUE
220 .inner
221 .borrow_ref(cs)
222 .as_ref()
223 .map(|inner| inner.queue.iter().count())
224 .unwrap_or(0)
225 })
226 }
227
228 #[test]
229 #[serial]
230 fn test_schedule() {
231 setup();
232
233 assert_eq!(queue_len(), 0);
234
235 let (flag, waker) = test_waker();
236
237 QUEUE.schedule_wake(Instant::from_secs(1), &waker);
238
239 assert!(!flag.awoken.load(Ordering::Relaxed));
240 assert_eq!(queue_len(), 1);
241 }
242
243 #[test]
244 #[serial]
245 fn test_schedule_same() {
246 setup();
247
248 let (_flag, waker) = test_waker();
249
250 QUEUE.schedule_wake(Instant::from_secs(1), &waker);
251
252 assert_eq!(queue_len(), 1);
253
254 QUEUE.schedule_wake(Instant::from_secs(1), &waker);
255
256 assert_eq!(queue_len(), 1);
257
258 QUEUE.schedule_wake(Instant::from_secs(100), &waker);
259
260 assert_eq!(queue_len(), 1);
261
262 let (_flag2, waker2) = test_waker();
263
264 QUEUE.schedule_wake(Instant::from_secs(100), &waker2);
265
266 assert_eq!(queue_len(), 2);
267 }
268
269 #[test]
270 #[serial]
271 fn test_trigger() {
272 setup();
273
274 let (flag, waker) = test_waker();
275
276 QUEUE.schedule_wake(Instant::from_secs(100), &waker);
277
278 assert!(!flag.awoken.load(Ordering::Relaxed));
279
280 MockDriver::get().advance(Duration::from_secs(99));
281
282 assert!(!flag.awoken.load(Ordering::Relaxed));
283
284 assert_eq!(queue_len(), 1);
285
286 MockDriver::get().advance(Duration::from_secs(1));
287
288 assert!(flag.awoken.load(Ordering::Relaxed));
289
290 assert_eq!(queue_len(), 0);
291 }
292
293 #[test]
294 #[serial]
295 fn test_immediate_trigger() {
296 setup();
297
298 let (flag, waker) = test_waker();
299
300 QUEUE.schedule_wake(Instant::from_secs(100), &waker);
301
302 MockDriver::get().advance(Duration::from_secs(50));
303
304 let (flag2, waker2) = test_waker();
305
306 QUEUE.schedule_wake(Instant::from_secs(40), &waker2);
307
308 assert!(!flag.awoken.load(Ordering::Relaxed));
309 assert!(flag2.awoken.load(Ordering::Relaxed));
310 assert_eq!(queue_len(), 1);
311 }
312
313 #[test]
314 #[serial]
315 fn test_queue_overflow() {
316 setup();
317
318 for i in 1..super::QUEUE_SIZE {
319 let (flag, waker) = test_waker();
320
321 QUEUE.schedule_wake(Instant::from_secs(310), &waker);
322
323 assert_eq!(queue_len(), i);
324 assert!(!flag.awoken.load(Ordering::Relaxed));
325 }
326
327 let (flag, waker) = test_waker();
328
329 QUEUE.schedule_wake(Instant::from_secs(300), &waker);
330
331 assert_eq!(queue_len(), super::QUEUE_SIZE);
332 assert!(!flag.awoken.load(Ordering::Relaxed));
333
334 let (flag2, waker2) = test_waker();
335
336 QUEUE.schedule_wake(Instant::from_secs(305), &waker2);
337
338 assert_eq!(queue_len(), super::QUEUE_SIZE);
339 assert!(flag.awoken.load(Ordering::Relaxed));
340
341 let (_flag3, waker3) = test_waker();
342 QUEUE.schedule_wake(Instant::from_secs(320), &waker3);
343 assert_eq!(queue_len(), super::QUEUE_SIZE);
344 assert!(flag2.awoken.load(Ordering::Relaxed));
345 }
346}
diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml
index 046571e05..45ad341fc 100644
--- a/examples/boot/application/nrf/Cargo.toml
+++ b/examples/boot/application/nrf/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] }
11embassy-nrf = { version = "0.2.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } 11embassy-nrf = { version = "0.2.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] }
12embassy-boot = { version = "0.3.0", path = "../../../../embassy-boot", features = [] } 12embassy-boot = { version = "0.3.0", path = "../../../../embassy-boot", features = [] }
diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml
index f859ddbc6..ec99f2605 100644
--- a/examples/boot/application/rp/Cargo.toml
+++ b/examples/boot/application/rp/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] } 9embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] }
11embassy-rp = { version = "0.2.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] } 11embassy-rp = { version = "0.2.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] }
12embassy-boot-rp = { version = "0.3.0", path = "../../../../embassy-boot-rp", features = [] } 12embassy-boot-rp = { version = "0.3.0", path = "../../../../embassy-boot-rp", features = [] }
diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml
index d5b26d698..d2138db87 100644
--- a/examples/boot/application/stm32f3/Cargo.toml
+++ b/examples/boot/application/stm32f3/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32" } 12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32" }
diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml
index d13692aa8..b86c66f5d 100644
--- a/examples/boot/application/stm32f7/Cargo.toml
+++ b/examples/boot/application/stm32f7/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] }
diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml
index a2de827aa..e2e2fe711 100644
--- a/examples/boot/application/stm32h7/Cargo.toml
+++ b/examples/boot/application/stm32h7/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] }
diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml
index ddfddf652..7e9c52ffa 100644
--- a/examples/boot/application/stm32l0/Cargo.toml
+++ b/examples/boot/application/stm32l0/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] }
diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml
index 4780c20f4..42353a24c 100644
--- a/examples/boot/application/stm32l1/Cargo.toml
+++ b/examples/boot/application/stm32l1/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] }
diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml
index 0a31d6b62..cf0b0242a 100644
--- a/examples/boot/application/stm32l4/Cargo.toml
+++ b/examples/boot/application/stm32l4/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] }
diff --git a/examples/boot/application/stm32wb-dfu/Cargo.toml b/examples/boot/application/stm32wb-dfu/Cargo.toml
index 67f6bde11..ea2879fb5 100644
--- a/examples/boot/application/stm32wb-dfu/Cargo.toml
+++ b/examples/boot/application/stm32wb-dfu/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] }
diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml
index da27d4601..6417b8430 100644
--- a/examples/boot/application/stm32wl/Cargo.toml
+++ b/examples/boot/application/stm32wl/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } 8embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" }
9embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } 9embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] }
10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] }
12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } 12embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] }
diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml
index 449056409..6d13d668a 100644
--- a/examples/nrf-rtos-trace/Cargo.toml
+++ b/examples/nrf-rtos-trace/Cargo.toml
@@ -16,7 +16,7 @@ log = [
16 16
17[dependencies] 17[dependencies]
18embassy-sync = { version = "0.6.1", path = "../../embassy-sync" } 18embassy-sync = { version = "0.6.1", path = "../../embassy-sync" }
19embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] } 19embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace"] }
20embassy-time = { version = "0.3.2", path = "../../embassy-time" } 20embassy-time = { version = "0.3.2", path = "../../embassy-time" }
21embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } 21embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
22 22
diff --git a/examples/nrf51/Cargo.toml b/examples/nrf51/Cargo.toml
index 05e702773..8d995cfd8 100644
--- a/examples/nrf51/Cargo.toml
+++ b/examples/nrf51/Cargo.toml
@@ -5,7 +5,7 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 8embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
9embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 9embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
10embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } 10embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] }
11 11
diff --git a/examples/nrf52810/Cargo.toml b/examples/nrf52810/Cargo.toml
index b0b73417b..fa2a27aaa 100644
--- a/examples/nrf52810/Cargo.toml
+++ b/examples/nrf52810/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
9embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 9embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 10embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
11embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 11embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
12embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 12embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
13 13
diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml
index 290b2fdb1..6b15b24da 100644
--- a/examples/nrf52840-rtic/Cargo.toml
+++ b/examples/nrf52840-rtic/Cargo.toml
@@ -9,7 +9,8 @@ rtic = { version = "2", features = ["thumbv7-backend"] }
9 9
10embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 10embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
11embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 11embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", "generic-queue"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime"] }
13embassy-time-queue-driver = { version = "0.1.0", path = "../../embassy-time-queue-driver", features = ["generic-queue-8"] }
13embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 14embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
14 15
15defmt = "0.3" 16defmt = "0.3"
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml
index 701911a30..fa29d52b9 100644
--- a/examples/nrf52840/Cargo.toml
+++ b/examples/nrf52840/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
9embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 9embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 10embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
11embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 11embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
12embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 12embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
13embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } 13embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }
diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml
index 13442405d..1792b277c 100644
--- a/examples/nrf5340/Cargo.toml
+++ b/examples/nrf5340/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 8embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
9embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 9embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 10embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] }
11embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 11embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
12embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } 12embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] }
13embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } 13embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }
diff --git a/examples/nrf54l15/Cargo.toml b/examples/nrf54l15/Cargo.toml
index 6d11269f7..7288ef6af 100644
--- a/examples/nrf54l15/Cargo.toml
+++ b/examples/nrf54l15/Cargo.toml
@@ -5,7 +5,7 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 8embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
9embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 9embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
10embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 10embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
11 11
diff --git a/examples/nrf9151/ns/Cargo.toml b/examples/nrf9151/ns/Cargo.toml
index 96bf6700d..0353cf598 100644
--- a/examples/nrf9151/ns/Cargo.toml
+++ b/examples/nrf9151/ns/Cargo.toml
@@ -5,7 +5,7 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-executor = { version = "0.6.3", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 8embassy-executor = { version = "0.6.3", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
9embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 9embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
10embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 10embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
11 11
diff --git a/examples/nrf9151/s/Cargo.toml b/examples/nrf9151/s/Cargo.toml
index f7adf259d..5d2302574 100644
--- a/examples/nrf9151/s/Cargo.toml
+++ b/examples/nrf9151/s/Cargo.toml
@@ -5,7 +5,7 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-executor = { version = "0.6.3", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 8embassy-executor = { version = "0.6.3", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
9embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 9embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
10embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 10embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
11 11
diff --git a/examples/nrf9160/Cargo.toml b/examples/nrf9160/Cargo.toml
index 3b404c730..b52cd4af0 100644
--- a/examples/nrf9160/Cargo.toml
+++ b/examples/nrf9160/Cargo.toml
@@ -5,7 +5,7 @@ version = "0.1.0"
5license = "MIT OR Apache-2.0" 5license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 8embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
9embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 9embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
10embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 10embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
11embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] } 11embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] }
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index 2dce1676a..ce812b2e0 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8[dependencies] 8[dependencies]
9embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } 9embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] }
10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
13embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } 13embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] }
14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
diff --git a/examples/rp23/Cargo.toml b/examples/rp23/Cargo.toml
index 2fcad247d..72eef222d 100644
--- a/examples/rp23/Cargo.toml
+++ b/examples/rp23/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8[dependencies] 8[dependencies]
9embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } 9embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] }
10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
13embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] } 13embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] }
14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml
index 77948515a..e43fd77c8 100644
--- a/examples/std/Cargo.toml
+++ b/examples/std/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["log"] } 8embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["log"] }
9embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] } 9embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log"] }
10embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "std", ] } 10embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "std", ] }
11embassy-net = { version = "0.5.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } 11embassy-net = { version = "0.5.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] }
12embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } 12embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" }
diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml
index 895e668da..5ac3018e1 100644
--- a/examples/stm32c0/Cargo.toml
+++ b/examples/stm32c0/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32c031c6 to your chip name, if necessary. 8# Change stm32c031c6 to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] }
10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13 13
14defmt = "0.3" 14defmt = "0.3"
diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml
index 056f8470d..af3ef7abb 100644
--- a/examples/stm32f0/Cargo.toml
+++ b/examples/stm32f0/Cargo.toml
@@ -13,7 +13,7 @@ defmt = "0.3"
13defmt-rtt = "0.4" 13defmt-rtt = "0.4"
14panic-probe = { version = "0.3", features = ["print-defmt"] } 14panic-probe = { version = "0.3", features = ["print-defmt"] }
15embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 15embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
16embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 16embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
17embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 17embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
18static_cell = "2" 18static_cell = "2"
19portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } 19portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] }
diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml
index c081333d7..538e95dfb 100644
--- a/examples/stm32f1/Cargo.toml
+++ b/examples/stm32f1/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32f103c8 to your chip name, if necessary. 8# Change stm32f103c8 to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] }
10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml
index f7993497c..48d524b90 100644
--- a/examples/stm32f2/Cargo.toml
+++ b/examples/stm32f2/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32f207zg to your chip name, if necessary. 8# Change stm32f207zg to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13 13
14defmt = "0.3" 14defmt = "0.3"
diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml
index a7b8935a9..66fb34223 100644
--- a/examples/stm32f3/Cargo.toml
+++ b/examples/stm32f3/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32f303ze to your chip name, if necessary. 8# Change stm32f303ze to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-tim2", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-tim2", "exti"] }
10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml
index ed8348772..c6b311fa5 100644
--- a/examples/stm32f334/Cargo.toml
+++ b/examples/stm32f334/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
10embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] }
12embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml
index 2a0b7c507..4f0629fc6 100644
--- a/examples/stm32f4/Cargo.toml
+++ b/examples/stm32f4/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32f429zi to your chip name, if necessary. 8# Change stm32f429zi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-tim4", "exti", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-tim4", "exti", "chrono"] }
10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt" ] } 13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt" ] }
14embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } 14embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] }
diff --git a/examples/stm32f469/Cargo.toml b/examples/stm32f469/Cargo.toml
index 382f7e485..a80409801 100644
--- a/examples/stm32f469/Cargo.toml
+++ b/examples/stm32f469/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8# Specific examples only for stm32f469 8# Specific examples only for stm32f469
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f469ni", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f469ni", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] }
10embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 10embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
11embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 11embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
12 12
13defmt = "0.3" 13defmt = "0.3"
diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml
index 480694dca..520b8bc42 100644
--- a/examples/stm32f7/Cargo.toml
+++ b/examples/stm32f7/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32f777zi to your chip name, if necessary. 8# Change stm32f777zi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] }
10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } 13embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }
14embedded-io-async = { version = "0.6.1" } 14embedded-io-async = { version = "0.6.1" }
diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml
index 66cac1885..3d11610ce 100644
--- a/examples/stm32g0/Cargo.toml
+++ b/examples/stm32g0/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32g0b1re to your chip name, if necessary. 8# Change stm32g0b1re to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] }
10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } 13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml
index 36bef4787..87fa2c53a 100644
--- a/examples/stm32g4/Cargo.toml
+++ b/examples/stm32g4/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32g491re to your chip name, if necessary. 8# Change stm32g491re to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] }
10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml
index 1a5791c83..516d491e5 100644
--- a/examples/stm32h5/Cargo.toml
+++ b/examples/stm32h5/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32h563zi to your chip name, if necessary. 8# Change stm32h563zi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "low-power"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "low-power"] }
10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } 13embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] }
14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml
index b90a6a455..68a0c3d88 100644
--- a/examples/stm32h7/Cargo.toml
+++ b/examples/stm32h7/Cargo.toml
@@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0"
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] }
10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
11embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } 11embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" }
12embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 12embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
13embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 13embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
14embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } 14embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] }
15embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 15embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
diff --git a/examples/stm32h723/Cargo.toml b/examples/stm32h723/Cargo.toml
index 6e3f0dd03..82f3cb9c2 100644
--- a/examples/stm32h723/Cargo.toml
+++ b/examples/stm32h723/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32h723zg to your chip name, if necessary. 8# Change stm32h723zg to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h723zg", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h723zg", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] }
10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
14 14
diff --git a/examples/stm32h735/Cargo.toml b/examples/stm32h735/Cargo.toml
index a9c66ec48..a517b9727 100644
--- a/examples/stm32h735/Cargo.toml
+++ b/examples/stm32h735/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h735ig", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } 8embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h735ig", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] }
9embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 9embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
10embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } 10embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" }
11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 13embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
14 14
diff --git a/examples/stm32h755cm4/Cargo.toml b/examples/stm32h755cm4/Cargo.toml
index 455dee98b..1d4d3eb85 100644
--- a/examples/stm32h755cm4/Cargo.toml
+++ b/examples/stm32h755cm4/Cargo.toml
@@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0"
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm4", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm4", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] }
10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
11embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } 11embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" }
12embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 12embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
13embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 13embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
14embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } 14embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] }
15embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 15embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
diff --git a/examples/stm32h755cm7/Cargo.toml b/examples/stm32h755cm7/Cargo.toml
index 4d6167ab2..76c88c806 100644
--- a/examples/stm32h755cm7/Cargo.toml
+++ b/examples/stm32h755cm7/Cargo.toml
@@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0"
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm7", "time-driver-tim3", "exti", "memory-x", "unstable-pac", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm7", "time-driver-tim3", "exti", "memory-x", "unstable-pac", "chrono"] }
10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
11embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } 11embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" }
12embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 12embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
13embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 13embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
14embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } 14embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] }
15embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 15embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
diff --git a/examples/stm32h7b0/Cargo.toml b/examples/stm32h7b0/Cargo.toml
index 41f0fb5ca..aba398fa5 100644
--- a/examples/stm32h7b0/Cargo.toml
+++ b/examples/stm32h7b0/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7b0vb", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } 8embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7b0vb", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] }
9embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 9embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
10embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } 10embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" }
11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } 13embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] }
14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
diff --git a/examples/stm32h7rs/Cargo.toml b/examples/stm32h7rs/Cargo.toml
index 24065dbce..1d957e2cc 100644
--- a/examples/stm32h7rs/Cargo.toml
+++ b/examples/stm32h7rs/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32h743bi to your chip name, if necessary. 8# Change stm32h743bi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] }
10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } 13embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] }
14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml
index 9d234804a..5cc312a50 100644
--- a/examples/stm32l0/Cargo.toml
+++ b/examples/stm32l0/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32l072cz to your chip name, if necessary. 8# Change stm32l072cz to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l073rz", "unstable-pac", "time-driver-any", "exti", "memory-x"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l073rz", "unstable-pac", "time-driver-any", "exti", "memory-x"] }
10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13 13
14defmt = "0.3" 14defmt = "0.3"
diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml
index 33e4f96e5..31b6785fa 100644
--- a/examples/stm32l1/Cargo.toml
+++ b/examples/stm32l1/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 8embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
9embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 9embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
10embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 10embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } 11embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] }
12embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 12embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml
index 512bb8064..3fde18ecd 100644
--- a/examples/stm32l4/Cargo.toml
+++ b/examples/stm32l4/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32l4s5vi to your chip name, if necessary. 8# Change stm32l4s5vi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4r5zi", "memory-x", "time-driver-any", "exti", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4r5zi", "memory-x", "time-driver-any", "exti", "chrono"] }
10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] }
13embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" }
14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml
index e09311f9d..2b8a2c064 100644
--- a/examples/stm32l5/Cargo.toml
+++ b/examples/stm32l5/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32l552ze to your chip name, if necessary. 8# Change stm32l552ze to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] }
10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } 14embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] }
diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml
index fef695c82..11953acfc 100644
--- a/examples/stm32u0/Cargo.toml
+++ b/examples/stm32u0/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32u083rc to your chip name, if necessary. 8# Change stm32u083rc to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] }
10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } 13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml
index 528429f4c..68a17ce43 100644
--- a/examples/stm32u5/Cargo.toml
+++ b/examples/stm32u5/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32u5g9zj to your chip name, if necessary. 8# Change stm32u5g9zj to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u5g9zj", "time-driver-any", "memory-x" ] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u5g9zj", "time-driver-any", "memory-x" ] }
10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } 13embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml
index 400c7b20c..ecc72397b 100644
--- a/examples/stm32wb/Cargo.toml
+++ b/examples/stm32wb/Cargo.toml
@@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0"
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] }
10embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } 10embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] }
11embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 11embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
12embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 12embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] }
13embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 13embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
14embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } 14embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true }
15 15
diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml
index 9e4251ce1..7735dfdde 100644
--- a/examples/stm32wba/Cargo.toml
+++ b/examples/stm32wba/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
7[dependencies] 7[dependencies]
8embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } 8embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] }
9embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 9embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
10embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 10embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] }
11embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 11embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
12embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } 12embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true }
13 13
diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml
index 6507fd1eb..0182745e5 100644
--- a/examples/stm32wl/Cargo.toml
+++ b/examples/stm32wl/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8# Change stm32wl55jc-cm4 to your chip name, if necessary. 8# Change stm32wl55jc-cm4 to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] }
10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } 13embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" }
14 14
diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml
index 5e4d352b5..f5dcdc0a2 100644
--- a/examples/wasm/Cargo.toml
+++ b/examples/wasm/Cargo.toml
@@ -9,7 +9,7 @@ crate-type = ["cdylib"]
9 9
10[dependencies] 10[dependencies]
11embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["log"] } 11embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["log"] }
12embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "integrated-timers"] } 12embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log"] }
13embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "wasm", ] } 13embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "wasm", ] }
14 14
15wasm-logger = "0.2.0" 15wasm-logger = "0.2.0"
diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml
index 766318998..7af3d0649 100644
--- a/tests/nrf/Cargo.toml
+++ b/tests/nrf/Cargo.toml
@@ -9,7 +9,7 @@ teleprobe-meta = "1"
9 9
10embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 10embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
11embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt", ] } 11embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt", ] }
12embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 12embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
13embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 13embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
14embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } 14embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] }
15embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } 15embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml
index 7fb791578..8cd40418a 100644
--- a/tests/rp/Cargo.toml
+++ b/tests/rp/Cargo.toml
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
8teleprobe-meta = "1.1" 8teleprobe-meta = "1.1"
9 9
10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] }
12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", ] } 12embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", ] }
13embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram", "rp2040"] } 13embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = [ "defmt", "unstable-pac", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram", "rp2040"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index 599f7c702..5ae6878cc 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -60,7 +60,7 @@ cm0 = ["portable-atomic/unsafe-assume-single-core"]
60teleprobe-meta = "1" 60teleprobe-meta = "1"
61 61
62embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } 62embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] }
63embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 63embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
64embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] } 64embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] }
65embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] } 65embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] }
66embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 66embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }