diff options
| author | Dario Nieuwenhuis <[email protected]> | 2024-12-16 12:30:30 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-12-16 12:30:30 +0000 |
| commit | 2c3bc75da6008afa7cacc1045954cef7e3d8740f (patch) | |
| tree | 47661322d49d3e38717e2fc3f38e920c222138f7 | |
| parent | 99ad61cecf4fe098feeced5524d3e60625137457 (diff) | |
| parent | e1c00613288024623f7fde61f65c4c40c9a5381a (diff) | |
Merge pull request #3593 from bugadani/refactor
Rework time-driver contract.
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 | |||
| 17 | cargo test --manifest-path ./embassy-sync/Cargo.toml | 17 | cargo test --manifest-path ./embassy-sync/Cargo.toml |
| 18 | cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml | 18 | cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml |
| 19 | cargo test --manifest-path ./embassy-hal-internal/Cargo.toml | 19 | cargo test --manifest-path ./embassy-hal-internal/Cargo.toml |
| 20 | cargo test --manifest-path ./embassy-time/Cargo.toml --features generic-queue,mock-driver | 20 | cargo test --manifest-path ./embassy-time/Cargo.toml --features mock-driver,embassy-time-queue-driver/generic-queue-8 |
| 21 | cargo test --manifest-path ./embassy-time-driver/Cargo.toml | 21 | cargo test --manifest-path ./embassy-time-driver/Cargo.toml |
| 22 | 22 | ||
| 23 | cargo test --manifest-path ./embassy-boot/Cargo.toml | 23 | cargo 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 | ||
| 31 | cargo 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 | 25 | cargo 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 |
| 32 | cargo 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 \ |
| @@ -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? |
| 308 | rm out/tests/stm32f207zg/eth | 303 | rm out/tests/stm32f207zg/eth |
| 309 | 304 | ||
| 305 | # temporarily disabled, hard faults for unknown reasons | ||
| 306 | rm 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. |
| 311 | rm out/tests/stm32u5a5zj/usart | 309 | rm 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" | |||
| 6 | license = "MIT OR Apache-2.0" | 6 | license = "MIT OR Apache-2.0" |
| 7 | 7 | ||
| 8 | [dependencies] | 8 | [dependencies] |
| 9 | embassy-executor = { version = "0.6.3", path = "../../../embassy-executor", features = ["defmt", "integrated-timers", "arch-cortex-m", "executor-thread"] } | 9 | embassy-executor = { version = "0.6.3", path = "../../../embassy-executor", features = ["defmt", "arch-cortex-m", "executor-thread"] } |
| 10 | embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt"] } | 10 | embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt"] } |
| 11 | embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote"] } | 11 | embassy-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] |
| 82 | embassy-stm32 = { version = "0.1.0", features = ["defmt", "time-driver-any", "stm32g474re", "memory-x", "unstable-pac", "exti"] } | 82 | embassy-stm32 = { version = "0.1.0", features = ["defmt", "time-driver-any", "stm32g474re", "memory-x", "unstable-pac", "exti"] } |
| 83 | embassy-executor = { version = "0.6.3", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 83 | embassy-executor = { version = "0.6.3", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt"] } |
| 84 | embassy-time = { version = "0.3.2", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 84 | embassy-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] |
| 102 | embassy-stm32 = {version = "0.1.0", features = ["defmt", "time-driver-any", "stm32g474re", "memory-x", "unstable-pac", "exti"]} | 102 | embassy-stm32 = {version = "0.1.0", features = ["defmt", "time-driver-any", "stm32g474re", "memory-x", "unstable-pac", "exti"]} |
| 103 | embassy-executor = { version = "0.3.3", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 103 | embassy-executor = { version = "0.3.3", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt"] } |
| 104 | embassy-time = { version = "0.2", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 104 | embassy-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 | ||
| 36 | embassy-executor-macros = { version = "0.6.2", path = "../embassy-executor-macros" } | 36 | embassy-executor-macros = { version = "0.6.2", path = "../embassy-executor-macros" } |
| 37 | embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver", optional = true } | 37 | embassy-time-driver = { version = "0.1.0", path = "../embassy-time-driver", optional = true } |
| 38 | embassy-time-queue-driver = { version = "0.1.0", path = "../embassy-time-queue-driver", optional = true } | ||
| 39 | critical-section = "1.1" | 38 | critical-section = "1.1" |
| 40 | 39 | ||
| 41 | document-features = "0.2.7" | 40 | document-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 |
| 68 | turbowakers = [] | 67 | turbowakers = [] |
| 69 | 68 | ||
| 70 | ## Use the executor-integrated `embassy-time` timer queue. | ||
| 71 | integrated-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) |
| 95 | trace = [] | 91 | trace = [] |
| 96 | ## Enable support for rtos-trace framework | 92 | ## Enable support for rtos-trace framework |
| 97 | rtos-trace = ["dep:rtos-trace", "trace"] | 93 | rtos-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")] |
| 17 | mod state; | 17 | mod state; |
| 18 | 18 | ||
| 19 | #[cfg(feature = "integrated-timers")] | 19 | pub mod timer_queue; |
| 20 | mod timer_queue; | ||
| 21 | #[cfg(feature = "trace")] | 20 | #[cfg(feature = "trace")] |
| 22 | mod trace; | 21 | mod trace; |
| 23 | pub(crate) mod util; | 22 | pub(crate) mod util; |
| @@ -31,9 +30,6 @@ use core::pin::Pin; | |||
| 31 | use core::ptr::NonNull; | 30 | use core::ptr::NonNull; |
| 32 | use core::task::{Context, Poll}; | 31 | use core::task::{Context, Poll}; |
| 33 | 32 | ||
| 34 | #[cfg(feature = "integrated-timers")] | ||
| 35 | use embassy_time_driver::AlarmHandle; | ||
| 36 | |||
| 37 | use self::run_queue::{RunQueue, RunQueueItem}; | 33 | use self::run_queue::{RunQueue, RunQueueItem}; |
| 38 | use self::state::State; | 34 | use self::state::State; |
| 39 | use self::util::{SyncUnsafeCell, UninitCell}; | 35 | use 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)] |
| 58 | pub struct TaskRef { | 52 | pub 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 | ||
| 233 | extern "Rust" { | ||
| 234 | fn _embassy_time_schedule_wake(at: u64, waker: &core::task::Waker); | ||
| 235 | } | ||
| 236 | |||
| 184 | /// An uninitialized [`TaskStorage`]. | 237 | /// An uninitialized [`TaskStorage`]. |
| 185 | pub struct AvailableTask<F: Future + 'static> { | 238 | pub struct AvailableTask<F: Future + 'static> { |
| 186 | task: &'static TaskStorage<F>, | 239 | task: &'static TaskStorage<F>, |
| @@ -316,34 +369,16 @@ impl Pender { | |||
| 316 | pub(crate) struct SyncExecutor { | 369 | pub(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 | ||
| 326 | impl SyncExecutor { | 374 | impl 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")] | ||
| 580 | struct TimerQueue; | ||
| 581 | |||
| 582 | #[cfg(feature = "integrated-timers")] | ||
| 583 | impl 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")] | ||
| 595 | embassy_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 @@ | |||
| 1 | use core::sync::atomic::{AtomicU32, Ordering}; | 1 | use core::sync::atomic::{AtomicU32, Ordering}; |
| 2 | 2 | ||
| 3 | use super::timer_queue::TimerEnqueueOperation; | ||
| 4 | |||
| 3 | /// Task is spawned (has a future) | 5 | /// Task is spawned (has a future) |
| 4 | pub(crate) const STATE_SPAWNED: u32 = 1 << 0; | 6 | pub(crate) const STATE_SPAWNED: u32 = 1 << 0; |
| 5 | /// Task is in the executor run queue | 7 | /// Task is in the executor run queue |
| 6 | pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1; | 8 | pub(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")] | ||
| 9 | pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2; | 10 | pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2; |
| 10 | 11 | ||
| 11 | pub(crate) struct State { | 12 | pub(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 @@ | |||
| 1 | use core::arch::asm; | 1 | use core::arch::asm; |
| 2 | use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering}; | 2 | use core::sync::atomic::{compiler_fence, AtomicBool, AtomicU32, Ordering}; |
| 3 | 3 | ||
| 4 | use 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`! |
| 5 | pub(crate) const STATE_SPAWNED: u32 = 1 << 0; | 7 | pub(crate) const STATE_SPAWNED: u32 = 1 << 0; |
| 6 | pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 8; | 8 | pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 8; |
| 9 | pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 16; | ||
| 7 | 10 | ||
| 8 | #[repr(C, align(4))] | 11 | #[repr(C, align(4))] |
| 9 | pub(crate) struct State { | 12 | pub(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 | ||
| 3 | use critical_section::Mutex; | 3 | use critical_section::Mutex; |
| 4 | 4 | ||
| 5 | use super::timer_queue::TimerEnqueueOperation; | ||
| 6 | |||
| 5 | /// Task is spawned (has a future) | 7 | /// Task is spawned (has a future) |
| 6 | pub(crate) const STATE_SPAWNED: u32 = 1 << 0; | 8 | pub(crate) const STATE_SPAWNED: u32 = 1 << 0; |
| 7 | /// Task is in the executor run queue | 9 | /// Task is in the executor run queue |
| 8 | pub(crate) const STATE_RUN_QUEUED: u32 = 1 << 1; | 10 | pub(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")] | ||
| 11 | pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2; | 12 | pub(crate) const STATE_TIMER_QUEUED: u32 = 1 << 2; |
| 12 | 13 | ||
| 13 | pub(crate) struct State { | 14 | pub(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 @@ | |||
| 1 | use core::cmp::min; | 1 | //! Timer queue operations. |
| 2 | |||
| 3 | use core::cell::Cell; | ||
| 2 | 4 | ||
| 3 | use super::TaskRef; | 5 | use super::TaskRef; |
| 4 | use crate::raw::util::SyncUnsafeCell; | ||
| 5 | 6 | ||
| 6 | pub(crate) struct TimerQueueItem { | 7 | /// An item in the timer queue. |
| 7 | next: SyncUnsafeCell<Option<TaskRef>>, | 8 | pub 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 | ||
| 10 | impl 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 | ||
| 18 | pub(crate) struct TimerQueue { | 19 | unsafe impl Sync for TimerQueueItem {} |
| 19 | head: SyncUnsafeCell<Option<TaskRef>>, | ||
| 20 | } | ||
| 21 | 20 | ||
| 22 | impl TimerQueue { | 21 | impl 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(); | 34 | pub 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"))] | ||
| 65 | const 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")] |
| 74 | impl rtos_trace::RtosTraceOSCallbacks for crate::raw::SyncExecutor { | 65 | impl 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] | ||
| 156 | fn _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] |
| 137 | embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } | 137 | embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } |
| 138 | embassy-time-queue-driver = { version = "0.1", path = "../embassy-time-queue-driver", optional = true } | ||
| 138 | embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true } | 139 | embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true } |
| 139 | embassy-sync = { version = "0.6.1", path = "../embassy-sync" } | 140 | embassy-sync = { version = "0.6.1", path = "../embassy-sync" } |
| 140 | embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } | 141 | embassy-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 @@ | |||
| 1 | use core::cell::Cell; | 1 | use core::cell::{Cell, RefCell}; |
| 2 | use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; | 2 | use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; |
| 3 | use core::{mem, ptr}; | ||
| 4 | 3 | ||
| 5 | use critical_section::CriticalSection; | 4 | use critical_section::CriticalSection; |
| 6 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | 5 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; |
| 7 | use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; | 6 | use embassy_sync::blocking_mutex::CriticalSectionMutex as Mutex; |
| 8 | use embassy_time_driver::{AlarmHandle, Driver}; | 7 | use embassy_time_driver::Driver; |
| 8 | use embassy_time_queue_driver::Queue; | ||
| 9 | 9 | ||
| 10 | use crate::interrupt::InterruptExt; | 10 | use crate::interrupt::InterruptExt; |
| 11 | use crate::{interrupt, pac}; | 11 | use crate::{interrupt, pac}; |
| @@ -94,11 +94,6 @@ mod test { | |||
| 94 | 94 | ||
| 95 | struct AlarmState { | 95 | struct 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 | ||
| 104 | unsafe impl Send for AlarmState {} | 99 | unsafe 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 | ||
| 116 | const ALARM_COUNT: usize = 3; | ||
| 117 | |||
| 118 | struct RtcDriver { | 109 | struct 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 | ||
| 126 | embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { | 117 | embassy_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 | ||
| 132 | impl RtcDriver { | 123 | impl 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"] | |||
| 40 | unstable-pac = [] | 40 | unstable-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. |
| 43 | time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-1_000_000"] | 43 | time-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. |
| 46 | rom-func-cache = [] | 46 | rom-func-cache = [] |
| @@ -110,6 +110,7 @@ binary-info = ["rt", "dep:rp-binary-info", "rp-binary-info?/binary-info"] | |||
| 110 | [dependencies] | 110 | [dependencies] |
| 111 | embassy-sync = { version = "0.6.1", path = "../embassy-sync" } | 111 | embassy-sync = { version = "0.6.1", path = "../embassy-sync" } |
| 112 | embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } | 112 | embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } |
| 113 | embassy-time-queue-driver = { version = "0.1", path = "../embassy-time-queue-driver", optional = true } | ||
| 113 | embassy-time = { version = "0.3.2", path = "../embassy-time" } | 114 | embassy-time = { version = "0.3.2", path = "../embassy-time" } |
| 114 | embassy-futures = { version = "0.1.0", path = "../embassy-futures" } | 115 | embassy-futures = { version = "0.1.0", path = "../embassy-futures" } |
| 115 | embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } | 116 | embassy-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. |
| 2 | use core::cell::Cell; | 2 | use core::cell::{Cell, RefCell}; |
| 3 | 3 | ||
| 4 | use atomic_polyfill::{AtomicU8, Ordering}; | ||
| 5 | use critical_section::CriticalSection; | 4 | use critical_section::CriticalSection; |
| 6 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | 5 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; |
| 7 | use embassy_sync::blocking_mutex::Mutex; | 6 | use embassy_sync::blocking_mutex::Mutex; |
| 8 | use embassy_time_driver::{AlarmHandle, Driver}; | 7 | use embassy_time_driver::Driver; |
| 8 | use embassy_time_queue_driver::Queue; | ||
| 9 | #[cfg(feature = "rp2040")] | 9 | #[cfg(feature = "rp2040")] |
| 10 | use pac::TIMER; | 10 | use pac::TIMER; |
| 11 | #[cfg(feature = "_rp235x")] | 11 | #[cfg(feature = "_rp235x")] |
| @@ -16,23 +16,19 @@ use crate::{interrupt, pac}; | |||
| 16 | 16 | ||
| 17 | struct AlarmState { | 17 | struct AlarmState { |
| 18 | timestamp: Cell<u64>, | 18 | timestamp: Cell<u64>, |
| 19 | callback: Cell<Option<(fn(*mut ()), *mut ())>>, | ||
| 20 | } | 19 | } |
| 21 | unsafe impl Send for AlarmState {} | 20 | unsafe impl Send for AlarmState {} |
| 22 | 21 | ||
| 23 | const ALARM_COUNT: usize = 4; | ||
| 24 | |||
| 25 | struct TimerDriver { | 22 | struct 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 | ||
| 30 | embassy_time_driver::time_driver_impl!(static DRIVER: TimerDriver = TimerDriver{ | 27 | embassy_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 | ||
| 38 | impl Driver for TimerDriver { | 34 | impl 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 | ||
| 101 | impl TimerDriver { | 60 | impl 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 { | |||
| 134 | pub unsafe fn init() { | 113 | pub 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] |
| 168 | fn TIMER_IRQ_0() { | 136 | fn TIMER_IRQ_0() { |
| 169 | DRIVER.check_alarm(0) | 137 | DRIVER.check_alarm() |
| 170 | } | ||
| 171 | |||
| 172 | #[cfg(all(feature = "rt", feature = "rp2040"))] | ||
| 173 | #[interrupt] | ||
| 174 | fn TIMER_IRQ_1() { | ||
| 175 | DRIVER.check_alarm(1) | ||
| 176 | } | ||
| 177 | |||
| 178 | #[cfg(all(feature = "rt", feature = "rp2040"))] | ||
| 179 | #[interrupt] | ||
| 180 | fn TIMER_IRQ_2() { | ||
| 181 | DRIVER.check_alarm(2) | ||
| 182 | } | ||
| 183 | |||
| 184 | #[cfg(all(feature = "rt", feature = "rp2040"))] | ||
| 185 | #[interrupt] | ||
| 186 | fn 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] |
| 192 | fn TIMER0_IRQ_0() { | 142 | fn TIMER0_IRQ_0() { |
| 193 | DRIVER.check_alarm(0) | 143 | DRIVER.check_alarm() |
| 194 | } | ||
| 195 | |||
| 196 | #[cfg(all(feature = "rt", feature = "_rp235x"))] | ||
| 197 | #[interrupt] | ||
| 198 | fn TIMER0_IRQ_1() { | ||
| 199 | DRIVER.check_alarm(1) | ||
| 200 | } | ||
| 201 | |||
| 202 | #[cfg(all(feature = "rt", feature = "_rp235x"))] | ||
| 203 | #[interrupt] | ||
| 204 | fn TIMER0_IRQ_2() { | ||
| 205 | DRIVER.check_alarm(2) | ||
| 206 | } | ||
| 207 | |||
| 208 | #[cfg(all(feature = "rt", feature = "_rp235x"))] | ||
| 209 | #[interrupt] | ||
| 210 | fn 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"] | |||
| 45 | embassy-sync = { version = "0.6.1", path = "../embassy-sync" } | 45 | embassy-sync = { version = "0.6.1", path = "../embassy-sync" } |
| 46 | embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true } | 46 | embassy-time = { version = "0.3.2", path = "../embassy-time", optional = true } |
| 47 | embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } | 47 | embassy-time-driver = { version = "0.1", path = "../embassy-time-driver", optional = true } |
| 48 | embassy-time-queue-driver = { version = "0.1", path = "../embassy-time-queue-driver", optional = true } | ||
| 48 | embassy-futures = { version = "0.1.0", path = "../embassy-futures" } | 49 | embassy-futures = { version = "0.1.0", path = "../embassy-futures" } |
| 49 | embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } | 50 | embassy-hal-internal = {version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } |
| 50 | embassy-embedded-hal = {version = "0.2.0", path = "../embassy-embedded-hal", default-features = false } | 51 | embassy-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 |
| 155 | time-driver-any = ["_time-driver"] | 156 | time-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 | ||
| 3 | use core::cell::Cell; | 3 | use core::cell::{Cell, RefCell}; |
| 4 | use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; | 4 | use core::sync::atomic::{compiler_fence, AtomicU32, Ordering}; |
| 5 | use core::{mem, ptr}; | ||
| 6 | 5 | ||
| 7 | use critical_section::CriticalSection; | 6 | use critical_section::CriticalSection; |
| 8 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | 7 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; |
| 9 | use embassy_sync::blocking_mutex::Mutex; | 8 | use embassy_sync::blocking_mutex::Mutex; |
| 10 | use embassy_time_driver::{AlarmHandle, Driver, TICK_HZ}; | 9 | use embassy_time_driver::{Driver, TICK_HZ}; |
| 10 | use embassy_time_queue_driver::Queue; | ||
| 11 | use stm32_metapac::timer::{regs, TimGp16}; | 11 | use stm32_metapac::timer::{regs, TimGp16}; |
| 12 | 12 | ||
| 13 | use crate::interrupt::typelevel::Interrupt; | 13 | use 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 | |||
| 32 | cfg_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)] |
| 41 | type T = peripherals::TIM1; | 29 | type T = peripherals::TIM1; |
| @@ -208,11 +196,6 @@ fn calc_now(period: u32, counter: u16) -> u64 { | |||
| 208 | 196 | ||
| 209 | struct AlarmState { | 197 | struct 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 | ||
| 218 | unsafe impl Send for AlarmState {} | 201 | unsafe 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 { | |||
| 230 | pub(crate) struct RtcDriver { | 211 | pub(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 | ||
| 240 | embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { | 220 | embassy_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 | ||
| 248 | impl RtcDriver { | 228 | impl 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 | ||
| 494 | impl 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. | 492 | impl 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 | |||
| 3 | All notable changes to this project will be documented in this file. | ||
| 4 | |||
| 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), | ||
| 6 | and 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 | |||
| 15 | Initial 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 | ||
| 104 | use core::task::Waker; | ||
| 105 | |||
| 66 | mod tick; | 106 | mod 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) |
| 71 | pub const TICK_HZ: u64 = tick::TICK_HZ; | 111 | pub const TICK_HZ: u64 = tick::TICK_HZ; |
| 72 | 112 | ||
| 73 | /// Alarm handle, assigned by the driver. | ||
| 74 | #[derive(Clone, Copy)] | ||
| 75 | pub struct AlarmHandle { | ||
| 76 | id: u8, | ||
| 77 | } | ||
| 78 | |||
| 79 | impl 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 |
| 96 | pub trait Driver: Send + Sync + 'static { | 114 | pub 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 | ||
| 173 | extern "Rust" { | 132 | extern "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. | ||
| 188 | pub unsafe fn allocate_alarm() -> Option<AlarmHandle> { | ||
| 189 | _embassy_time_allocate_alarm() | ||
| 190 | } | ||
| 191 | |||
| 192 | /// See [`Driver::set_alarm_callback`] | ||
| 193 | pub 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`] | ||
| 198 | pub 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 | |||
| 3 | All notable changes to this project will be documented in this file. | ||
| 4 | |||
| 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), | ||
| 6 | and 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 | |||
| 15 | Initial 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. |
| 21 | links = "embassy-time-queue" | 21 | links = "embassy-time-queue" |
| 22 | 22 | ||
| 23 | [dependencies] | ||
| 24 | heapless = "0.8" | ||
| 25 | embassy-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 | ||
| 43 | generic-queue-8 = ["_generic-queue"] | ||
| 44 | ## Generic Queue with 16 timers | ||
| 45 | generic-queue-16 = ["_generic-queue"] | ||
| 46 | ## Generic Queue with 32 timers | ||
| 47 | generic-queue-32 = ["_generic-queue"] | ||
| 48 | ## Generic Queue with 64 timers | ||
| 49 | generic-queue-64 = ["_generic-queue"] | ||
| 50 | ## Generic Queue with 128 timers | ||
| 51 | generic-queue-128 = ["_generic-queue"] | ||
| 52 | |||
| 53 | _generic-queue = [] | ||
| 54 | |||
| 23 | [package.metadata.embassy_docs] | 55 | [package.metadata.embassy_docs] |
| 24 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-time-queue-driver-v$VERSION/embassy-time-queue-driver/src/" | 56 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-time-queue-driver-v$VERSION/embassy-time-queue-driver/src/" |
| 25 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-time-queue-driver/src/" | 57 | src_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 | //! ``` | ||
| 29 | use core::task::Waker; | 13 | use core::task::Waker; |
| 30 | 14 | ||
| 31 | /// Timer queue | 15 | #[cfg(feature = "_generic-queue")] |
| 32 | pub trait TimerQueue { | 16 | pub 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. | 18 | pub mod queue_integrated; |
| 35 | fn schedule_wake(&'static self, at: u64, waker: &Waker); | 19 | |
| 36 | } | 20 | #[cfg(feature = "_generic-queue")] |
| 21 | pub use queue_generic::Queue; | ||
| 22 | #[cfg(not(feature = "_generic-queue"))] | ||
| 23 | pub use queue_integrated::Queue; | ||
| 37 | 24 | ||
| 38 | extern "Rust" { | 25 | extern "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`. |
| 43 | pub fn schedule_wake(at: u64, waker: &Waker) { | 30 | pub 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; |
| 51 | macro_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 | |||
| 5 | use core::cmp::{min, Ordering}; | ||
| 6 | use core::task::Waker; | ||
| 7 | |||
| 8 | use heapless::Vec; | ||
| 9 | |||
| 10 | #[derive(Debug)] | ||
| 11 | struct Timer { | ||
| 12 | at: u64, | ||
| 13 | waker: Waker, | ||
| 14 | } | ||
| 15 | |||
| 16 | impl PartialEq for Timer { | ||
| 17 | fn eq(&self, other: &Self) -> bool { | ||
| 18 | self.at == other.at | ||
| 19 | } | ||
| 20 | } | ||
| 21 | |||
| 22 | impl Eq for Timer {} | ||
| 23 | |||
| 24 | impl PartialOrd for Timer { | ||
| 25 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | ||
| 26 | self.at.partial_cmp(&other.at) | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | impl 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. | ||
| 37 | pub struct ConstGenericQueue<const QUEUE_SIZE: usize> { | ||
| 38 | queue: Vec<Timer, QUEUE_SIZE>, | ||
| 39 | } | ||
| 40 | |||
| 41 | impl<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")] | ||
| 103 | const QUEUE_SIZE: usize = 8; | ||
| 104 | #[cfg(feature = "generic-queue-16")] | ||
| 105 | const QUEUE_SIZE: usize = 16; | ||
| 106 | #[cfg(feature = "generic-queue-32")] | ||
| 107 | const QUEUE_SIZE: usize = 32; | ||
| 108 | #[cfg(feature = "generic-queue-64")] | ||
| 109 | const QUEUE_SIZE: usize = 64; | ||
| 110 | #[cfg(feature = "generic-queue-128")] | ||
| 111 | const 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 | )))] | ||
| 119 | const QUEUE_SIZE: usize = 64; | ||
| 120 | |||
| 121 | /// A timer queue with a pre-determined capacity. | ||
| 122 | pub struct Queue { | ||
| 123 | queue: ConstGenericQueue<QUEUE_SIZE>, | ||
| 124 | } | ||
| 125 | |||
| 126 | impl 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. | ||
| 2 | use core::cell::Cell; | ||
| 3 | use core::cmp::min; | ||
| 4 | use core::task::Waker; | ||
| 5 | |||
| 6 | use embassy_executor::raw::TaskRef; | ||
| 7 | |||
| 8 | /// A timer queue, with items integrated into tasks. | ||
| 9 | pub struct Queue { | ||
| 10 | head: Cell<Option<TaskRef>>, | ||
| 11 | } | ||
| 12 | |||
| 13 | impl 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. |
| 43 | mock-driver = ["tick-hz-1_000_000"] | 43 | mock-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. | ||
| 49 | generic-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 | ||
| 58 | generic-queue-8 = ["generic-queue"] | ||
| 59 | ## Generic Queue with 16 timers | ||
| 60 | generic-queue-16 = ["generic-queue"] | ||
| 61 | ## Generic Queue with 32 timers | ||
| 62 | generic-queue-32 = ["generic-queue"] | ||
| 63 | ## Generic Queue with 64 timers | ||
| 64 | generic-queue-64 = ["generic-queue"] | ||
| 65 | ## Generic Queue with 128 timers | ||
| 66 | generic-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" } | |||
| 419 | futures-util = { version = "0.3.17", default-features = false } | 396 | futures-util = { version = "0.3.17", default-features = false } |
| 420 | critical-section = "1.1" | 397 | critical-section = "1.1" |
| 421 | cfg-if = "1.0.0" | 398 | cfg-if = "1.0.0" |
| 422 | heapless = "0.8" | ||
| 423 | 399 | ||
| 424 | document-features = "0.2.7" | 400 | document-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 @@ | |||
| 1 | use core::cell::RefCell; | 1 | use core::cell::RefCell; |
| 2 | use core::task::Waker; | ||
| 2 | 3 | ||
| 3 | use critical_section::Mutex as CsMutex; | 4 | use critical_section::Mutex as CsMutex; |
| 4 | use embassy_time_driver::{AlarmHandle, Driver}; | 5 | use embassy_time_driver::Driver; |
| 6 | use embassy_time_queue_driver::Queue; | ||
| 5 | 7 | ||
| 6 | use crate::{Duration, Instant}; | 8 | use 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 | ||
| 131 | struct InnerMockDriver { | 83 | struct InnerMockDriver { |
| 132 | now: Instant, | 84 | now: Instant, |
| 133 | alarm: Option<AlarmState>, | 85 | queue: Queue, |
| 134 | } | 86 | } |
| 135 | 87 | ||
| 136 | impl InnerMockDriver { | 88 | impl 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 | |||
| 145 | struct AlarmState { | ||
| 146 | timestamp: u64, | ||
| 147 | callback: fn(*mut ()), | ||
| 148 | ctx: *mut (), | ||
| 149 | } | ||
| 150 | |||
| 151 | impl 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 | ||
| 163 | unsafe impl Send for AlarmState {} | ||
| 164 | |||
| 165 | #[cfg(test)] | 97 | #[cfg(test)] |
| 166 | mod tests { | 98 | mod 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 @@ | |||
| 1 | use core::sync::atomic::{AtomicU8, Ordering}; | 1 | use std::sync::{Condvar, Mutex}; |
| 2 | use std::cell::{RefCell, UnsafeCell}; | 2 | use std::thread; |
| 3 | use std::mem::MaybeUninit; | ||
| 4 | use std::sync::{Condvar, Mutex, Once}; | ||
| 5 | use std::time::{Duration as StdDuration, Instant as StdInstant}; | 3 | use std::time::{Duration as StdDuration, Instant as StdInstant}; |
| 6 | use std::{mem, ptr, thread}; | ||
| 7 | 4 | ||
| 8 | use critical_section::Mutex as CsMutex; | 5 | use embassy_time_driver::Driver; |
| 9 | use embassy_time_driver::{AlarmHandle, Driver}; | 6 | use embassy_time_queue_driver::Queue; |
| 10 | 7 | ||
| 11 | const ALARM_COUNT: usize = 4; | 8 | struct TimeDriver { |
| 12 | 9 | signaler: Signaler, | |
| 13 | struct 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 | ||
| 22 | unsafe impl Send for AlarmState {} | 13 | struct Inner { |
| 23 | 14 | zero_instant: Option<StdInstant>, | |
| 24 | impl 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 | |||
| 34 | struct 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 | ||
| 46 | embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { | 18 | embassy_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 | ||
| 55 | impl TimeDriver { | 26 | impl 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 | ||
| 115 | impl Driver for TimeDriver { | 35 | impl 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 ()) { | 51 | fn 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 | ||
| 166 | impl Signaler { | 72 | impl 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 | |||
| 200 | pub(crate) struct UninitCell<T>(MaybeUninit<UnsafeCell<T>>); | ||
| 201 | unsafe impl<T> Send for UninitCell<T> {} | ||
| 202 | unsafe impl<T> Sync for UninitCell<T> {} | ||
| 203 | |||
| 204 | impl<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 | |||
| 226 | impl<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 @@ | |||
| 1 | use core::sync::atomic::{AtomicU8, Ordering}; | 1 | use std::sync::Mutex; |
| 2 | use std::cell::UnsafeCell; | ||
| 3 | use std::mem::MaybeUninit; | ||
| 4 | use std::ptr; | ||
| 5 | use std::sync::{Mutex, Once}; | ||
| 6 | 2 | ||
| 7 | use embassy_time_driver::{AlarmHandle, Driver}; | 3 | use embassy_time_driver::Driver; |
| 4 | use embassy_time_queue_driver::Queue; | ||
| 8 | use wasm_bindgen::prelude::*; | 5 | use wasm_bindgen::prelude::*; |
| 9 | use wasm_timer::Instant as StdInstant; | 6 | use wasm_timer::Instant as StdInstant; |
| 10 | 7 | ||
| 11 | const ALARM_COUNT: usize = 4; | ||
| 12 | |||
| 13 | struct AlarmState { | 8 | struct AlarmState { |
| 14 | token: Option<f64>, | 9 | token: Option<f64>, |
| 15 | closure: Option<Closure<dyn FnMut() + 'static>>, | ||
| 16 | } | 10 | } |
| 17 | 11 | ||
| 18 | unsafe impl Send for AlarmState {} | ||
| 19 | |||
| 20 | impl AlarmState { | 12 | impl 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 | ||
| 35 | struct TimeDriver { | 24 | struct 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 | ||
| 43 | embassy_time_driver::time_driver_impl!(static DRIVER: TimeDriver = TimeDriver { | 28 | struct 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 | |||
| 50 | impl 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 | ||
| 60 | impl Driver for TimeDriver { | 35 | unsafe impl Send for Inner {} |
| 61 | fn now(&self) -> u64 { | ||
| 62 | self.init(); | ||
| 63 | 36 | ||
| 64 | let zero = unsafe { self.zero_instant.read() }; | 37 | embassy_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 { | 46 | impl 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 | ||
| 112 | pub(crate) struct UninitCell<T>(MaybeUninit<UnsafeCell<T>>); | 73 | impl Driver for TimeDriver { |
| 113 | unsafe impl<T> Send for UninitCell<T> {} | 74 | fn now(&self) -> u64 { |
| 114 | unsafe impl<T> Sync for UninitCell<T> {} | 75 | let mut inner = self.inner.lock().unwrap(); |
| 115 | 76 | let zero = inner.init(); | |
| 116 | impl<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 | ||
| 137 | impl<T: Copy> UninitCell<T> { | 94 | fn 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; | |||
| 25 | mod driver_std; | 25 | mod driver_std; |
| 26 | #[cfg(feature = "wasm")] | 26 | #[cfg(feature = "wasm")] |
| 27 | mod driver_wasm; | 27 | mod driver_wasm; |
| 28 | #[cfg(feature = "generic-queue")] | ||
| 29 | mod queue_generic; | ||
| 30 | 28 | ||
| 31 | pub use delay::{block_for, Delay}; | 29 | pub use delay::{block_for, Delay}; |
| 32 | pub use duration::Duration; | 30 | pub 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 @@ | |||
| 1 | use core::cell::RefCell; | ||
| 2 | use core::cmp::{min, Ordering}; | ||
| 3 | use core::task::Waker; | ||
| 4 | |||
| 5 | use critical_section::Mutex; | ||
| 6 | use embassy_time_driver::{allocate_alarm, set_alarm, set_alarm_callback, AlarmHandle}; | ||
| 7 | use embassy_time_queue_driver::TimerQueue; | ||
| 8 | use heapless::Vec; | ||
| 9 | |||
| 10 | use crate::Instant; | ||
| 11 | |||
| 12 | #[cfg(feature = "generic-queue-8")] | ||
| 13 | const QUEUE_SIZE: usize = 8; | ||
| 14 | #[cfg(feature = "generic-queue-16")] | ||
| 15 | const QUEUE_SIZE: usize = 16; | ||
| 16 | #[cfg(feature = "generic-queue-32")] | ||
| 17 | const QUEUE_SIZE: usize = 32; | ||
| 18 | #[cfg(feature = "generic-queue-64")] | ||
| 19 | const QUEUE_SIZE: usize = 64; | ||
| 20 | #[cfg(feature = "generic-queue-128")] | ||
| 21 | const 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 | )))] | ||
| 29 | const QUEUE_SIZE: usize = 64; | ||
| 30 | |||
| 31 | #[derive(Debug)] | ||
| 32 | struct Timer { | ||
| 33 | at: Instant, | ||
| 34 | waker: Waker, | ||
| 35 | } | ||
| 36 | |||
| 37 | impl PartialEq for Timer { | ||
| 38 | fn eq(&self, other: &Self) -> bool { | ||
| 39 | self.at == other.at | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | impl Eq for Timer {} | ||
| 44 | |||
| 45 | impl PartialOrd for Timer { | ||
| 46 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | ||
| 47 | self.at.partial_cmp(&other.at) | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | impl Ord for Timer { | ||
| 52 | fn cmp(&self, other: &Self) -> Ordering { | ||
| 53 | self.at.cmp(&other.at) | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | struct InnerQueue { | ||
| 58 | queue: Vec<Timer, QUEUE_SIZE>, | ||
| 59 | alarm: AlarmHandle, | ||
| 60 | } | ||
| 61 | |||
| 62 | impl 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 | |||
| 130 | struct Queue { | ||
| 131 | inner: Mutex<RefCell<Option<InnerQueue>>>, | ||
| 132 | } | ||
| 133 | |||
| 134 | impl 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 | |||
| 167 | impl 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 | |||
| 173 | embassy_time_queue_driver::timer_queue_impl!(static QUEUE: Queue = Queue::new()); | ||
| 174 | |||
| 175 | #[cfg(test)] | ||
| 176 | #[cfg(feature = "mock-driver")] | ||
| 177 | mod 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] |
| 8 | embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } | 8 | embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } |
| 9 | embassy-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"] } | 9 | embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } |
| 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } | 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } |
| 11 | embassy-nrf = { version = "0.2.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } | 11 | embassy-nrf = { version = "0.2.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } |
| 12 | embassy-boot = { version = "0.3.0", path = "../../../../embassy-boot", features = [] } | 12 | embassy-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] |
| 8 | embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } | 8 | embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } |
| 9 | embassy-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"] } | 9 | embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "arch-cortex-m", "executor-thread"] } |
| 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } | 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [] } |
| 11 | embassy-rp = { version = "0.2.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] } | 11 | embassy-rp = { version = "0.2.0", path = "../../../../embassy-rp", features = ["time-driver", "rp2040"] } |
| 12 | embassy-boot-rp = { version = "0.3.0", path = "../../../../embassy-boot-rp", features = [] } | 12 | embassy-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] |
| 8 | embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } | 8 | embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } |
| 9 | embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } | 9 | embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } |
| 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } |
| 12 | embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32" } | 12 | embassy-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] |
| 8 | embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } | 8 | embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } |
| 9 | embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } | 9 | embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } |
| 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } |
| 12 | embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } | 12 | embassy-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] |
| 8 | embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } | 8 | embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } |
| 9 | embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } | 9 | embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } |
| 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } |
| 12 | embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } | 12 | embassy-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] |
| 8 | embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } | 8 | embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } |
| 9 | embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } | 9 | embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } |
| 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } |
| 12 | embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } | 12 | embassy-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] |
| 8 | embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } | 8 | embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } |
| 9 | embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } | 9 | embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } |
| 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } |
| 12 | embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } | 12 | embassy-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] |
| 8 | embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } | 8 | embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } |
| 9 | embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } | 9 | embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } |
| 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } |
| 12 | embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } | 12 | embassy-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] |
| 8 | embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } | 8 | embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } |
| 9 | embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } | 9 | embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } |
| 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } |
| 12 | embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } | 12 | embassy-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] |
| 8 | embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } | 8 | embassy-sync = { version = "0.6.1", path = "../../../../embassy-sync" } |
| 9 | embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "integrated-timers"] } | 9 | embassy-executor = { version = "0.6.3", path = "../../../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread"] } |
| 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.3.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wl55jc-cm4", "time-driver-any", "exti"] } |
| 12 | embassy-boot-stm32 = { version = "0.2.0", path = "../../../../embassy-boot-stm32", features = [] } | 12 | embassy-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] |
| 18 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync" } | 18 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync" } |
| 19 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "integrated-timers"] } | 19 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace"] } |
| 20 | embassy-time = { version = "0.3.2", path = "../../embassy-time" } | 20 | embassy-time = { version = "0.3.2", path = "../../embassy-time" } |
| 21 | embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } | 21 | embassy-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" | |||
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 8 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 9 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 9 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 10 | embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "gpiote", "time-driver-rtc1", "unstable-pac", "time", "rt"] } | 10 | embassy-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] |
| 8 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 8 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 9 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 9 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 10 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 10 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-8192", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 11 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 11 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 12 | embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52810", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } | 12 | embassy-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 | ||
| 10 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 10 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 11 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 11 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", "generic-queue"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime"] } |
| 13 | embassy-time-queue-driver = { version = "0.1.0", path = "../../embassy-time-queue-driver", features = ["generic-queue-8"] } | ||
| 13 | embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } | 14 | embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = [ "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } |
| 14 | 15 | ||
| 15 | defmt = "0.3" | 16 | defmt = "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] |
| 8 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 8 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 9 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 9 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 10 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 10 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 11 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 11 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 12 | embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } | 12 | embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } |
| 13 | embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } | 13 | embassy-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] |
| 8 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 8 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 9 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 9 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 10 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 10 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } |
| 11 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 11 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 12 | embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } | 12 | embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf5340-app-s", "time-driver-rtc1", "gpiote", "unstable-pac"] } |
| 13 | embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } | 13 | embassy-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" | |||
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 8 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 9 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 9 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 10 | embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } | 10 | embassy-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" | |||
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-executor = { version = "0.6.3", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 8 | embassy-executor = { version = "0.6.3", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 9 | embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 9 | embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 10 | embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-ns", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } | 10 | embassy-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" | |||
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-executor = { version = "0.6.3", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 8 | embassy-executor = { version = "0.6.3", path = "../../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 9 | embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 9 | embassy-time = { version = "0.3.2", path = "../../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 10 | embassy-nrf = { version = "0.2.0", path = "../../../embassy-nrf", features = ["defmt", "nrf9120-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } | 10 | embassy-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" | |||
| 5 | license = "MIT OR Apache-2.0" | 5 | license = "MIT OR Apache-2.0" |
| 6 | 6 | ||
| 7 | [dependencies] | 7 | [dependencies] |
| 8 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 8 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 9 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 9 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 10 | embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } | 10 | embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "nrf9160-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } |
| 11 | embassy-net-nrf91 = { version = "0.1.0", path = "../../embassy-net-nrf91", features = ["defmt"] } | 11 | embassy-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] |
| 9 | embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } | 9 | embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } |
| 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 13 | embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } | 13 | embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] } |
| 14 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } | 14 | embassy-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] |
| 9 | embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } | 9 | embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal", features = ["defmt"] } |
| 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 13 | embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] } | 13 | embassy-rp = { version = "0.2.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp235xa", "binary-info"] } |
| 14 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } | 14 | embassy-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] |
| 8 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["log"] } | 8 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["log"] } |
| 9 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log", "integrated-timers"] } | 9 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-std", "executor-thread", "log"] } |
| 10 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "std", ] } | 10 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "std", ] } |
| 11 | embassy-net = { version = "0.5.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } | 11 | embassy-net = { version = "0.5.0", path = "../../embassy-net", features=[ "std", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } |
| 12 | embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } | 12 | embassy-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. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } |
| 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } |
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | 13 | ||
| 14 | defmt = "0.3" | 14 | defmt = "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" | |||
| 13 | defmt-rtt = "0.4" | 13 | defmt-rtt = "0.4" |
| 14 | panic-probe = { version = "0.3", features = ["print-defmt"] } | 14 | panic-probe = { version = "0.3", features = ["print-defmt"] } |
| 15 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 15 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 16 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 16 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 17 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 17 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 18 | static_cell = "2" | 18 | static_cell = "2" |
| 19 | portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } | 19 | portable-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. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any" ] } |
| 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } |
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } | 13 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } |
| 14 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 14 | embassy-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. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } |
| 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } |
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | 13 | ||
| 14 | defmt = "0.3" | 14 | defmt = "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. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-tim2", "exti"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-tim2", "exti"] } |
| 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } | 13 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } |
| 14 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 14 | embassy-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] |
| 8 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 8 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 9 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 9 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 10 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } |
| 12 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } | 12 | embassy-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. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-tim4", "exti", "chrono"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-tim4", "exti", "chrono"] } |
| 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt" ] } | 13 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt" ] } |
| 14 | embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", ] } | 14 | embassy-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 |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f469ni", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f469ni", "unstable-pac", "memory-x", "time-driver-any", "exti", "chrono"] } |
| 10 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 10 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 11 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 11 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 12 | 12 | ||
| 13 | defmt = "0.3" | 13 | defmt = "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. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32f777zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } |
| 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } |
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } | 13 | embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } |
| 14 | embedded-io-async = { version = "0.6.1" } | 14 | embedded-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. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g0b1re", "memory-x", "unstable-pac", "exti"] } |
| 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } |
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } | 13 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } |
| 14 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 14 | embassy-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. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } |
| 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } |
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } | 13 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } |
| 14 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 14 | embassy-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. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "low-power"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "low-power"] } |
| 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } |
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } | 13 | embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } |
| 14 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } | 14 | embassy-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" | |||
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } |
| 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } | 11 | embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } |
| 12 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 12 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 13 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 13 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 14 | embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } | 14 | embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } |
| 15 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } | 15 | embassy-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. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h723zg", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h723zg", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } |
| 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.2", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 13 | embassy-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" | |||
| 8 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h735ig", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } | 8 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h735ig", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } |
| 9 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 9 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 10 | embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } | 10 | embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } |
| 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 13 | embassy-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" | |||
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm4", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm4", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } |
| 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } | 11 | embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } |
| 12 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 12 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 13 | embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 13 | embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 14 | embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } | 14 | embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } |
| 15 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } | 15 | embassy-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" | |||
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm7", "time-driver-tim3", "exti", "memory-x", "unstable-pac", "chrono"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h755zi-cm7", "time-driver-tim3", "exti", "memory-x", "unstable-pac", "chrono"] } |
| 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } | 11 | embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } |
| 12 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 12 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 13 | embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 13 | embassy-time = { version = "0.3.1", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 14 | embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } | 14 | embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } |
| 15 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } | 15 | embassy-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" | |||
| 8 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7b0vb", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } | 8 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7b0vb", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } |
| 9 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 9 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 10 | embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } | 10 | embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } |
| 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } | 13 | embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } |
| 14 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } | 14 | embassy-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. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h7s3l8", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] } |
| 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } |
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } | 13 | embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } |
| 14 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } | 14 | embassy-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. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l073rz", "unstable-pac", "time-driver-any", "exti", "memory-x"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l073rz", "unstable-pac", "time-driver-any", "exti", "memory-x"] } |
| 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } |
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | 13 | ||
| 14 | defmt = "0.3" | 14 | defmt = "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] |
| 8 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 8 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 9 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 9 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } |
| 10 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 10 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } | 11 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } |
| 12 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } | 12 | embassy-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. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4r5zi", "memory-x", "time-driver-any", "exti", "chrono"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l4r5zi", "memory-x", "time-driver-any", "exti", "chrono"] } |
| 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } |
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", ] } |
| 13 | embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } | 13 | embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } |
| 14 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } | 14 | embassy-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. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "memory-x", "low-power"] } |
| 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } |
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } | 13 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } |
| 14 | embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } | 14 | embassy-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. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti", "chrono"] } |
| 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } |
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } | 13 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", default-features = false, features = ["defmt"] } |
| 14 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 14 | embassy-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. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u5g9zj", "time-driver-any", "memory-x" ] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "unstable-pac", "stm32u5g9zj", "time-driver-any", "memory-x" ] } |
| 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } |
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } | 13 | embassy-usb = { version = "0.3.0", path = "../../embassy-usb", features = ["defmt"] } |
| 14 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 14 | embassy-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" | |||
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wb55rg", "time-driver-any", "memory-x", "exti"] } |
| 10 | embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } | 10 | embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } |
| 11 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 11 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 12 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 12 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } |
| 13 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 13 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 14 | embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } | 14 | embassy-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] |
| 8 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } | 8 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } |
| 9 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 9 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 10 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 10 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } |
| 11 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 11 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 12 | embassy-net = { version = "0.5.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", ], optional=true } | 12 | embassy-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. |
| 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } | 9 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } |
| 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "defmt"] } |
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } |
| 13 | embassy-embedded-hal = { version = "0.2.0", path = "../../embassy-embedded-hal" } | 13 | embassy-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] |
| 11 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["log"] } | 11 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["log"] } |
| 12 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "integrated-timers"] } | 12 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log"] } |
| 13 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "wasm", ] } | 13 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["log", "wasm", ] } |
| 14 | 14 | ||
| 15 | wasm-logger = "0.2.0" | 15 | wasm-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 | ||
| 10 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 10 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 11 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt", ] } | 11 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt", ] } |
| 12 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 12 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } |
| 13 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } | 13 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } |
| 14 | embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } | 14 | embassy-nrf = { version = "0.2.0", path = "../../embassy-nrf", features = ["defmt", "time-driver-rtc1", "gpiote", "unstable-pac"] } |
| 15 | embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } | 15 | embedded-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" | |||
| 8 | teleprobe-meta = "1.1" | 8 | teleprobe-meta = "1.1" |
| 9 | 9 | ||
| 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 10 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 11 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt"] } |
| 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", ] } | 12 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", ] } |
| 13 | embassy-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"] } | 13 | embassy-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"] } |
| 14 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 14 | embassy-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"] | |||
| 60 | teleprobe-meta = "1" | 60 | teleprobe-meta = "1" |
| 61 | 61 | ||
| 62 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } | 62 | embassy-sync = { version = "0.6.1", path = "../../embassy-sync", features = ["defmt"] } |
| 63 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } | 63 | embassy-executor = { version = "0.6.3", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } |
| 64 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] } | 64 | embassy-time = { version = "0.3.2", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] } |
| 65 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] } | 65 | embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "unstable-pac", "memory-x", "time-driver-any"] } |
| 66 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 66 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
