Compare commits

...

52 Commits

Author SHA1 Message Date
8b36a32ed5 ci: use beta, add secondary nightly ci. 2023-12-21 15:03:57 +01:00
530ead5fde Merge pull request #2339 from embassy-rs/make-static-remove
Replace make_static! macro usage with non-macro version
2023-12-21 10:02:11 +00:00
8442e72589 Merge pull request #2338 from eZioPan/note-on-circular-dma
docs: add a note about circular mode DMA
2023-12-21 09:36:38 +00:00
0acf7b09c3 chore: replace make_static! macro usage with non-macro version 2023-12-21 10:29:57 +01:00
745d618ab7 note on circular mode DMA 2023-12-21 17:03:10 +08:00
d832d45c0b Merge pull request #2337 from embassy-rs/boot-nrf-sd-mbr
fix: remove git dependency in embassy-boot
2023-12-20 14:13:43 +00:00
03dc624fb1 Merge pull request #2336 from embassy-rs/noproto-cratesio
net-esp-hosted: use released noproto version.
2023-12-20 13:16:33 +00:00
d6fda686bc net-esp-hosted: use released noproto version. 2023-12-20 14:13:52 +01:00
896690c415 fix: remove git dependency in embassy-boot 2023-12-20 13:46:43 +01:00
76c600365d Merge pull request #2334 from embassy-rs/embassy-net-adin1110-docs
docs: embassy-net-adin1110
2023-12-20 12:44:19 +00:00
18dac099cb Merge pull request #2333 from embassy-rs/embassy-net-wiznet-docs
docs: document public apis of wiznet driver
2023-12-20 12:44:16 +00:00
49005e955d Merge pull request #2330 from embassy-rs/embassy-net-esp-hosted-docs
Embassy net esp hosted docs
2023-12-20 12:44:11 +00:00
70ea805af3 Merge pull request #2332 from embassy-rs/embassy-net-tuntap-docs
docs: document embassy-net-tuntap
2023-12-20 12:44:06 +00:00
93bb34d8d1 fix: expose less 2023-12-20 13:39:45 +01:00
51a67cb69a fix: expose less 2023-12-20 13:34:34 +01:00
c8eb128a56 Merge pull request #2328 from rmja/signal-try-take
feat(embassy-sync): Add try_take() to signal
2023-12-20 12:34:01 +00:00
22ee868f04 Merge pull request #2335 from embassy-rs/remove-embedded-sdmmc
remove embedded-sdmmc
2023-12-20 12:32:04 +00:00
1c3cf347cb remove embedded-sdmmc
Remove support for embedded-sdmmc due to lack of maintainership. Bring
it back once the upstream includes the async functionality.
2023-12-20 13:25:36 +01:00
b8777eaea2 better keep missing docs for into 2023-12-20 13:12:32 +01:00
13c107e815 Put waiting state back if any 2023-12-20 13:09:16 +01:00
b0583b17cb fix: make non-public instead 2023-12-20 13:08:06 +01:00
246c49621c docs: embassy-net-adin1110 2023-12-20 12:52:35 +01:00
c3b827d8cd fix: add readme and fix remaining warnings 2023-12-20 12:24:51 +01:00
4dfae9328e add missing guards 2023-12-20 12:18:02 +01:00
73f8cd7ade fix: add repository to manifest 2023-12-20 12:16:01 +01:00
4a2dd7b944 docs: document public apis of wiznet driver 2023-12-20 12:14:25 +01:00
afb01e3fc5 docs: document embassy-net-tuntap 2023-12-20 12:08:26 +01:00
89cfdcb9f5 fix suddenly ending comment 2023-12-20 12:06:49 +01:00
abea4dde3d docs: document most of esp-hosted driver 2023-12-20 10:15:18 +01:00
52a801fdb7 Merge pull request #2329 from embassy-rs/apidoc-embassy-net-driver-channel
docs: document public apis of embassy-net-driver-channel
2023-12-20 09:08:55 +00:00
fc6e70caa5 docs: document public apis of embassy-net-driver-channel 2023-12-20 09:24:10 +01:00
f9d0daad80 feat(embassy-sync): Add try_take() to signal 2023-12-20 08:37:15 +01:00
97e919ea64 Merge pull request #2326 from embassy-rs/salty-update
Salty update
2023-12-19 21:30:32 +00:00
c7841a37fa boot: update ed25519-dalek in dev-dependencies. 2023-12-19 22:26:50 +01:00
589a16b255 Merge pull request #2327 from dragonnn/main
fix stm32 rtc year from 1970 base 2000 to make leap years work
2023-12-19 20:26:01 +00:00
4567b87482 cargo fmt 2023-12-19 21:21:52 +01:00
12de90e13d fix: update ed25519-dalek to new version 2023-12-19 21:20:30 +01:00
871ed538b1 fix stm32 rtc year from 1970 base 2000 2023-12-19 21:17:42 +01:00
efd5dbe019 fix: build warnings 2023-12-19 20:25:20 +01:00
9d46ee0758 fix: update salty to released version 2023-12-19 20:24:55 +01:00
e5912972ec Merge pull request #2325 from embassy-rs/stm32-docs
stm32: finish docs.
2023-12-19 17:07:53 +00:00
c8c8b89104 stm32: doc everything else. 2023-12-19 18:03:20 +01:00
189b15c426 stm32/timer: docs. 2023-12-19 17:35:38 +01:00
41c3c26beb Merge pull request #2323 from embassy-rs/embassy-usb-stuffs
docs: document usb-logger and usb-dfu
2023-12-19 16:58:46 +01:00
7ec1ed4de3 Merge pull request #2324 from barnabywalters/stm32-usart-docs
stm32: Documented usart public API
2023-12-19 16:58:27 +01:00
6564c04531 Reset .vscode/settings.json (doh) 2023-12-19 16:42:51 +01:00
f97ef61ef8 Documented usart public API 2023-12-19 16:41:00 +01:00
71584409d9 Merge pull request #2321 from embassy-rs/stm32-docs
stm32: document hrtim, qspi, sdmmc, spi.
2023-12-19 15:29:26 +00:00
1ea87ec6e7 stm32: document hrtim, qspi, sdmmc, spi. 2023-12-19 16:21:51 +01:00
7d9a76da00 Merge pull request #2313 from eZioPan/update-metapac6
match up with "DMA cleanup" metapac change
2023-12-19 15:20:15 +00:00
3e2e109437 update metapac dep 2023-12-19 19:09:06 +08:00
254d587385 match up with metapac change 2023-12-19 17:12:34 +08:00
421 changed files with 1310 additions and 1028 deletions

View File

@ -7,6 +7,7 @@ set -euo pipefail
export RUSTUP_HOME=/ci/cache/rustup export RUSTUP_HOME=/ci/cache/rustup
export CARGO_HOME=/ci/cache/cargo export CARGO_HOME=/ci/cache/cargo
export CARGO_TARGET_DIR=/ci/cache/target export CARGO_TARGET_DIR=/ci/cache/target
mv rust-toolchain-nightly.toml rust-toolchain.toml
# needed for "dumb HTTP" transport support # needed for "dumb HTTP" transport support
# used when pointing stm32-metapac to a CI-built one. # used when pointing stm32-metapac to a CI-built one.
@ -21,9 +22,7 @@ fi
hashtime restore /ci/cache/filetime.json || true hashtime restore /ci/cache/filetime.json || true
hashtime save /ci/cache/filetime.json hashtime save /ci/cache/filetime.json
sed -i 's/channel.*/channel = "beta"/g' rust-toolchain.toml ./ci-nightly.sh
./ci_stable.sh
# Save lockfiles # Save lockfiles
echo Saving lockfiles... echo Saving lockfiles...

12
.github/ci/rustfmt.sh vendored Executable file
View File

@ -0,0 +1,12 @@
#!/bin/bash
## on push branch~=gh-readonly-queue/main/.*
## on pull_request
set -euo pipefail
export RUSTUP_HOME=/ci/cache/rustup
export CARGO_HOME=/ci/cache/cargo
export CARGO_TARGET_DIR=/ci/cache/target
mv rust-toolchain-nightly.toml rust-toolchain.toml
find . -name '*.rs' -not -path '*target*' | xargs rustfmt --check --skip-children --unstable-features --edition 2021

13
.github/ci/test-nightly.sh vendored Executable file
View File

@ -0,0 +1,13 @@
#!/bin/bash
## on push branch~=gh-readonly-queue/main/.*
## on pull_request
set -euo pipefail
export RUSTUP_HOME=/ci/cache/rustup
export CARGO_HOME=/ci/cache/cargo
export CARGO_TARGET_DIR=/ci/cache/target
mv rust-toolchain-nightly.toml rust-toolchain.toml
MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml
MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml --features nightly

3
.github/ci/test.sh vendored
View File

@ -8,9 +8,6 @@ export RUSTUP_HOME=/ci/cache/rustup
export CARGO_HOME=/ci/cache/cargo export CARGO_HOME=/ci/cache/cargo
export CARGO_TARGET_DIR=/ci/cache/target export CARGO_TARGET_DIR=/ci/cache/target
MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml
MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml --features nightly
cargo test --manifest-path ./embassy-sync/Cargo.toml cargo test --manifest-path ./embassy-sync/Cargo.toml
cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml
cargo test --manifest-path ./embassy-hal-internal/Cargo.toml cargo test --manifest-path ./embassy-hal-internal/Cargo.toml

View File

@ -15,14 +15,10 @@
//"rust-analyzer.cargo.target": "thumbv7m-none-eabi", //"rust-analyzer.cargo.target": "thumbv7m-none-eabi",
"rust-analyzer.cargo.target": "thumbv7em-none-eabi", "rust-analyzer.cargo.target": "thumbv7em-none-eabi",
//"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf", //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf",
"rust-analyzer.cargo.features": [
// Uncomment if the example has a "nightly" feature.
"nightly",
],
"rust-analyzer.linkedProjects": [ "rust-analyzer.linkedProjects": [
// Uncomment ONE line for the chip you want to work on. // Uncomment ONE line for the chip you want to work on.
// This makes rust-analyzer work on the example crate and all its dependencies. // This makes rust-analyzer work on the example crate and all its dependencies.
"examples/nrf52840/Cargo.toml", "examples/stm32l4/Cargo.toml",
// "examples/nrf52840-rtic/Cargo.toml", // "examples/nrf52840-rtic/Cargo.toml",
// "examples/nrf5340/Cargo.toml", // "examples/nrf5340/Cargo.toml",
// "examples/nrf-rtos-trace/Cargo.toml", // "examples/nrf-rtos-trace/Cargo.toml",
@ -49,4 +45,4 @@
// "examples/stm32wl/Cargo.toml", // "examples/stm32wl/Cargo.toml",
// "examples/wasm/Cargo.toml", // "examples/wasm/Cargo.toml",
], ],
} }

30
ci-nightly.sh Executable file
View File

@ -0,0 +1,30 @@
#!/bin/bash
set -eo pipefail
export RUSTFLAGS=-Dwarnings
export DEFMT_LOG=trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info
if [[ -z "${CARGO_TARGET_DIR}" ]]; then
export CARGO_TARGET_DIR=target_ci
fi
cargo batch \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,log \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,defmt \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,integrated-timers \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,integrated-timers \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt,integrated-timers \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \
--- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32 \
--- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,integrated-timers \
--- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread \
--- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread,integrated-timers \
--- build --release --manifest-path examples/nrf52840-rtic/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840-rtic \

41
ci.sh
View File

@ -15,26 +15,24 @@ if [ $TARGET = "x86_64-unknown-linux-gnu" ]; then
BUILD_EXTRA="--- build --release --manifest-path examples/std/Cargo.toml --target $TARGET --out-dir out/examples/std" BUILD_EXTRA="--- build --release --manifest-path examples/std/Cargo.toml --target $TARGET --out-dir out/examples/std"
fi fi
find . -name '*.rs' -not -path '*target*' | xargs rustfmt --check --skip-children --unstable-features --edition 2021
cargo batch \ cargo batch \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,log \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features log \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,defmt \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features defmt \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,integrated-timers \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,integrated-timers \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,integrated-timers \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread,integrated-timers \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-interrupt \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt,integrated-timers \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-interrupt,integrated-timers \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread,executor-interrupt \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \ --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \
--- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32 \ --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32 \
--- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,integrated-timers \ --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,integrated-timers \
--- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread \ --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,executor-thread \
--- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread,integrated-timers \ --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features arch-riscv32,executor-thread,integrated-timers \
--- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features defmt \ --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features defmt \
--- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \ --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \
@ -91,12 +89,12 @@ cargo batch \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f417zg,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f417zg,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f423zh,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f423zh,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f427zi,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f427zi,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,embedded-sdmmc,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f437zi,log,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f437zi,log,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f439zi,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f439zi,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f446ze,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f446ze,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f469zi,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f469zi,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f479zi,defmt,exti,time-driver-any,embedded-sdmmc,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f479zi,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f730i8,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f730i8,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h753zi,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h753zi,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h735zg,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h735zg,defmt,exti,time-driver-any,time \
@ -140,7 +138,6 @@ cargo batch \
--- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-irq/Cargo.toml --target thumbv7em-none-eabi \ --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-irq/Cargo.toml --target thumbv7em-none-eabi \
--- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml --target thumbv7em-none-eabi \ --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml --target thumbv7em-none-eabi \
--- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \ --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \
--- build --release --manifest-path examples/nrf52840-rtic/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840-rtic \
--- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \ --- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \
--- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \ --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \
--- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \ --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \

View File

@ -1,77 +0,0 @@
#!/bin/bash
set -euo pipefail
export RUSTFLAGS=-Dwarnings
export DEFMT_LOG=trace
cargo batch \
--- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
--- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \
--- build --release --manifest-path embassy-boot/rp/Cargo.toml --target thumbv6m-none-eabi \
--- build --release --manifest-path embassy-boot/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features log \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features defmt \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features defmt \
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52805,gpiote,time-driver-rtc1 \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52810,gpiote,time-driver-rtc1 \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52811,gpiote,time-driver-rtc1 \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52820,gpiote,time-driver-rtc1 \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52832,gpiote,time-driver-rtc1 \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52833,gpiote,time-driver-rtc1 \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf9160-s,gpiote,time-driver-rtc1 \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf9160-ns,gpiote,time-driver-rtc1 \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-app-s,gpiote,time-driver-rtc1 \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-app-ns,gpiote,time-driver-rtc1 \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nrf5340-net,gpiote,time-driver-rtc1 \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,time-driver-rtc1 \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,log,gpiote,time-driver-rtc1 \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,defmt,gpiote,time-driver-rtc1 \
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features defmt \
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features log \
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi \
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features qspi-as-gpio \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g473cc,defmt,exti,time-driver-any \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g491re,defmt,exti,time-driver-any \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585zi,defmt,exti,time-driver-any \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55vy,defmt,exti,time-driver-any \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55cc-cm4,defmt,exti,time-driver-any \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g473cc,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g491re,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585zi,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55vy,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55cc-cm4,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4r9zi,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303vc,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,time \
--- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --no-default-features --out-dir out/examples/nrf52840 --bin raw_spawn \
--- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --no-default-features --out-dir out/examples/stm32l0 --bin raw_spawn \

View File

@ -1,6 +1,5 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)]
use defmt::*; use defmt::*;
use embassy_executor::Spawner; use embassy_executor::Spawner;

View File

@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
cortex-m = "0.7" cortex-m = "0.7"
cortex-m-rt = "0.7" cortex-m-rt = "0.7"
embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x", "exti"] } embassy-stm32 = { version = "0.1.0", features = ["stm32l475vg", "memory-x", "exti"] }
embassy-executor = { version = "0.4.0", features = ["nightly", "arch-cortex-m", "executor-thread"] } embassy-executor = { version = "0.4.0", features = ["arch-cortex-m", "executor-thread"] }
defmt = "0.3.0" defmt = "0.3.0"
defmt-rtt = "0.3.0" defmt-rtt = "0.3.0"

View File

@ -1,6 +1,5 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)]
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::exti::ExtiInput; use embassy_stm32::exti::ExtiInput;

View File

@ -26,25 +26,22 @@ features = ["defmt"]
defmt = { version = "0.3", optional = true } defmt = { version = "0.3", optional = true }
digest = "0.10" digest = "0.10"
log = { version = "0.4", optional = true } log = { version = "0.4", optional = true }
ed25519-dalek = { version = "1.0.1", default_features = false, features = ["u32_backend"], optional = true } ed25519-dalek = { version = "2", default_features = false, features = ["digest"], optional = true }
embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
embassy-sync = { version = "0.5.0", path = "../../embassy-sync" } embassy-sync = { version = "0.5.0", path = "../../embassy-sync" }
embedded-storage = "0.3.1" embedded-storage = "0.3.1"
embedded-storage-async = { version = "0.4.1" } embedded-storage-async = { version = "0.4.1" }
salty = { git = "https://github.com/ycrypto/salty.git", rev = "a9f17911a5024698406b75c0fac56ab5ccf6a8c7", optional = true } salty = { version = "0.3", optional = true }
signature = { version = "1.6.4", default-features = false } signature = { version = "2.0", default-features = false }
[dev-dependencies] [dev-dependencies]
log = "0.4" log = "0.4"
env_logger = "0.9" env_logger = "0.9"
rand = "0.7" # ed25519-dalek v1.0.1 depends on this exact version rand = "0.8"
futures = { version = "0.3", features = ["executor"] } futures = { version = "0.3", features = ["executor"] }
sha1 = "0.10.5" sha1 = "0.10.5"
critical-section = { version = "1.1.1", features = ["std"] } critical-section = { version = "1.1.1", features = ["std"] }
ed25519-dalek = { version = "2", default_features = false, features = ["std", "rand_core", "digest"] }
[dev-dependencies.ed25519-dalek]
default_features = false
features = ["rand", "std", "u32_backend"]
[features] [features]
ed25519-dalek = ["dep:ed25519-dalek", "_verify"] ed25519-dalek = ["dep:ed25519-dalek", "_verify"]

View File

@ -1,6 +1,6 @@
use digest::typenum::U64; use digest::typenum::U64;
use digest::{FixedOutput, HashMarker, OutputSizeUser, Update}; use digest::{FixedOutput, HashMarker, OutputSizeUser, Update};
use ed25519_dalek::Digest as _; use ed25519_dalek::Digest;
pub struct Sha512(ed25519_dalek::Sha512); pub struct Sha512(ed25519_dalek::Sha512);
@ -12,7 +12,7 @@ impl Default for Sha512 {
impl Update for Sha512 { impl Update for Sha512 {
fn update(&mut self, data: &[u8]) { fn update(&mut self, data: &[u8]) {
self.0.update(data) Digest::update(&mut self.0, data)
} }
} }

View File

@ -79,8 +79,8 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> {
#[cfg(feature = "_verify")] #[cfg(feature = "_verify")]
pub async fn verify_and_mark_updated( pub async fn verify_and_mark_updated(
&mut self, &mut self,
_public_key: &[u8], _public_key: &[u8; 32],
_signature: &[u8], _signature: &[u8; 64],
_update_len: u32, _update_len: u32,
) -> Result<(), FirmwareUpdaterError> { ) -> Result<(), FirmwareUpdaterError> {
assert!(_update_len <= self.dfu.capacity() as u32); assert!(_update_len <= self.dfu.capacity() as u32);
@ -89,14 +89,14 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> {
#[cfg(feature = "ed25519-dalek")] #[cfg(feature = "ed25519-dalek")]
{ {
use ed25519_dalek::{PublicKey, Signature, SignatureError, Verifier}; use ed25519_dalek::{Signature, SignatureError, Verifier, VerifyingKey};
use crate::digest_adapters::ed25519_dalek::Sha512; use crate::digest_adapters::ed25519_dalek::Sha512;
let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into()); let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into());
let public_key = PublicKey::from_bytes(_public_key).map_err(into_signature_error)?; let public_key = VerifyingKey::from_bytes(_public_key).map_err(into_signature_error)?;
let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; let signature = Signature::from_bytes(_signature);
let mut chunk_buf = [0; 2]; let mut chunk_buf = [0; 2];
let mut message = [0; 64]; let mut message = [0; 64];
@ -106,7 +106,6 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> {
} }
#[cfg(feature = "ed25519-salty")] #[cfg(feature = "ed25519-salty")]
{ {
use salty::constants::{PUBLICKEY_SERIALIZED_LENGTH, SIGNATURE_SERIALIZED_LENGTH};
use salty::{PublicKey, Signature}; use salty::{PublicKey, Signature};
use crate::digest_adapters::salty::Sha512; use crate::digest_adapters::salty::Sha512;
@ -115,10 +114,8 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> {
FirmwareUpdaterError::Signature(signature::Error::default()) FirmwareUpdaterError::Signature(signature::Error::default())
} }
let public_key: [u8; PUBLICKEY_SERIALIZED_LENGTH] = _public_key.try_into().map_err(into_signature_error)?; let public_key = PublicKey::try_from(_public_key).map_err(into_signature_error)?;
let public_key = PublicKey::try_from(&public_key).map_err(into_signature_error)?; let signature = Signature::try_from(_signature).map_err(into_signature_error)?;
let signature: [u8; SIGNATURE_SERIALIZED_LENGTH] = _signature.try_into().map_err(into_signature_error)?;
let signature = Signature::try_from(&signature).map_err(into_signature_error)?;
let mut message = [0; 64]; let mut message = [0; 64];
let mut chunk_buf = [0; 2]; let mut chunk_buf = [0; 2];

View File

@ -86,8 +86,8 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE>
#[cfg(feature = "_verify")] #[cfg(feature = "_verify")]
pub fn verify_and_mark_updated( pub fn verify_and_mark_updated(
&mut self, &mut self,
_public_key: &[u8], _public_key: &[u8; 32],
_signature: &[u8], _signature: &[u8; 64],
_update_len: u32, _update_len: u32,
) -> Result<(), FirmwareUpdaterError> { ) -> Result<(), FirmwareUpdaterError> {
assert!(_update_len <= self.dfu.capacity() as u32); assert!(_update_len <= self.dfu.capacity() as u32);
@ -96,14 +96,14 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE>
#[cfg(feature = "ed25519-dalek")] #[cfg(feature = "ed25519-dalek")]
{ {
use ed25519_dalek::{PublicKey, Signature, SignatureError, Verifier}; use ed25519_dalek::{Signature, SignatureError, Verifier, VerifyingKey};
use crate::digest_adapters::ed25519_dalek::Sha512; use crate::digest_adapters::ed25519_dalek::Sha512;
let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into()); let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into());
let public_key = PublicKey::from_bytes(_public_key).map_err(into_signature_error)?; let public_key = VerifyingKey::from_bytes(_public_key).map_err(into_signature_error)?;
let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; let signature = Signature::from_bytes(_signature);
let mut message = [0; 64]; let mut message = [0; 64];
let mut chunk_buf = [0; 2]; let mut chunk_buf = [0; 2];
@ -113,7 +113,6 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE>
} }
#[cfg(feature = "ed25519-salty")] #[cfg(feature = "ed25519-salty")]
{ {
use salty::constants::{PUBLICKEY_SERIALIZED_LENGTH, SIGNATURE_SERIALIZED_LENGTH};
use salty::{PublicKey, Signature}; use salty::{PublicKey, Signature};
use crate::digest_adapters::salty::Sha512; use crate::digest_adapters::salty::Sha512;
@ -122,10 +121,8 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE>
FirmwareUpdaterError::Signature(signature::Error::default()) FirmwareUpdaterError::Signature(signature::Error::default())
} }
let public_key: [u8; PUBLICKEY_SERIALIZED_LENGTH] = _public_key.try_into().map_err(into_signature_error)?; let public_key = PublicKey::try_from(_public_key).map_err(into_signature_error)?;
let public_key = PublicKey::try_from(&public_key).map_err(into_signature_error)?; let signature = Signature::try_from(_signature).map_err(into_signature_error)?;
let signature: [u8; SIGNATURE_SERIALIZED_LENGTH] = _signature.try_into().map_err(into_signature_error)?;
let signature = Signature::try_from(&signature).map_err(into_signature_error)?;
let mut message = [0; 64]; let mut message = [0; 64];
let mut chunk_buf = [0; 2]; let mut chunk_buf = [0; 2];

View File

@ -275,21 +275,19 @@ mod tests {
// The following key setup is based on: // The following key setup is based on:
// https://docs.rs/ed25519-dalek/latest/ed25519_dalek/#example // https://docs.rs/ed25519-dalek/latest/ed25519_dalek/#example
use ed25519_dalek::Keypair; use ed25519_dalek::{Digest, Sha512, Signature, Signer, SigningKey, VerifyingKey};
use rand::rngs::OsRng; use rand::rngs::OsRng;
let mut csprng = OsRng {}; let mut csprng = OsRng {};
let keypair: Keypair = Keypair::generate(&mut csprng); let keypair = SigningKey::generate(&mut csprng);
use ed25519_dalek::{Digest, Sha512, Signature, Signer};
let firmware: &[u8] = b"This are bytes that would otherwise be firmware bytes for DFU."; let firmware: &[u8] = b"This are bytes that would otherwise be firmware bytes for DFU.";
let mut digest = Sha512::new(); let mut digest = Sha512::new();
digest.update(&firmware); digest.update(&firmware);
let message = digest.finalize(); let message = digest.finalize();
let signature: Signature = keypair.sign(&message); let signature: Signature = keypair.sign(&message);
use ed25519_dalek::PublicKey; let public_key = keypair.verifying_key();
let public_key: PublicKey = keypair.public;
// Setup flash // Setup flash
let flash = BlockingTestFlash::new(BootLoaderConfig { let flash = BlockingTestFlash::new(BootLoaderConfig {

View File

@ -4,6 +4,12 @@ name = "embassy-boot-nrf"
version = "0.1.0" version = "0.1.0"
description = "Bootloader lib for nRF chips" description = "Bootloader lib for nRF chips"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
repository = "https://github.com/embassy-rs/embassy"
categories = [
"embedded",
"no-std",
"asynchronous",
]
[package.metadata.embassy_docs] [package.metadata.embassy_docs]
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-nrf-v$VERSION/embassy-boot/nrf/src/" src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-nrf-v$VERSION/embassy-boot/nrf/src/"
@ -25,7 +31,7 @@ embedded-storage = "0.3.1"
embedded-storage-async = { version = "0.4.1" } embedded-storage-async = { version = "0.4.1" }
cfg-if = "1.0.0" cfg-if = "1.0.0"
nrf-softdevice-mbr = { version = "0.1.0", git = "https://github.com/embassy-rs/nrf-softdevice.git", branch = "master", optional = true } nrf-softdevice-mbr = { version = "0.2.0", optional = true }
[features] [features]
defmt = [ defmt = [

View File

@ -4,6 +4,12 @@ name = "embassy-boot-rp"
version = "0.1.0" version = "0.1.0"
description = "Bootloader lib for RP2040 chips" description = "Bootloader lib for RP2040 chips"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
repository = "https://github.com/embassy-rs/embassy"
categories = [
"embedded",
"no-std",
"asynchronous",
]
[package.metadata.embassy_docs] [package.metadata.embassy_docs]
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-rp-v$VERSION/src/" src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-rp-v$VERSION/src/"

View File

@ -4,6 +4,12 @@ name = "embassy-boot-stm32"
version = "0.1.0" version = "0.1.0"
description = "Bootloader lib for STM32 chips" description = "Bootloader lib for STM32 chips"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
repository = "https://github.com/embassy-rs/embassy"
categories = [
"embedded",
"no-std",
"asynchronous",
]
[package.metadata.embassy_docs] [package.metadata.embassy_docs]
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-nrf-v$VERSION/embassy-boot/stm32/src/" src_base = "https://github.com/embassy-rs/embassy/blob/embassy-boot-nrf-v$VERSION/embassy-boot/stm32/src/"

View File

@ -14,7 +14,7 @@ categories = [
[package.metadata.embassy_docs] [package.metadata.embassy_docs]
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-executor-v$VERSION/embassy-executor/src/" src_base = "https://github.com/embassy-rs/embassy/blob/embassy-executor-v$VERSION/embassy-executor/src/"
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-executor/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-executor/src/"
features = ["nightly", "defmt"] features = ["defmt"]
flavors = [ flavors = [
{ name = "std", target = "x86_64-unknown-linux-gnu", features = ["arch-std", "executor-thread"] }, { name = "std", target = "x86_64-unknown-linux-gnu", features = ["arch-std", "executor-thread"] },
{ name = "wasm", target = "wasm32-unknown-unknown", features = ["arch-wasm", "executor-thread"] }, { name = "wasm", target = "wasm32-unknown-unknown", features = ["arch-wasm", "executor-thread"] },
@ -25,7 +25,7 @@ flavors = [
[package.metadata.docs.rs] [package.metadata.docs.rs]
default-target = "thumbv7em-none-eabi" default-target = "thumbv7em-none-eabi"
targets = ["thumbv7em-none-eabi"] targets = ["thumbv7em-none-eabi"]
features = ["nightly", "defmt", "arch-cortex-m", "executor-thread", "executor-interrupt"] features = ["defmt", "arch-cortex-m", "executor-thread", "executor-interrupt"]
[dependencies] [dependencies]
defmt = { version = "0.3", optional = true } defmt = { version = "0.3", optional = true }

View File

@ -6,8 +6,7 @@ keywords = ["embedded", "ADIN1110", "embassy-net", "embedded-hal-async", "ethern
categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
edition = "2021" edition = "2021"
repository = "https://github.com/embassy-rs/embassy"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
heapless = "0.8" heapless = "0.8"

View File

@ -1,3 +1,4 @@
/// CRC32 lookup table.
pub const CRC32R_LOOKUP_TABLE: [u32; 256] = [ pub const CRC32R_LOOKUP_TABLE: [u32; 256] = [
0x0000_0000, 0x0000_0000,
0x7707_3096, 0x7707_3096,
@ -263,8 +264,9 @@ pub const CRC32R_LOOKUP_TABLE: [u32; 256] = [
pub struct ETH_FCS(pub u32); pub struct ETH_FCS(pub u32);
impl ETH_FCS { impl ETH_FCS {
pub const CRC32_OK: u32 = 0x2144_df1c; const CRC32_OK: u32 = 0x2144_df1c;
/// Create a new frame check sequence from `data`.
#[must_use] #[must_use]
pub fn new(data: &[u8]) -> Self { pub fn new(data: &[u8]) -> Self {
let fcs = data.iter().fold(u32::MAX, |crc, byte| { let fcs = data.iter().fold(u32::MAX, |crc, byte| {
@ -274,6 +276,7 @@ impl ETH_FCS {
Self(fcs) Self(fcs)
} }
/// Update the frame check sequence with `data`.
#[must_use] #[must_use]
pub fn update(self, data: &[u8]) -> Self { pub fn update(self, data: &[u8]) -> Self {
let fcs = data.iter().fold(self.0 ^ u32::MAX, |crc, byte| { let fcs = data.iter().fold(self.0 ^ u32::MAX, |crc, byte| {
@ -283,16 +286,19 @@ impl ETH_FCS {
Self(fcs) Self(fcs)
} }
/// Check if the frame check sequence is correct.
#[must_use] #[must_use]
pub fn crc_ok(&self) -> bool { pub fn crc_ok(&self) -> bool {
self.0 == Self::CRC32_OK self.0 == Self::CRC32_OK
} }
/// Switch byte order.
#[must_use] #[must_use]
pub fn hton_bytes(&self) -> [u8; 4] { pub fn hton_bytes(&self) -> [u8; 4] {
self.0.to_le_bytes() self.0.to_le_bytes()
} }
/// Switch byte order as a u32.
#[must_use] #[must_use]
pub fn hton(&self) -> u32 { pub fn hton(&self) -> u32 {
self.0.to_le() self.0.to_le()

View File

@ -5,6 +5,7 @@
#![allow(clippy::missing_errors_doc)] #![allow(clippy::missing_errors_doc)]
#![allow(clippy::missing_panics_doc)] #![allow(clippy::missing_panics_doc)]
#![doc = include_str!("../README.md")] #![doc = include_str!("../README.md")]
#![warn(missing_docs)]
// must go first! // must go first!
mod fmt; mod fmt;
@ -26,8 +27,9 @@ use embedded_hal_async::digital::Wait;
use embedded_hal_async::spi::{Error, Operation, SpiDevice}; use embedded_hal_async::spi::{Error, Operation, SpiDevice};
use heapless::Vec; use heapless::Vec;
pub use mdio::MdioBus; pub use mdio::MdioBus;
pub use phy::{Phy10BaseT1x, RegsC22, RegsC45}; pub use phy::Phy10BaseT1x;
pub use regs::{Config0, Config2, SpiRegisters as sr, Status0, Status1}; use phy::{RegsC22, RegsC45};
use regs::{Config0, Config2, SpiRegisters as sr, Status0, Status1};
use crate::fmt::Bytes; use crate::fmt::Bytes;
use crate::regs::{LedCntrl, LedFunc, LedPol, LedPolarity, SpiHeader}; use crate::regs::{LedCntrl, LedFunc, LedPol, LedPolarity, SpiHeader};
@ -446,6 +448,7 @@ pub struct Runner<'d, SPI, INT, RST> {
} }
impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> { impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> {
/// Run the driver.
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
pub async fn run(mut self) -> ! { pub async fn run(mut self) -> ! {
loop { loop {

View File

@ -39,6 +39,7 @@ enum Reg13Op {
/// ///
/// Clause 45 methodes are bases on <https://www.ieee802.org/3/efm/public/nov02/oam/pannell_oam_1_1102.pdf> /// Clause 45 methodes are bases on <https://www.ieee802.org/3/efm/public/nov02/oam/pannell_oam_1_1102.pdf>
pub trait MdioBus { pub trait MdioBus {
/// Error type.
type Error; type Error;
/// Read, Clause 22 /// Read, Clause 22

View File

@ -2,6 +2,7 @@ use core::fmt::{Debug, Display};
use bitfield::{bitfield, bitfield_bitrange, bitfield_fields}; use bitfield::{bitfield, bitfield_bitrange, bitfield_fields};
#[allow(missing_docs)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]

View File

@ -1,5 +1,6 @@
#![no_std] #![no_std]
#![doc = include_str!("../README.md")] #![doc = include_str!("../README.md")]
#![warn(missing_docs)]
// must go first! // must go first!
mod fmt; mod fmt;
@ -15,6 +16,9 @@ use embassy_sync::blocking_mutex::Mutex;
use embassy_sync::waitqueue::WakerRegistration; use embassy_sync::waitqueue::WakerRegistration;
use embassy_sync::zerocopy_channel; use embassy_sync::zerocopy_channel;
/// Channel state.
///
/// Holds a buffer of packets with size MTU, for both TX and RX.
pub struct State<const MTU: usize, const N_RX: usize, const N_TX: usize> { pub struct State<const MTU: usize, const N_RX: usize, const N_TX: usize> {
rx: [PacketBuf<MTU>; N_RX], rx: [PacketBuf<MTU>; N_RX],
tx: [PacketBuf<MTU>; N_TX], tx: [PacketBuf<MTU>; N_TX],
@ -24,6 +28,7 @@ pub struct State<const MTU: usize, const N_RX: usize, const N_TX: usize> {
impl<const MTU: usize, const N_RX: usize, const N_TX: usize> State<MTU, N_RX, N_TX> { impl<const MTU: usize, const N_RX: usize, const N_TX: usize> State<MTU, N_RX, N_TX> {
const NEW_PACKET: PacketBuf<MTU> = PacketBuf::new(); const NEW_PACKET: PacketBuf<MTU> = PacketBuf::new();
/// Create a new channel state.
pub const fn new() -> Self { pub const fn new() -> Self {
Self { Self {
rx: [Self::NEW_PACKET; N_RX], rx: [Self::NEW_PACKET; N_RX],
@ -39,33 +44,45 @@ struct StateInner<'d, const MTU: usize> {
shared: Mutex<NoopRawMutex, RefCell<Shared>>, shared: Mutex<NoopRawMutex, RefCell<Shared>>,
} }
/// State of the LinkState
struct Shared { struct Shared {
link_state: LinkState, link_state: LinkState,
waker: WakerRegistration, waker: WakerRegistration,
hardware_address: driver::HardwareAddress, hardware_address: driver::HardwareAddress,
} }
/// Channel runner.
///
/// Holds the shared state and the lower end of channels for inbound and outbound packets.
pub struct Runner<'d, const MTU: usize> { pub struct Runner<'d, const MTU: usize> {
tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>, tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>,
rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>, rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>,
shared: &'d Mutex<NoopRawMutex, RefCell<Shared>>, shared: &'d Mutex<NoopRawMutex, RefCell<Shared>>,
} }
/// State runner.
///
/// Holds the shared state of the channel such as link state.
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct StateRunner<'d> { pub struct StateRunner<'d> {
shared: &'d Mutex<NoopRawMutex, RefCell<Shared>>, shared: &'d Mutex<NoopRawMutex, RefCell<Shared>>,
} }
/// RX runner.
///
/// Holds the lower end of the channel for passing inbound packets up the stack.
pub struct RxRunner<'d, const MTU: usize> { pub struct RxRunner<'d, const MTU: usize> {
rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>, rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>,
} }
/// TX runner.
///
/// Holds the lower end of the channel for passing outbound packets down the stack.
pub struct TxRunner<'d, const MTU: usize> { pub struct TxRunner<'d, const MTU: usize> {
tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>, tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>,
} }
impl<'d, const MTU: usize> Runner<'d, MTU> { impl<'d, const MTU: usize> Runner<'d, MTU> {
/// Split the runner into separate runners for controlling state, rx and tx.
pub fn split(self) -> (StateRunner<'d>, RxRunner<'d, MTU>, TxRunner<'d, MTU>) { pub fn split(self) -> (StateRunner<'d>, RxRunner<'d, MTU>, TxRunner<'d, MTU>) {
( (
StateRunner { shared: self.shared }, StateRunner { shared: self.shared },
@ -74,6 +91,7 @@ impl<'d, const MTU: usize> Runner<'d, MTU> {
) )
} }
/// Split the runner into separate runners for controlling state, rx and tx borrowing the underlying state.
pub fn borrow_split(&mut self) -> (StateRunner<'_>, RxRunner<'_, MTU>, TxRunner<'_, MTU>) { pub fn borrow_split(&mut self) -> (StateRunner<'_>, RxRunner<'_, MTU>, TxRunner<'_, MTU>) {
( (
StateRunner { shared: self.shared }, StateRunner { shared: self.shared },
@ -86,10 +104,12 @@ impl<'d, const MTU: usize> Runner<'d, MTU> {
) )
} }
/// Create a state runner sharing the state channel.
pub fn state_runner(&self) -> StateRunner<'d> { pub fn state_runner(&self) -> StateRunner<'d> {
StateRunner { shared: self.shared } StateRunner { shared: self.shared }
} }
/// Set the link state.
pub fn set_link_state(&mut self, state: LinkState) { pub fn set_link_state(&mut self, state: LinkState) {
self.shared.lock(|s| { self.shared.lock(|s| {
let s = &mut *s.borrow_mut(); let s = &mut *s.borrow_mut();
@ -98,6 +118,7 @@ impl<'d, const MTU: usize> Runner<'d, MTU> {
}); });
} }
/// Set the hardware address.
pub fn set_hardware_address(&mut self, address: driver::HardwareAddress) { pub fn set_hardware_address(&mut self, address: driver::HardwareAddress) {
self.shared.lock(|s| { self.shared.lock(|s| {
let s = &mut *s.borrow_mut(); let s = &mut *s.borrow_mut();
@ -106,16 +127,19 @@ impl<'d, const MTU: usize> Runner<'d, MTU> {
}); });
} }
/// Wait until there is space for more inbound packets and return a slice they can be copied into.
pub async fn rx_buf(&mut self) -> &mut [u8] { pub async fn rx_buf(&mut self) -> &mut [u8] {
let p = self.rx_chan.send().await; let p = self.rx_chan.send().await;
&mut p.buf &mut p.buf
} }
/// Check if there is space for more inbound packets right now.
pub fn try_rx_buf(&mut self) -> Option<&mut [u8]> { pub fn try_rx_buf(&mut self) -> Option<&mut [u8]> {
let p = self.rx_chan.try_send()?; let p = self.rx_chan.try_send()?;
Some(&mut p.buf) Some(&mut p.buf)
} }
/// Polling the inbound channel if there is space for packets.
pub fn poll_rx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> { pub fn poll_rx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> {
match self.rx_chan.poll_send(cx) { match self.rx_chan.poll_send(cx) {
Poll::Ready(p) => Poll::Ready(&mut p.buf), Poll::Ready(p) => Poll::Ready(&mut p.buf),
@ -123,22 +147,26 @@ impl<'d, const MTU: usize> Runner<'d, MTU> {
} }
} }
/// Mark packet of len bytes as pushed to the inbound channel.
pub fn rx_done(&mut self, len: usize) { pub fn rx_done(&mut self, len: usize) {
let p = self.rx_chan.try_send().unwrap(); let p = self.rx_chan.try_send().unwrap();
p.len = len; p.len = len;
self.rx_chan.send_done(); self.rx_chan.send_done();
} }
/// Wait until there is space for more outbound packets and return a slice they can be copied into.
pub async fn tx_buf(&mut self) -> &mut [u8] { pub async fn tx_buf(&mut self) -> &mut [u8] {
let p = self.tx_chan.receive().await; let p = self.tx_chan.receive().await;
&mut p.buf[..p.len] &mut p.buf[..p.len]
} }
/// Check if there is space for more outbound packets right now.
pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> { pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> {
let p = self.tx_chan.try_receive()?; let p = self.tx_chan.try_receive()?;
Some(&mut p.buf[..p.len]) Some(&mut p.buf[..p.len])
} }
/// Polling the outbound channel if there is space for packets.
pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> { pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> {
match self.tx_chan.poll_receive(cx) { match self.tx_chan.poll_receive(cx) {
Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]), Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]),
@ -146,12 +174,14 @@ impl<'d, const MTU: usize> Runner<'d, MTU> {
} }
} }
/// Mark outbound packet as copied.
pub fn tx_done(&mut self) { pub fn tx_done(&mut self) {
self.tx_chan.receive_done(); self.tx_chan.receive_done();
} }
} }
impl<'d> StateRunner<'d> { impl<'d> StateRunner<'d> {
/// Set link state.
pub fn set_link_state(&self, state: LinkState) { pub fn set_link_state(&self, state: LinkState) {
self.shared.lock(|s| { self.shared.lock(|s| {
let s = &mut *s.borrow_mut(); let s = &mut *s.borrow_mut();
@ -160,6 +190,7 @@ impl<'d> StateRunner<'d> {
}); });
} }
/// Set the hardware address.
pub fn set_hardware_address(&self, address: driver::HardwareAddress) { pub fn set_hardware_address(&self, address: driver::HardwareAddress) {
self.shared.lock(|s| { self.shared.lock(|s| {
let s = &mut *s.borrow_mut(); let s = &mut *s.borrow_mut();
@ -170,16 +201,19 @@ impl<'d> StateRunner<'d> {
} }
impl<'d, const MTU: usize> RxRunner<'d, MTU> { impl<'d, const MTU: usize> RxRunner<'d, MTU> {
/// Wait until there is space for more inbound packets and return a slice they can be copied into.
pub async fn rx_buf(&mut self) -> &mut [u8] { pub async fn rx_buf(&mut self) -> &mut [u8] {
let p = self.rx_chan.send().await; let p = self.rx_chan.send().await;
&mut p.buf &mut p.buf
} }
/// Check if there is space for more inbound packets right now.
pub fn try_rx_buf(&mut self) -> Option<&mut [u8]> { pub fn try_rx_buf(&mut self) -> Option<&mut [u8]> {
let p = self.rx_chan.try_send()?; let p = self.rx_chan.try_send()?;
Some(&mut p.buf) Some(&mut p.buf)
} }
/// Polling the inbound channel if there is space for packets.
pub fn poll_rx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> { pub fn poll_rx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> {
match self.rx_chan.poll_send(cx) { match self.rx_chan.poll_send(cx) {
Poll::Ready(p) => Poll::Ready(&mut p.buf), Poll::Ready(p) => Poll::Ready(&mut p.buf),
@ -187,6 +221,7 @@ impl<'d, const MTU: usize> RxRunner<'d, MTU> {
} }
} }
/// Mark packet of len bytes as pushed to the inbound channel.
pub fn rx_done(&mut self, len: usize) { pub fn rx_done(&mut self, len: usize) {
let p = self.rx_chan.try_send().unwrap(); let p = self.rx_chan.try_send().unwrap();
p.len = len; p.len = len;
@ -195,16 +230,19 @@ impl<'d, const MTU: usize> RxRunner<'d, MTU> {
} }
impl<'d, const MTU: usize> TxRunner<'d, MTU> { impl<'d, const MTU: usize> TxRunner<'d, MTU> {
/// Wait until there is space for more outbound packets and return a slice they can be copied into.
pub async fn tx_buf(&mut self) -> &mut [u8] { pub async fn tx_buf(&mut self) -> &mut [u8] {
let p = self.tx_chan.receive().await; let p = self.tx_chan.receive().await;
&mut p.buf[..p.len] &mut p.buf[..p.len]
} }
/// Check if there is space for more outbound packets right now.
pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> { pub fn try_tx_buf(&mut self) -> Option<&mut [u8]> {
let p = self.tx_chan.try_receive()?; let p = self.tx_chan.try_receive()?;
Some(&mut p.buf[..p.len]) Some(&mut p.buf[..p.len])
} }
/// Polling the outbound channel if there is space for packets.
pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> { pub fn poll_tx_buf(&mut self, cx: &mut Context) -> Poll<&mut [u8]> {
match self.tx_chan.poll_receive(cx) { match self.tx_chan.poll_receive(cx) {
Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]), Poll::Ready(p) => Poll::Ready(&mut p.buf[..p.len]),
@ -212,11 +250,18 @@ impl<'d, const MTU: usize> TxRunner<'d, MTU> {
} }
} }
/// Mark outbound packet as copied.
pub fn tx_done(&mut self) { pub fn tx_done(&mut self) {
self.tx_chan.receive_done(); self.tx_chan.receive_done();
} }
} }
/// Create a channel.
///
/// Returns a pair of handles for interfacing with the peripheral and the networking stack.
///
/// The runner is interfacing with the peripheral at the lower part of the stack.
/// The device is interfacing with the networking stack on the layer above.
pub fn new<'d, const MTU: usize, const N_RX: usize, const N_TX: usize>( pub fn new<'d, const MTU: usize, const N_RX: usize, const N_TX: usize>(
state: &'d mut State<MTU, N_RX, N_TX>, state: &'d mut State<MTU, N_RX, N_TX>,
hardware_address: driver::HardwareAddress, hardware_address: driver::HardwareAddress,
@ -257,17 +302,22 @@ pub fn new<'d, const MTU: usize, const N_RX: usize, const N_TX: usize>(
) )
} }
/// Represents a packet of size MTU.
pub struct PacketBuf<const MTU: usize> { pub struct PacketBuf<const MTU: usize> {
len: usize, len: usize,
buf: [u8; MTU], buf: [u8; MTU],
} }
impl<const MTU: usize> PacketBuf<MTU> { impl<const MTU: usize> PacketBuf<MTU> {
/// Create a new packet buffer.
pub const fn new() -> Self { pub const fn new() -> Self {
Self { len: 0, buf: [0; MTU] } Self { len: 0, buf: [0; MTU] }
} }
} }
/// Channel device.
///
/// Holds the shared state and upper end of channels for inbound and outbound packets.
pub struct Device<'d, const MTU: usize> { pub struct Device<'d, const MTU: usize> {
rx: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>, rx: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>,
tx: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>, tx: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>,
@ -314,6 +364,9 @@ impl<'d, const MTU: usize> embassy_net_driver::Driver for Device<'d, MTU> {
} }
} }
/// A rx token.
///
/// Holds inbound receive channel and interfaces with embassy-net-driver.
pub struct RxToken<'a, const MTU: usize> { pub struct RxToken<'a, const MTU: usize> {
rx: zerocopy_channel::Receiver<'a, NoopRawMutex, PacketBuf<MTU>>, rx: zerocopy_channel::Receiver<'a, NoopRawMutex, PacketBuf<MTU>>,
} }
@ -331,6 +384,9 @@ impl<'a, const MTU: usize> embassy_net_driver::RxToken for RxToken<'a, MTU> {
} }
} }
/// A tx token.
///
/// Holds outbound transmit channel and interfaces with embassy-net-driver.
pub struct TxToken<'a, const MTU: usize> { pub struct TxToken<'a, const MTU: usize> {
tx: zerocopy_channel::Sender<'a, NoopRawMutex, PacketBuf<MTU>>, tx: zerocopy_channel::Sender<'a, NoopRawMutex, PacketBuf<MTU>>,
} }

View File

@ -2,6 +2,10 @@
name = "embassy-net-esp-hosted" name = "embassy-net-esp-hosted"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
description = "embassy-net driver for ESP-Hosted"
keywords = ["embedded", "esp-hosted", "embassy-net", "embedded-hal-async", "wifi", "async"]
categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"]
license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
defmt = { version = "0.3", optional = true } defmt = { version = "0.3", optional = true }
@ -15,8 +19,7 @@ embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-
embedded-hal = { version = "1.0.0-rc.3" } embedded-hal = { version = "1.0.0-rc.3" }
embedded-hal-async = { version = "=1.0.0-rc.3" } embedded-hal-async = { version = "=1.0.0-rc.3" }
noproto = { git="https://github.com/embassy-rs/noproto", rev = "f5e6d1f325b6ad4e344f60452b09576e24671f62", default-features = false, features = ["derive"] } noproto = "0.1.0"
#noproto = { version = "0.1", path = "/home/dirbaio/noproto", default-features = false, features = ["derive"] }
heapless = "0.8" heapless = "0.8"
[package.metadata.embassy_docs] [package.metadata.embassy_docs]

View File

@ -0,0 +1,27 @@
# ESP-Hosted `embassy-net` integration
[`embassy-net`](https://crates.io/crates/embassy-net) integration for Espressif SoCs running the the ESP-Hosted stack.
See [`examples`](https://github.com/embassy-rs/embassy/tree/main/examples/nrf52840) directory for usage examples with the nRF52840.
## Supported chips
- W5500
- W5100S
## Interoperability
This crate can run on any executor.
It supports any SPI driver implementing [`embedded-hal-async`](https://crates.io/crates/embedded-hal-async).
## License
This work is licensed under either of
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.

View File

@ -5,38 +5,54 @@ use heapless::String;
use crate::ioctl::Shared; use crate::ioctl::Shared;
use crate::proto::{self, CtrlMsg}; use crate::proto::{self, CtrlMsg};
/// Errors reported by control.
#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error { pub enum Error {
/// The operation failed with the given error code.
Failed(u32), Failed(u32),
/// The operation timed out.
Timeout, Timeout,
/// Internal error.
Internal, Internal,
} }
/// Handle for managing the network and WiFI state.
pub struct Control<'a> { pub struct Control<'a> {
state_ch: ch::StateRunner<'a>, state_ch: ch::StateRunner<'a>,
shared: &'a Shared, shared: &'a Shared,
} }
/// WiFi mode.
#[allow(unused)] #[allow(unused)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
enum WifiMode { enum WifiMode {
/// No mode.
None = 0, None = 0,
/// Client station.
Sta = 1, Sta = 1,
/// Access point mode.
Ap = 2, Ap = 2,
/// Repeater mode.
ApSta = 3, ApSta = 3,
} }
pub use proto::CtrlWifiSecProt as Security; pub use proto::CtrlWifiSecProt as Security;
/// WiFi status.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Status { pub struct Status {
/// Service Set Identifier.
pub ssid: String<32>, pub ssid: String<32>,
/// Basic Service Set Identifier.
pub bssid: [u8; 6], pub bssid: [u8; 6],
/// Received Signal Strength Indicator.
pub rssi: i32, pub rssi: i32,
/// WiFi channel.
pub channel: u32, pub channel: u32,
/// Security mode.
pub security: Security, pub security: Security,
} }
@ -65,6 +81,7 @@ impl<'a> Control<'a> {
Self { state_ch, shared } Self { state_ch, shared }
} }
/// Initialize device.
pub async fn init(&mut self) -> Result<(), Error> { pub async fn init(&mut self) -> Result<(), Error> {
debug!("wait for init event..."); debug!("wait for init event...");
self.shared.init_wait().await; self.shared.init_wait().await;
@ -82,6 +99,7 @@ impl<'a> Control<'a> {
Ok(()) Ok(())
} }
/// Get the current status.
pub async fn get_status(&mut self) -> Result<Status, Error> { pub async fn get_status(&mut self) -> Result<Status, Error> {
let req = proto::CtrlMsgReqGetApConfig {}; let req = proto::CtrlMsgReqGetApConfig {};
ioctl!(self, ReqGetApConfig, RespGetApConfig, req, resp); ioctl!(self, ReqGetApConfig, RespGetApConfig, req, resp);
@ -95,6 +113,7 @@ impl<'a> Control<'a> {
}) })
} }
/// Connect to the network identified by ssid using the provided password.
pub async fn connect(&mut self, ssid: &str, password: &str) -> Result<(), Error> { pub async fn connect(&mut self, ssid: &str, password: &str) -> Result<(), Error> {
let req = proto::CtrlMsgReqConnectAp { let req = proto::CtrlMsgReqConnectAp {
ssid: unwrap!(String::try_from(ssid)), ssid: unwrap!(String::try_from(ssid)),
@ -108,6 +127,7 @@ impl<'a> Control<'a> {
Ok(()) Ok(())
} }
/// Disconnect from any currently connected network.
pub async fn disconnect(&mut self) -> Result<(), Error> { pub async fn disconnect(&mut self) -> Result<(), Error> {
let req = proto::CtrlMsgReqGetStatus {}; let req = proto::CtrlMsgReqGetStatus {};
ioctl!(self, ReqDisconnectAp, RespDisconnectAp, req, resp); ioctl!(self, ReqDisconnectAp, RespDisconnectAp, req, resp);

View File

@ -1,4 +1,6 @@
#![no_std] #![no_std]
#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
use embassy_futures::select::{select4, Either4}; use embassy_futures::select::{select4, Either4};
use embassy_net_driver_channel as ch; use embassy_net_driver_channel as ch;
@ -97,12 +99,14 @@ enum InterfaceType {
const MAX_SPI_BUFFER_SIZE: usize = 1600; const MAX_SPI_BUFFER_SIZE: usize = 1600;
const HEARTBEAT_MAX_GAP: Duration = Duration::from_secs(20); const HEARTBEAT_MAX_GAP: Duration = Duration::from_secs(20);
/// State for the esp-hosted driver.
pub struct State { pub struct State {
shared: Shared, shared: Shared,
ch: ch::State<MTU, 4, 4>, ch: ch::State<MTU, 4, 4>,
} }
impl State { impl State {
/// Create a new state.
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
shared: Shared::new(), shared: Shared::new(),
@ -111,8 +115,13 @@ impl State {
} }
} }
/// Type alias for network driver.
pub type NetDriver<'a> = ch::Device<'a, MTU>; pub type NetDriver<'a> = ch::Device<'a, MTU>;
/// Create a new esp-hosted driver using the provided state, SPI peripheral and pins.
///
/// Returns a device handle for interfacing with embassy-net, a control handle for
/// interacting with the driver, and a runner for communicating with the WiFi device.
pub async fn new<'a, SPI, IN, OUT>( pub async fn new<'a, SPI, IN, OUT>(
state: &'a mut State, state: &'a mut State,
spi: SPI, spi: SPI,
@ -144,6 +153,7 @@ where
(device, Control::new(state_ch, &state.shared), runner) (device, Control::new(state_ch, &state.shared), runner)
} }
/// Runner for communicating with the WiFi device.
pub struct Runner<'a, SPI, IN, OUT> { pub struct Runner<'a, SPI, IN, OUT> {
ch: ch::Runner<'a, MTU>, ch: ch::Runner<'a, MTU>,
state_ch: ch::StateRunner<'a>, state_ch: ch::StateRunner<'a>,
@ -166,6 +176,7 @@ where
{ {
async fn init(&mut self) {} async fn init(&mut self) {}
/// Run the packet processing.
pub async fn run(mut self) -> ! { pub async fn run(mut self) -> ! {
debug!("resetting..."); debug!("resetting...");
self.reset.set_low().unwrap(); self.reset.set_low().unwrap();

View File

@ -4,7 +4,7 @@ use heapless::{String, Vec};
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ScanResult { pub(crate) struct ScanResult {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub ssid: String<32>, pub ssid: String<32>,
#[noproto(tag = "2")] #[noproto(tag = "2")]
@ -19,7 +19,7 @@ pub struct ScanResult {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ConnectedStaList { pub(crate) struct ConnectedStaList {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub mac: String<32>, pub mac: String<32>,
#[noproto(tag = "2")] #[noproto(tag = "2")]
@ -29,14 +29,14 @@ pub struct ConnectedStaList {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqGetMacAddress { pub(crate) struct CtrlMsgReqGetMacAddress {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub mode: u32, pub mode: u32,
} }
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespGetMacAddress { pub(crate) struct CtrlMsgRespGetMacAddress {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub mac: String<32>, pub mac: String<32>,
#[noproto(tag = "2")] #[noproto(tag = "2")]
@ -45,11 +45,11 @@ pub struct CtrlMsgRespGetMacAddress {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqGetMode {} pub(crate) struct CtrlMsgReqGetMode {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespGetMode { pub(crate) struct CtrlMsgRespGetMode {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub mode: u32, pub mode: u32,
#[noproto(tag = "2")] #[noproto(tag = "2")]
@ -58,32 +58,32 @@ pub struct CtrlMsgRespGetMode {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqSetMode { pub(crate) struct CtrlMsgReqSetMode {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub mode: u32, pub mode: u32,
} }
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespSetMode { pub(crate) struct CtrlMsgRespSetMode {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub resp: u32, pub resp: u32,
} }
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqGetStatus {} pub(crate) struct CtrlMsgReqGetStatus {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespGetStatus { pub(crate) struct CtrlMsgRespGetStatus {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub resp: u32, pub resp: u32,
} }
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqSetMacAddress { pub(crate) struct CtrlMsgReqSetMacAddress {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub mac: String<32>, pub mac: String<32>,
#[noproto(tag = "2")] #[noproto(tag = "2")]
@ -92,18 +92,18 @@ pub struct CtrlMsgReqSetMacAddress {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespSetMacAddress { pub(crate) struct CtrlMsgRespSetMacAddress {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub resp: u32, pub resp: u32,
} }
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqGetApConfig {} pub(crate) struct CtrlMsgReqGetApConfig {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespGetApConfig { pub(crate) struct CtrlMsgRespGetApConfig {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub ssid: String<32>, pub ssid: String<32>,
#[noproto(tag = "2")] #[noproto(tag = "2")]
@ -120,7 +120,7 @@ pub struct CtrlMsgRespGetApConfig {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqConnectAp { pub(crate) struct CtrlMsgReqConnectAp {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub ssid: String<32>, pub ssid: String<32>,
#[noproto(tag = "2")] #[noproto(tag = "2")]
@ -135,7 +135,7 @@ pub struct CtrlMsgReqConnectAp {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespConnectAp { pub(crate) struct CtrlMsgRespConnectAp {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub resp: u32, pub resp: u32,
#[noproto(tag = "2")] #[noproto(tag = "2")]
@ -144,11 +144,11 @@ pub struct CtrlMsgRespConnectAp {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqGetSoftApConfig {} pub(crate) struct CtrlMsgReqGetSoftApConfig {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespGetSoftApConfig { pub(crate) struct CtrlMsgRespGetSoftApConfig {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub ssid: String<32>, pub ssid: String<32>,
#[noproto(tag = "2")] #[noproto(tag = "2")]
@ -169,7 +169,7 @@ pub struct CtrlMsgRespGetSoftApConfig {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqStartSoftAp { pub(crate) struct CtrlMsgReqStartSoftAp {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub ssid: String<32>, pub ssid: String<32>,
#[noproto(tag = "2")] #[noproto(tag = "2")]
@ -188,7 +188,7 @@ pub struct CtrlMsgReqStartSoftAp {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespStartSoftAp { pub(crate) struct CtrlMsgRespStartSoftAp {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub resp: u32, pub resp: u32,
#[noproto(tag = "2")] #[noproto(tag = "2")]
@ -197,11 +197,11 @@ pub struct CtrlMsgRespStartSoftAp {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqScanResult {} pub(crate) struct CtrlMsgReqScanResult {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespScanResult { pub(crate) struct CtrlMsgRespScanResult {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub count: u32, pub count: u32,
#[noproto(repeated, tag = "2")] #[noproto(repeated, tag = "2")]
@ -212,11 +212,11 @@ pub struct CtrlMsgRespScanResult {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqSoftApConnectedSta {} pub(crate) struct CtrlMsgReqSoftApConnectedSta {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespSoftApConnectedSta { pub(crate) struct CtrlMsgRespSoftApConnectedSta {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub num: u32, pub num: u32,
#[noproto(repeated, tag = "2")] #[noproto(repeated, tag = "2")]
@ -227,43 +227,43 @@ pub struct CtrlMsgRespSoftApConnectedSta {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqOtaBegin {} pub(crate) struct CtrlMsgReqOtaBegin {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespOtaBegin { pub(crate) struct CtrlMsgRespOtaBegin {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub resp: u32, pub resp: u32,
} }
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqOtaWrite { pub(crate) struct CtrlMsgReqOtaWrite {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub ota_data: Vec<u8, 1024>, pub ota_data: Vec<u8, 1024>,
} }
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespOtaWrite { pub(crate) struct CtrlMsgRespOtaWrite {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub resp: u32, pub resp: u32,
} }
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqOtaEnd {} pub(crate) struct CtrlMsgReqOtaEnd {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespOtaEnd { pub(crate) struct CtrlMsgRespOtaEnd {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub resp: u32, pub resp: u32,
} }
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqVendorIeData { pub(crate) struct CtrlMsgReqVendorIeData {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub element_id: u32, pub element_id: u32,
#[noproto(tag = "2")] #[noproto(tag = "2")]
@ -278,7 +278,7 @@ pub struct CtrlMsgReqVendorIeData {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqSetSoftApVendorSpecificIe { pub(crate) struct CtrlMsgReqSetSoftApVendorSpecificIe {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub enable: bool, pub enable: bool,
#[noproto(tag = "2")] #[noproto(tag = "2")]
@ -291,32 +291,32 @@ pub struct CtrlMsgReqSetSoftApVendorSpecificIe {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespSetSoftApVendorSpecificIe { pub(crate) struct CtrlMsgRespSetSoftApVendorSpecificIe {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub resp: u32, pub resp: u32,
} }
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqSetWifiMaxTxPower { pub(crate) struct CtrlMsgReqSetWifiMaxTxPower {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub wifi_max_tx_power: u32, pub wifi_max_tx_power: u32,
} }
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespSetWifiMaxTxPower { pub(crate) struct CtrlMsgRespSetWifiMaxTxPower {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub resp: u32, pub resp: u32,
} }
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqGetWifiCurrTxPower {} pub(crate) struct CtrlMsgReqGetWifiCurrTxPower {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespGetWifiCurrTxPower { pub(crate) struct CtrlMsgRespGetWifiCurrTxPower {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub wifi_curr_tx_power: u32, pub wifi_curr_tx_power: u32,
#[noproto(tag = "2")] #[noproto(tag = "2")]
@ -325,7 +325,7 @@ pub struct CtrlMsgRespGetWifiCurrTxPower {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqConfigHeartbeat { pub(crate) struct CtrlMsgReqConfigHeartbeat {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub enable: bool, pub enable: bool,
#[noproto(tag = "2")] #[noproto(tag = "2")]
@ -334,7 +334,7 @@ pub struct CtrlMsgReqConfigHeartbeat {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespConfigHeartbeat { pub(crate) struct CtrlMsgRespConfigHeartbeat {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub resp: u32, pub resp: u32,
} }
@ -342,28 +342,28 @@ pub struct CtrlMsgRespConfigHeartbeat {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgEventEspInit { pub(crate) struct CtrlMsgEventEspInit {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub init_data: Vec<u8, 64>, pub init_data: Vec<u8, 64>,
} }
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgEventHeartbeat { pub(crate) struct CtrlMsgEventHeartbeat {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub hb_num: u32, pub hb_num: u32,
} }
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgEventStationDisconnectFromAp { pub(crate) struct CtrlMsgEventStationDisconnectFromAp {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub resp: u32, pub resp: u32,
} }
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgEventStationDisconnectFromEspSoftAp { pub(crate) struct CtrlMsgEventStationDisconnectFromEspSoftAp {
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub resp: u32, pub resp: u32,
#[noproto(tag = "2")] #[noproto(tag = "2")]
@ -372,7 +372,7 @@ pub struct CtrlMsgEventStationDisconnectFromEspSoftAp {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsg { pub(crate) struct CtrlMsg {
/// msg_type could be req, resp or Event /// msg_type could be req, resp or Event
#[noproto(tag = "1")] #[noproto(tag = "1")]
pub msg_type: CtrlMsgType, pub msg_type: CtrlMsgType,
@ -390,7 +390,7 @@ pub struct CtrlMsg {
/// union of all msg ids /// union of all msg ids
#[derive(Debug, Clone, Eq, PartialEq, noproto::Oneof)] #[derive(Debug, Clone, Eq, PartialEq, noproto::Oneof)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlMsgPayload { pub(crate) enum CtrlMsgPayload {
/// * Requests * /// * Requests *
#[noproto(tag = "101")] #[noproto(tag = "101")]
ReqGetMacAddress(CtrlMsgReqGetMacAddress), ReqGetMacAddress(CtrlMsgReqGetMacAddress),
@ -492,7 +492,7 @@ pub enum CtrlMsgPayload {
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)] #[repr(u32)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlVendorIeType { pub(crate) enum CtrlVendorIeType {
#[default] #[default]
Beacon = 0, Beacon = 0,
ProbeReq = 1, ProbeReq = 1,
@ -504,7 +504,7 @@ pub enum CtrlVendorIeType {
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)] #[repr(u32)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlVendorIeid { pub(crate) enum CtrlVendorIeid {
#[default] #[default]
Id0 = 0, Id0 = 0,
Id1 = 1, Id1 = 1,
@ -513,7 +513,7 @@ pub enum CtrlVendorIeid {
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)] #[repr(u32)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlWifiMode { pub(crate) enum CtrlWifiMode {
#[default] #[default]
None = 0, None = 0,
Sta = 1, Sta = 1,
@ -524,7 +524,7 @@ pub enum CtrlWifiMode {
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)] #[repr(u32)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlWifiBw { pub(crate) enum CtrlWifiBw {
#[default] #[default]
BwInvalid = 0, BwInvalid = 0,
Ht20 = 1, Ht20 = 1,
@ -534,13 +534,15 @@ pub enum CtrlWifiBw {
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)] #[repr(u32)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlWifiPowerSave { pub(crate) enum CtrlWifiPowerSave {
#[default] #[default]
PsInvalid = 0, PsInvalid = 0,
MinModem = 1, MinModem = 1,
MaxModem = 2, MaxModem = 2,
} }
/// Wifi Security Settings
#[allow(missing_docs)]
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)] #[repr(u32)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
@ -560,7 +562,7 @@ pub enum CtrlWifiSecProt {
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)] #[repr(u32)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlStatus { pub(crate) enum CtrlStatus {
#[default] #[default]
Connected = 0, Connected = 0,
NotConnected = 1, NotConnected = 1,
@ -573,7 +575,7 @@ pub enum CtrlStatus {
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)] #[repr(u32)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlMsgType { pub(crate) enum CtrlMsgType {
#[default] #[default]
MsgTypeInvalid = 0, MsgTypeInvalid = 0,
Req = 1, Req = 1,
@ -585,7 +587,7 @@ pub enum CtrlMsgType {
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)] #[repr(u32)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlMsgId { pub(crate) enum CtrlMsgId {
#[default] #[default]
MsgIdInvalid = 0, MsgIdInvalid = 0,
/// * Request Msgs * /// * Request Msgs *

View File

@ -6,6 +6,7 @@ keywords = ["embedded", "tuntap", "embassy-net", "embedded-hal-async", "ethernet
categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
edition = "2021" edition = "2021"
repository = "https://github.com/embassy-rs/embassy"
[dependencies] [dependencies]
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" } embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
@ -16,4 +17,4 @@ libc = "0.2.101"
[package.metadata.embassy_docs] [package.metadata.embassy_docs]
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-tuntap-v$VERSION/embassy-net-tuntap/src/" src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-tuntap-v$VERSION/embassy-net-tuntap/src/"
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-tuntap/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-tuntap/src/"
target = "thumbv7em-none-eabi" target = "thumbv7em-none-eabi"

View File

@ -1,3 +1,5 @@
#![warn(missing_docs)]
#![doc = include_str!("../README.md")]
use std::io; use std::io;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, RawFd};
@ -7,12 +9,19 @@ use async_io::Async;
use embassy_net_driver::{self, Capabilities, Driver, HardwareAddress, LinkState}; use embassy_net_driver::{self, Capabilities, Driver, HardwareAddress, LinkState};
use log::*; use log::*;
/// Get the MTU of the given interface.
pub const SIOCGIFMTU: libc::c_ulong = 0x8921; pub const SIOCGIFMTU: libc::c_ulong = 0x8921;
/// Get the index of the given interface.
pub const _SIOCGIFINDEX: libc::c_ulong = 0x8933; pub const _SIOCGIFINDEX: libc::c_ulong = 0x8933;
/// Capture all packages.
pub const _ETH_P_ALL: libc::c_short = 0x0003; pub const _ETH_P_ALL: libc::c_short = 0x0003;
/// Set the interface flags.
pub const TUNSETIFF: libc::c_ulong = 0x400454CA; pub const TUNSETIFF: libc::c_ulong = 0x400454CA;
/// TUN device.
pub const _IFF_TUN: libc::c_int = 0x0001; pub const _IFF_TUN: libc::c_int = 0x0001;
/// TAP device.
pub const IFF_TAP: libc::c_int = 0x0002; pub const IFF_TAP: libc::c_int = 0x0002;
/// No packet information.
pub const IFF_NO_PI: libc::c_int = 0x1000; pub const IFF_NO_PI: libc::c_int = 0x1000;
const ETHERNET_HEADER_LEN: usize = 14; const ETHERNET_HEADER_LEN: usize = 14;
@ -47,6 +56,7 @@ fn ifreq_ioctl(lower: libc::c_int, ifreq: &mut ifreq, cmd: libc::c_ulong) -> io:
Ok(ifreq.ifr_data) Ok(ifreq.ifr_data)
} }
/// A TUN/TAP device.
#[derive(Debug)] #[derive(Debug)]
pub struct TunTap { pub struct TunTap {
fd: libc::c_int, fd: libc::c_int,
@ -60,6 +70,7 @@ impl AsRawFd for TunTap {
} }
impl TunTap { impl TunTap {
/// Create a new TUN/TAP device.
pub fn new(name: &str) -> io::Result<TunTap> { pub fn new(name: &str) -> io::Result<TunTap> {
unsafe { unsafe {
let fd = libc::open( let fd = libc::open(
@ -126,11 +137,13 @@ impl io::Write for TunTap {
} }
} }
/// A TUN/TAP device, wrapped in an async interface.
pub struct TunTapDevice { pub struct TunTapDevice {
device: Async<TunTap>, device: Async<TunTap>,
} }
impl TunTapDevice { impl TunTapDevice {
/// Create a new TUN/TAP device.
pub fn new(name: &str) -> io::Result<TunTapDevice> { pub fn new(name: &str) -> io::Result<TunTapDevice> {
Ok(Self { Ok(Self {
device: Async::new(TunTap::new(name)?)?, device: Async::new(TunTap::new(name)?)?,

View File

@ -6,6 +6,7 @@ keywords = ["embedded", "wiznet", "embassy-net", "embedded-hal-async", "ethernet
categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"] categories = ["embedded", "hardware-support", "no-std", "network-programming", "async"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
edition = "2021" edition = "2021"
repository = "https://github.com/embassy-rs/embassy"
[dependencies] [dependencies]
embedded-hal = { version = "1.0.0-rc.3" } embedded-hal = { version = "1.0.0-rc.3" }

View File

@ -1,3 +1,4 @@
//! Wiznet W5100s and W5500 family driver.
mod w5500; mod w5500;
pub use w5500::W5500; pub use w5500::W5500;
mod w5100s; mod w5100s;
@ -45,4 +46,5 @@ pub(crate) mod sealed {
} }
} }
/// Trait for Wiznet chips.
pub trait Chip: sealed::Chip {} pub trait Chip: sealed::Chip {}

View File

@ -4,6 +4,7 @@ const SOCKET_BASE: u16 = 0x400;
const TX_BASE: u16 = 0x4000; const TX_BASE: u16 = 0x4000;
const RX_BASE: u16 = 0x6000; const RX_BASE: u16 = 0x6000;
/// Wizard W5100S chip.
pub enum W5100S {} pub enum W5100S {}
impl super::Chip for W5100S {} impl super::Chip for W5100S {}

View File

@ -8,6 +8,7 @@ pub enum RegisterBlock {
RxBuf = 0x03, RxBuf = 0x03,
} }
/// Wiznet W5500 chip.
pub enum W5500 {} pub enum W5500 {}
impl super::Chip for W5500 {} impl super::Chip for W5500 {}

View File

@ -1,6 +1,7 @@
#![no_std] #![no_std]
#![allow(async_fn_in_trait)] #![allow(async_fn_in_trait)]
#![doc = include_str!("../README.md")] #![doc = include_str!("../README.md")]
#![warn(missing_docs)]
pub mod chip; pub mod chip;
mod device; mod device;
@ -47,6 +48,7 @@ pub struct Runner<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> {
/// You must call this in a background task for the driver to operate. /// You must call this in a background task for the driver to operate.
impl<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, C, SPI, INT, RST> { impl<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, C, SPI, INT, RST> {
/// Run the driver.
pub async fn run(mut self) -> ! { pub async fn run(mut self) -> ! {
let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split(); let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split();
let mut tick = Ticker::every(Duration::from_millis(500)); let mut tick = Ticker::every(Duration::from_millis(500));

View File

@ -411,10 +411,12 @@ impl<D: Driver> Stack<D> {
/// ```ignore /// ```ignore
/// let config = embassy_net::Config::dhcpv4(Default::default()); /// let config = embassy_net::Config::dhcpv4(Default::default());
///// Init network stack ///// Init network stack
/// let stack = &*make_static!(embassy_net::Stack::new( /// static RESOURCES: StaticCell<embassy_net::StackResources<2> = StaticCell::new();
/// static STACK: StaticCell<embassy_net::Stack> = StaticCell::new();
/// let stack = &*STACK.init(embassy_net::Stack::new(
/// device, /// device,
/// config, /// config,
/// make_static!(embassy_net::StackResources::<2>::new()), /// RESOURCES.init(embassy_net::StackResources::new()),
/// seed /// seed
/// )); /// ));
/// // Launch network task that runs `stack.run().await` /// // Launch network task that runs `stack.run().await`

View File

@ -87,5 +87,5 @@ pio = {version= "0.2.1" }
rp2040-boot2 = "0.3" rp2040-boot2 = "0.3"
[dev-dependencies] [dev-dependencies]
embassy-executor = { version = "0.4.0", path = "../embassy-executor", features = ["nightly", "arch-std", "executor-thread"] } embassy-executor = { version = "0.4.0", path = "../embassy-executor", features = ["arch-std", "executor-thread"] }
static_cell = { version = "2" } static_cell = { version = "2" }

View File

@ -247,7 +247,6 @@ select_bootloader! {
/// # Usage /// # Usage
/// ///
/// ```no_run /// ```no_run
/// #![feature(type_alias_impl_trait)]
/// use embassy_rp::install_core0_stack_guard; /// use embassy_rp::install_core0_stack_guard;
/// use embassy_executor::{Executor, Spawner}; /// use embassy_executor::{Executor, Spawner};
/// ///

View File

@ -11,7 +11,6 @@
//! # Usage //! # Usage
//! //!
//! ```no_run //! ```no_run
//! # #![feature(type_alias_impl_trait)]
//! use embassy_rp::multicore::Stack; //! use embassy_rp::multicore::Stack;
//! use static_cell::StaticCell; //! use static_cell::StaticCell;
//! use embassy_executor::Executor; //! use embassy_executor::Executor;

View File

@ -26,7 +26,7 @@ aligned = "0.4.1"
bit_field = "0.10.2" bit_field = "0.10.2"
stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] } stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] }
stm32wb-hci = { version = "0.1.4", optional = true } stm32wb-hci = { git = "https://github.com/Dirbaio/stm32wb-hci", rev = "0aff47e009c30c5fc5d520672625173d75f7505c", optional = true }
futures = { version = "0.3.17", default-features = false, features = ["async-await"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
bitflags = { version = "2.3.3", optional = true } bitflags = { version = "2.3.3", optional = true }

View File

@ -56,9 +56,8 @@ cortex-m = "0.7.6"
futures = { version = "0.3.17", default-features = false, features = ["async-await"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
rand_core = "0.6.3" rand_core = "0.6.3"
sdio-host = "0.5.0" sdio-host = "0.5.0"
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
critical-section = "1.1" critical-section = "1.1"
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-91cee0d1fdcb4e447b65a09756b506f4af91b7e2" } stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2234f380f51d16d0398b8e547088b33ea623cc7c" }
vcell = "0.1.3" vcell = "0.1.3"
bxcan = "0.7.0" bxcan = "0.7.0"
nb = "1.0.0" nb = "1.0.0"
@ -76,7 +75,7 @@ critical-section = { version = "1.1", features = ["std"] }
[build-dependencies] [build-dependencies]
proc-macro2 = "1.0.36" proc-macro2 = "1.0.36"
quote = "1.0.15" quote = "1.0.15"
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-91cee0d1fdcb4e447b65a09756b506f4af91b7e2", default-features = false, features = ["metadata"]} stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2234f380f51d16d0398b8e547088b33ea623cc7c", default-features = false, features = ["metadata"]}
[features] [features]

View File

@ -23,6 +23,10 @@ use crate::pac::bdma::{regs, vals};
#[non_exhaustive] #[non_exhaustive]
pub struct TransferOptions { pub struct TransferOptions {
/// Enable circular DMA /// Enable circular DMA
///
/// Note:
/// If you enable circular mode manually, you may want to build and `.await` the `Transfer` in a separate task.
/// Since DMA in circular mode need manually stop, `.await` in current task would block the task forever.
pub circular: bool, pub circular: bool,
/// Enable half transfer interrupt /// Enable half transfer interrupt
pub half_transfer_ir: bool, pub half_transfer_ir: bool,
@ -303,20 +307,14 @@ impl<'a, C: Channel> Transfer<'a, C> {
ch.cr().write(|w| { ch.cr().write(|w| {
w.set_psize(data_size.into()); w.set_psize(data_size.into());
w.set_msize(data_size.into()); w.set_msize(data_size.into());
if incr_mem { w.set_minc(incr_mem);
w.set_minc(vals::Inc::ENABLED);
} else {
w.set_minc(vals::Inc::DISABLED);
}
w.set_dir(dir.into()); w.set_dir(dir.into());
w.set_teie(true); w.set_teie(true);
w.set_tcie(options.complete_transfer_ir); w.set_tcie(options.complete_transfer_ir);
w.set_htie(options.half_transfer_ir); w.set_htie(options.half_transfer_ir);
w.set_circ(options.circular);
if options.circular { if options.circular {
w.set_circ(vals::Circ::ENABLED);
debug!("Setting circular mode"); debug!("Setting circular mode");
} else {
w.set_circ(vals::Circ::DISABLED);
} }
w.set_pl(vals::Pl::VERYHIGH); w.set_pl(vals::Pl::VERYHIGH);
w.set_en(true); w.set_en(true);
@ -352,7 +350,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
pub fn is_running(&mut self) -> bool { pub fn is_running(&mut self) -> bool {
let ch = self.channel.regs().ch(self.channel.num()); let ch = self.channel.regs().ch(self.channel.num());
let en = ch.cr().read().en(); let en = ch.cr().read().en();
let circular = ch.cr().read().circ() == vals::Circ::ENABLED; let circular = ch.cr().read().circ();
let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0; let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0;
en && (circular || !tcif) en && (circular || !tcif)
} }
@ -467,12 +465,12 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
let mut w = regs::Cr(0); let mut w = regs::Cr(0);
w.set_psize(data_size.into()); w.set_psize(data_size.into());
w.set_msize(data_size.into()); w.set_msize(data_size.into());
w.set_minc(vals::Inc::ENABLED); w.set_minc(true);
w.set_dir(dir.into()); w.set_dir(dir.into());
w.set_teie(true); w.set_teie(true);
w.set_htie(true); w.set_htie(true);
w.set_tcie(true); w.set_tcie(true);
w.set_circ(vals::Circ::ENABLED); w.set_circ(true);
w.set_pl(vals::Pl::VERYHIGH); w.set_pl(vals::Pl::VERYHIGH);
w.set_en(true); w.set_en(true);
@ -625,12 +623,12 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
let mut w = regs::Cr(0); let mut w = regs::Cr(0);
w.set_psize(data_size.into()); w.set_psize(data_size.into());
w.set_msize(data_size.into()); w.set_msize(data_size.into());
w.set_minc(vals::Inc::ENABLED); w.set_minc(true);
w.set_dir(dir.into()); w.set_dir(dir.into());
w.set_teie(true); w.set_teie(true);
w.set_htie(true); w.set_htie(true);
w.set_tcie(true); w.set_tcie(true);
w.set_circ(vals::Circ::ENABLED); w.set_circ(true);
w.set_pl(vals::Pl::VERYHIGH); w.set_pl(vals::Pl::VERYHIGH);
w.set_en(true); w.set_en(true);

View File

@ -30,6 +30,10 @@ pub struct TransferOptions {
/// FIFO threshold for DMA FIFO mode. If none, direct mode is used. /// FIFO threshold for DMA FIFO mode. If none, direct mode is used.
pub fifo_threshold: Option<FifoThreshold>, pub fifo_threshold: Option<FifoThreshold>,
/// Enable circular DMA /// Enable circular DMA
///
/// Note:
/// If you enable circular mode manually, you may want to build and `.await` the `Transfer` in a separate task.
/// Since DMA in circular mode need manually stop, `.await` in current task would block the task forever.
pub circular: bool, pub circular: bool,
/// Enable half transfer interrupt /// Enable half transfer interrupt
pub half_transfer_ir: bool, pub half_transfer_ir: bool,
@ -382,18 +386,13 @@ impl<'a, C: Channel> Transfer<'a, C> {
w.set_msize(data_size.into()); w.set_msize(data_size.into());
w.set_psize(data_size.into()); w.set_psize(data_size.into());
w.set_pl(vals::Pl::VERYHIGH); w.set_pl(vals::Pl::VERYHIGH);
w.set_minc(match incr_mem { w.set_minc(incr_mem);
true => vals::Inc::INCREMENTED, w.set_pinc(false);
false => vals::Inc::FIXED,
});
w.set_pinc(vals::Inc::FIXED);
w.set_teie(true); w.set_teie(true);
w.set_tcie(options.complete_transfer_ir); w.set_tcie(options.complete_transfer_ir);
w.set_circ(options.circular);
if options.circular { if options.circular {
w.set_circ(vals::Circ::ENABLED);
debug!("Setting circular mode"); debug!("Setting circular mode");
} else {
w.set_circ(vals::Circ::DISABLED);
} }
#[cfg(dma_v1)] #[cfg(dma_v1)]
w.set_trbuff(true); w.set_trbuff(true);
@ -545,8 +544,8 @@ impl<'a, C: Channel, W: Word> DoubleBuffered<'a, C, W> {
w.set_msize(data_size.into()); w.set_msize(data_size.into());
w.set_psize(data_size.into()); w.set_psize(data_size.into());
w.set_pl(vals::Pl::VERYHIGH); w.set_pl(vals::Pl::VERYHIGH);
w.set_minc(vals::Inc::INCREMENTED); w.set_minc(true);
w.set_pinc(vals::Inc::FIXED); w.set_pinc(false);
w.set_teie(true); w.set_teie(true);
w.set_tcie(true); w.set_tcie(true);
#[cfg(dma_v1)] #[cfg(dma_v1)]
@ -703,12 +702,12 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
w.set_msize(data_size.into()); w.set_msize(data_size.into());
w.set_psize(data_size.into()); w.set_psize(data_size.into());
w.set_pl(vals::Pl::VERYHIGH); w.set_pl(vals::Pl::VERYHIGH);
w.set_minc(vals::Inc::INCREMENTED); w.set_minc(true);
w.set_pinc(vals::Inc::FIXED); w.set_pinc(false);
w.set_teie(true); w.set_teie(true);
w.set_htie(options.half_transfer_ir); w.set_htie(options.half_transfer_ir);
w.set_tcie(true); w.set_tcie(true);
w.set_circ(vals::Circ::ENABLED); w.set_circ(true);
#[cfg(dma_v1)] #[cfg(dma_v1)]
w.set_trbuff(true); w.set_trbuff(true);
#[cfg(dma_v2)] #[cfg(dma_v2)]
@ -878,12 +877,12 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
w.set_msize(data_size.into()); w.set_msize(data_size.into());
w.set_psize(data_size.into()); w.set_psize(data_size.into());
w.set_pl(vals::Pl::VERYHIGH); w.set_pl(vals::Pl::VERYHIGH);
w.set_minc(vals::Inc::INCREMENTED); w.set_minc(true);
w.set_pinc(vals::Inc::FIXED); w.set_pinc(false);
w.set_teie(true); w.set_teie(true);
w.set_htie(options.half_transfer_ir); w.set_htie(options.half_transfer_ir);
w.set_tcie(true); w.set_tcie(true);
w.set_circ(vals::Circ::ENABLED); w.set_circ(true);
#[cfg(dma_v1)] #[cfg(dma_v1)]
w.set_trbuff(true); w.set_trbuff(true);
#[cfg(dma_v2)] #[cfg(dma_v2)]

View File

@ -16,6 +16,7 @@ use crate::interrupt::Priority;
use crate::pac; use crate::pac;
use crate::pac::gpdma::vals; use crate::pac::gpdma::vals;
/// GPDMA transfer options.
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive] #[non_exhaustive]
@ -113,10 +114,13 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::gpdma::Gpdma, channel_num: usize, in
} }
} }
/// DMA request type alias. (also known as DMA channel number in some chips)
pub type Request = u8; pub type Request = u8;
/// DMA channel.
#[cfg(dmamux)] #[cfg(dmamux)]
pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {} pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {}
/// DMA channel.
#[cfg(not(dmamux))] #[cfg(not(dmamux))]
pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {} pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static {}
@ -131,12 +135,14 @@ pub(crate) mod sealed {
} }
} }
/// DMA transfer.
#[must_use = "futures do nothing unless you `.await` or poll them"] #[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Transfer<'a, C: Channel> { pub struct Transfer<'a, C: Channel> {
channel: PeripheralRef<'a, C>, channel: PeripheralRef<'a, C>,
} }
impl<'a, C: Channel> Transfer<'a, C> { impl<'a, C: Channel> Transfer<'a, C> {
/// Create a new read DMA transfer (peripheral to memory).
pub unsafe fn new_read<W: Word>( pub unsafe fn new_read<W: Word>(
channel: impl Peripheral<P = C> + 'a, channel: impl Peripheral<P = C> + 'a,
request: Request, request: Request,
@ -147,6 +153,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
Self::new_read_raw(channel, request, peri_addr, buf, options) Self::new_read_raw(channel, request, peri_addr, buf, options)
} }
/// Create a new read DMA transfer (peripheral to memory), using raw pointers.
pub unsafe fn new_read_raw<W: Word>( pub unsafe fn new_read_raw<W: Word>(
channel: impl Peripheral<P = C> + 'a, channel: impl Peripheral<P = C> + 'a,
request: Request, request: Request,
@ -172,6 +179,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
) )
} }
/// Create a new write DMA transfer (memory to peripheral).
pub unsafe fn new_write<W: Word>( pub unsafe fn new_write<W: Word>(
channel: impl Peripheral<P = C> + 'a, channel: impl Peripheral<P = C> + 'a,
request: Request, request: Request,
@ -182,6 +190,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
Self::new_write_raw(channel, request, buf, peri_addr, options) Self::new_write_raw(channel, request, buf, peri_addr, options)
} }
/// Create a new write DMA transfer (memory to peripheral), using raw pointers.
pub unsafe fn new_write_raw<W: Word>( pub unsafe fn new_write_raw<W: Word>(
channel: impl Peripheral<P = C> + 'a, channel: impl Peripheral<P = C> + 'a,
request: Request, request: Request,
@ -207,6 +216,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
) )
} }
/// Create a new write DMA transfer (memory to peripheral), writing the same value repeatedly.
pub unsafe fn new_write_repeated<W: Word>( pub unsafe fn new_write_repeated<W: Word>(
channel: impl Peripheral<P = C> + 'a, channel: impl Peripheral<P = C> + 'a,
request: Request, request: Request,
@ -297,6 +307,9 @@ impl<'a, C: Channel> Transfer<'a, C> {
this this
} }
/// Request the transfer to stop.
///
/// This doesn't immediately stop the transfer, you have to wait until [`is_running`](Self::is_running) returns false.
pub fn request_stop(&mut self) { pub fn request_stop(&mut self) {
let ch = self.channel.regs().ch(self.channel.num()); let ch = self.channel.regs().ch(self.channel.num());
ch.cr().modify(|w| { ch.cr().modify(|w| {
@ -304,6 +317,10 @@ impl<'a, C: Channel> Transfer<'a, C> {
}) })
} }
/// Return whether this transfer is still running.
///
/// If this returns `false`, it can be because either the transfer finished, or
/// it was requested to stop early with [`request_stop`](Self::request_stop).
pub fn is_running(&mut self) -> bool { pub fn is_running(&mut self) -> bool {
let ch = self.channel.regs().ch(self.channel.num()); let ch = self.channel.regs().ch(self.channel.num());
let sr = ch.sr().read(); let sr = ch.sr().read();
@ -317,6 +334,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
ch.br1().read().bndt() ch.br1().read().bndt()
} }
/// Blocking wait until the transfer finishes.
pub fn blocking_wait(mut self) { pub fn blocking_wait(mut self) {
while self.is_running() {} while self.is_running() {}

View File

@ -15,38 +15,42 @@ use crate::rcc::get_freqs;
use crate::time::Hertz; use crate::time::Hertz;
use crate::Peripheral; use crate::Peripheral;
pub enum Source { /// HRTIM burst controller instance.
Master,
ChA,
ChB,
ChC,
ChD,
ChE,
#[cfg(hrtim_v2)]
ChF,
}
pub struct BurstController<T: Instance> { pub struct BurstController<T: Instance> {
phantom: PhantomData<T>, phantom: PhantomData<T>,
} }
/// HRTIM master instance.
pub struct Master<T: Instance> { pub struct Master<T: Instance> {
phantom: PhantomData<T>, phantom: PhantomData<T>,
} }
/// HRTIM channel A instance.
pub struct ChA<T: Instance> { pub struct ChA<T: Instance> {
phantom: PhantomData<T>, phantom: PhantomData<T>,
} }
/// HRTIM channel B instance.
pub struct ChB<T: Instance> { pub struct ChB<T: Instance> {
phantom: PhantomData<T>, phantom: PhantomData<T>,
} }
/// HRTIM channel C instance.
pub struct ChC<T: Instance> { pub struct ChC<T: Instance> {
phantom: PhantomData<T>, phantom: PhantomData<T>,
} }
/// HRTIM channel D instance.
pub struct ChD<T: Instance> { pub struct ChD<T: Instance> {
phantom: PhantomData<T>, phantom: PhantomData<T>,
} }
/// HRTIM channel E instance.
pub struct ChE<T: Instance> { pub struct ChE<T: Instance> {
phantom: PhantomData<T>, phantom: PhantomData<T>,
} }
/// HRTIM channel F instance.
#[cfg(hrtim_v2)] #[cfg(hrtim_v2)]
pub struct ChF<T: Instance> { pub struct ChF<T: Instance> {
phantom: PhantomData<T>, phantom: PhantomData<T>,
@ -60,22 +64,26 @@ mod sealed {
} }
} }
/// Advanced channel instance trait.
pub trait AdvancedChannel<T: Instance>: sealed::AdvancedChannel<T> {} pub trait AdvancedChannel<T: Instance>: sealed::AdvancedChannel<T> {}
pub struct PwmPin<'d, Perip, Channel> { /// HRTIM PWM pin.
pub struct PwmPin<'d, T, C> {
_pin: PeripheralRef<'d, AnyPin>, _pin: PeripheralRef<'d, AnyPin>,
phantom: PhantomData<(Perip, Channel)>, phantom: PhantomData<(T, C)>,
} }
pub struct ComplementaryPwmPin<'d, Perip, Channel> { /// HRTIM complementary PWM pin.
pub struct ComplementaryPwmPin<'d, T, C> {
_pin: PeripheralRef<'d, AnyPin>, _pin: PeripheralRef<'d, AnyPin>,
phantom: PhantomData<(Perip, Channel)>, phantom: PhantomData<(T, C)>,
} }
macro_rules! advanced_channel_impl { macro_rules! advanced_channel_impl {
($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => { ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => {
impl<'d, Perip: Instance> PwmPin<'d, Perip, $channel<Perip>> { impl<'d, T: Instance> PwmPin<'d, T, $channel<T>> {
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self { #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")]
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd) -> Self {
into_ref!(pin); into_ref!(pin);
critical_section::with(|_| { critical_section::with(|_| {
pin.set_low(); pin.set_low();
@ -90,8 +98,9 @@ macro_rules! advanced_channel_impl {
} }
} }
impl<'d, Perip: Instance> ComplementaryPwmPin<'d, Perip, $channel<Perip>> { impl<'d, T: Instance> ComplementaryPwmPin<'d, T, $channel<T>> {
pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self { #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")]
pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<T>> + 'd) -> Self {
into_ref!(pin); into_ref!(pin);
critical_section::with(|_| { critical_section::with(|_| {
pin.set_low(); pin.set_low();
@ -126,18 +135,29 @@ advanced_channel_impl!(new_chf, ChF, 5, ChannelFPin, ChannelFComplementaryPin);
/// Struct used to divide a high resolution timer into multiple channels /// Struct used to divide a high resolution timer into multiple channels
pub struct AdvancedPwm<'d, T: Instance> { pub struct AdvancedPwm<'d, T: Instance> {
_inner: PeripheralRef<'d, T>, _inner: PeripheralRef<'d, T>,
/// Master instance.
pub master: Master<T>, pub master: Master<T>,
/// Burst controller.
pub burst_controller: BurstController<T>, pub burst_controller: BurstController<T>,
/// Channel A.
pub ch_a: ChA<T>, pub ch_a: ChA<T>,
/// Channel B.
pub ch_b: ChB<T>, pub ch_b: ChB<T>,
/// Channel C.
pub ch_c: ChC<T>, pub ch_c: ChC<T>,
/// Channel D.
pub ch_d: ChD<T>, pub ch_d: ChD<T>,
/// Channel E.
pub ch_e: ChE<T>, pub ch_e: ChE<T>,
/// Channel F.
#[cfg(hrtim_v2)] #[cfg(hrtim_v2)]
pub ch_f: ChF<T>, pub ch_f: ChF<T>,
} }
impl<'d, T: Instance> AdvancedPwm<'d, T> { impl<'d, T: Instance> AdvancedPwm<'d, T> {
/// Create a new HRTIM driver.
///
/// This splits the HRTIM into its constituent parts, which you can then use individually.
pub fn new( pub fn new(
tim: impl Peripheral<P = T> + 'd, tim: impl Peripheral<P = T> + 'd,
_cha: Option<PwmPin<'d, T, ChA<T>>>, _cha: Option<PwmPin<'d, T, ChA<T>>>,
@ -200,13 +220,7 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> {
} }
} }
impl<T: Instance> BurstController<T> { /// Fixed-frequency bridge converter driver.
pub fn set_source(&mut self, _source: Source) {
todo!("burst mode control registers not implemented")
}
}
/// Represents a fixed-frequency bridge converter
/// ///
/// Our implementation of the bridge converter uses a single channel and three compare registers, /// Our implementation of the bridge converter uses a single channel and three compare registers,
/// allowing implementation of a synchronous buck or boost converter in continuous or discontinuous /// allowing implementation of a synchronous buck or boost converter in continuous or discontinuous
@ -225,6 +239,7 @@ pub struct BridgeConverter<T: Instance, C: AdvancedChannel<T>> {
} }
impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> { impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> {
/// Create a new HRTIM bridge converter driver.
pub fn new(_channel: C, frequency: Hertz) -> Self { pub fn new(_channel: C, frequency: Hertz) -> Self {
use crate::pac::hrtim::vals::{Activeeffect, Inactiveeffect}; use crate::pac::hrtim::vals::{Activeeffect, Inactiveeffect};
@ -281,14 +296,17 @@ impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> {
} }
} }
/// Start HRTIM.
pub fn start(&mut self) { pub fn start(&mut self) {
T::regs().mcr().modify(|w| w.set_tcen(C::raw(), true)); T::regs().mcr().modify(|w| w.set_tcen(C::raw(), true));
} }
/// Stop HRTIM.
pub fn stop(&mut self) { pub fn stop(&mut self) {
T::regs().mcr().modify(|w| w.set_tcen(C::raw(), false)); T::regs().mcr().modify(|w| w.set_tcen(C::raw(), false));
} }
/// Enable burst mode.
pub fn enable_burst_mode(&mut self) { pub fn enable_burst_mode(&mut self) {
T::regs().tim(C::raw()).outr().modify(|w| { T::regs().tim(C::raw()).outr().modify(|w| {
// Enable Burst Mode // Enable Burst Mode
@ -301,6 +319,7 @@ impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> {
}) })
} }
/// Disable burst mode.
pub fn disable_burst_mode(&mut self) { pub fn disable_burst_mode(&mut self) {
T::regs().tim(C::raw()).outr().modify(|w| { T::regs().tim(C::raw()).outr().modify(|w| {
// Disable Burst Mode // Disable Burst Mode
@ -357,7 +376,7 @@ impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> {
} }
} }
/// Represents a variable-frequency resonant converter /// Variable-frequency resonant converter driver.
/// ///
/// This implementation of a resonsant converter is appropriate for a half or full bridge, /// This implementation of a resonsant converter is appropriate for a half or full bridge,
/// but does not include secondary rectification, which is appropriate for applications /// but does not include secondary rectification, which is appropriate for applications
@ -370,6 +389,7 @@ pub struct ResonantConverter<T: Instance, C: AdvancedChannel<T>> {
} }
impl<T: Instance, C: AdvancedChannel<T>> ResonantConverter<T, C> { impl<T: Instance, C: AdvancedChannel<T>> ResonantConverter<T, C> {
/// Create a new variable-frequency resonant converter driver.
pub fn new(_channel: C, min_frequency: Hertz, max_frequency: Hertz) -> Self { pub fn new(_channel: C, min_frequency: Hertz, max_frequency: Hertz) -> Self {
T::set_channel_frequency(C::raw(), min_frequency); T::set_channel_frequency(C::raw(), min_frequency);
@ -408,6 +428,7 @@ impl<T: Instance, C: AdvancedChannel<T>> ResonantConverter<T, C> {
T::set_channel_dead_time(C::raw(), value); T::set_channel_dead_time(C::raw(), value);
} }
/// Set the timer period.
pub fn set_period(&mut self, period: u16) { pub fn set_period(&mut self, period: u16) {
assert!(period < self.max_period); assert!(period < self.max_period);
assert!(period > self.min_period); assert!(period > self.min_period);

View File

@ -125,7 +125,6 @@ pub(crate) mod sealed {
} }
/// Set the dead time as a proportion of max_duty /// Set the dead time as a proportion of max_duty
fn set_channel_dead_time(channel: usize, dead_time: u16) { fn set_channel_dead_time(channel: usize, dead_time: u16) {
let regs = Self::regs(); let regs = Self::regs();
@ -148,13 +147,10 @@ pub(crate) mod sealed {
w.set_dtr(dt_val as u16); w.set_dtr(dt_val as u16);
}); });
} }
// fn enable_outputs(enable: bool);
//
// fn enable_channel(&mut self, channel: usize, enable: bool);
} }
} }
/// HRTIM instance trait.
pub trait Instance: sealed::Instance + 'static {} pub trait Instance: sealed::Instance + 'static {}
foreach_interrupt! { foreach_interrupt! {

View File

@ -1,3 +1,5 @@
//! Inter-Process Communication Controller (IPCC)
use core::future::poll_fn; use core::future::poll_fn;
use core::sync::atomic::{compiler_fence, Ordering}; use core::sync::atomic::{compiler_fence, Ordering};
use core::task::Poll; use core::task::Poll;
@ -41,6 +43,7 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_RX> for Receive
} }
} }
/// TX interrupt handler.
pub struct TransmitInterruptHandler {} pub struct TransmitInterruptHandler {}
impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for TransmitInterruptHandler { impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for TransmitInterruptHandler {
@ -72,6 +75,7 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::IPCC_C1_TX> for Transmi
} }
} }
/// IPCC config.
#[non_exhaustive] #[non_exhaustive]
#[derive(Clone, Copy, Default)] #[derive(Clone, Copy, Default)]
pub struct Config { pub struct Config {
@ -79,6 +83,8 @@ pub struct Config {
// reserved for future use // reserved for future use
} }
/// Channel.
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
#[repr(C)] #[repr(C)]
pub enum IpccChannel { pub enum IpccChannel {
@ -90,9 +96,11 @@ pub enum IpccChannel {
Channel6 = 5, Channel6 = 5,
} }
/// IPCC driver.
pub struct Ipcc; pub struct Ipcc;
impl Ipcc { impl Ipcc {
/// Enable IPCC.
pub fn enable(_config: Config) { pub fn enable(_config: Config) {
IPCC::enable_and_reset(); IPCC::enable_and_reset();
IPCC::set_cpu2(true); IPCC::set_cpu2(true);

View File

@ -1,5 +1,6 @@
#![cfg_attr(not(test), no_std)] #![cfg_attr(not(test), no_std)]
#![allow(async_fn_in_trait)] #![allow(async_fn_in_trait)]
#![warn(missing_docs)]
//! ## Feature flags //! ## Feature flags
#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)] #![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
@ -79,6 +80,7 @@ pub(crate) mod _generated {
#![allow(dead_code)] #![allow(dead_code)]
#![allow(unused_imports)] #![allow(unused_imports)]
#![allow(non_snake_case)] #![allow(non_snake_case)]
#![allow(missing_docs)]
include!(concat!(env!("OUT_DIR"), "/_generated.rs")); include!(concat!(env!("OUT_DIR"), "/_generated.rs"));
} }

View File

@ -1,50 +1,54 @@
/// The STM32 line of microcontrollers support various deep-sleep modes which exploit clock-gating //! Low-power support.
/// to reduce power consumption. `embassy-stm32` provides a low-power executor, [`Executor`] which //!
/// can use knowledge of which peripherals are currently blocked upon to transparently and safely //! The STM32 line of microcontrollers support various deep-sleep modes which exploit clock-gating
/// enter such low-power modes (currently, only `STOP2`) when idle. //! to reduce power consumption. `embassy-stm32` provides a low-power executor, [`Executor`] which
/// //! can use knowledge of which peripherals are currently blocked upon to transparently and safely
/// The executor determines which peripherals are active by their RCC state; consequently, //! enter such low-power modes (currently, only `STOP2`) when idle.
/// low-power states can only be entered if all peripherals have been `drop`'d. There are a few //!
/// exceptions to this rule: //! The executor determines which peripherals are active by their RCC state; consequently,
/// //! low-power states can only be entered if all peripherals have been `drop`'d. There are a few
/// * `GPIO` //! exceptions to this rule:
/// * `RCC` //!
/// //! * `GPIO`
/// Since entering and leaving low-power modes typically incurs a significant latency, the //! * `RCC`
/// low-power executor will only attempt to enter when the next timer event is at least //!
/// [`time_driver::MIN_STOP_PAUSE`] in the future. //! Since entering and leaving low-power modes typically incurs a significant latency, the
/// //! low-power executor will only attempt to enter when the next timer event is at least
/// Currently there is no macro analogous to `embassy_executor::main` for this executor; //! [`time_driver::MIN_STOP_PAUSE`] in the future.
/// consequently one must define their entrypoint manually. Moveover, you must relinquish control //!
/// of the `RTC` peripheral to the executor. This will typically look like //! Currently there is no macro analogous to `embassy_executor::main` for this executor;
/// //! consequently one must define their entrypoint manually. Moveover, you must relinquish control
/// ```rust,no_run //! of the `RTC` peripheral to the executor. This will typically look like
/// use embassy_executor::Spawner; //!
/// use embassy_stm32::low_power::Executor; //! ```rust,no_run
/// use embassy_stm32::rtc::{Rtc, RtcConfig}; //! use embassy_executor::Spawner;
/// use static_cell::make_static; //! use embassy_stm32::low_power::Executor;
/// //! use embassy_stm32::rtc::{Rtc, RtcConfig};
/// #[cortex_m_rt::entry] //! use static_cell::StaticCell;
/// fn main() -> ! { //!
/// Executor::take().run(|spawner| { //! #[cortex_m_rt::entry]
/// unwrap!(spawner.spawn(async_main(spawner))); //! fn main() -> ! {
/// }); //! Executor::take().run(|spawner| {
/// } //! unwrap!(spawner.spawn(async_main(spawner)));
/// //! });
/// #[embassy_executor::task] //! }
/// async fn async_main(spawner: Spawner) { //!
/// // initialize the platform... //! #[embassy_executor::task]
/// let mut config = embassy_stm32::Config::default(); //! async fn async_main(spawner: Spawner) {
/// let p = embassy_stm32::init(config); //! // initialize the platform...
/// //! let mut config = embassy_stm32::Config::default();
/// // give the RTC to the executor... //! let p = embassy_stm32::init(config);
/// let mut rtc = Rtc::new(p.RTC, RtcConfig::default()); //!
/// let rtc = make_static!(rtc); //! // give the RTC to the executor...
/// embassy_stm32::low_power::stop_with_rtc(rtc); //! let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
/// //! static RTC: StaticCell<Rtc> = StaticCell::new();
/// // your application here... //! let rtc = RTC.init(rtc);
/// } //! embassy_stm32::low_power::stop_with_rtc(rtc);
/// ``` //!
//! // your application here...
//! }
//! ```
use core::arch::asm; use core::arch::asm;
use core::marker::PhantomData; use core::marker::PhantomData;
use core::sync::atomic::{compiler_fence, Ordering}; use core::sync::atomic::{compiler_fence, Ordering};
@ -64,6 +68,7 @@ static mut EXECUTOR: Option<Executor> = None;
foreach_interrupt! { foreach_interrupt! {
(RTC, rtc, $block:ident, WKUP, $irq:ident) => { (RTC, rtc, $block:ident, WKUP, $irq:ident) => {
#[interrupt] #[interrupt]
#[allow(non_snake_case)]
unsafe fn $irq() { unsafe fn $irq() {
EXECUTOR.as_mut().unwrap().on_wakeup_irq(); EXECUTOR.as_mut().unwrap().on_wakeup_irq();
} }
@ -75,10 +80,15 @@ pub(crate) unsafe fn on_wakeup_irq() {
EXECUTOR.as_mut().unwrap().on_wakeup_irq(); EXECUTOR.as_mut().unwrap().on_wakeup_irq();
} }
/// Configure STOP mode with RTC.
pub fn stop_with_rtc(rtc: &'static Rtc) { pub fn stop_with_rtc(rtc: &'static Rtc) {
unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc) unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc)
} }
/// Get whether the core is ready to enter the given stop mode.
///
/// This will return false if some peripheral driver is in use that
/// prevents entering the given stop mode.
pub fn stop_ready(stop_mode: StopMode) -> bool { pub fn stop_ready(stop_mode: StopMode) -> bool {
match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() { match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() {
Some(StopMode::Stop2) => true, Some(StopMode::Stop2) => true,
@ -87,10 +97,13 @@ pub fn stop_ready(stop_mode: StopMode) -> bool {
} }
} }
/// Available stop modes.
#[non_exhaustive] #[non_exhaustive]
#[derive(PartialEq)] #[derive(PartialEq)]
pub enum StopMode { pub enum StopMode {
/// STOP 1
Stop1, Stop1,
/// STOP 2
Stop2, Stop2,
} }

View File

@ -1,9 +1,12 @@
//! Operational Amplifier (OPAMP)
#![macro_use] #![macro_use]
use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_hal_internal::{into_ref, PeripheralRef};
use crate::Peripheral; use crate::Peripheral;
/// Gain
#[allow(missing_docs)]
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum OpAmpGain { pub enum OpAmpGain {
Mul1, Mul1,
@ -13,6 +16,8 @@ pub enum OpAmpGain {
Mul16, Mul16,
} }
/// Speed
#[allow(missing_docs)]
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum OpAmpSpeed { pub enum OpAmpSpeed {
Normal, Normal,
@ -180,6 +185,7 @@ impl<'d, T: Instance> Drop for OpAmpInternalOutput<'d, T> {
} }
} }
/// Opamp instance trait.
pub trait Instance: sealed::Instance + 'static {} pub trait Instance: sealed::Instance + 'static {}
pub(crate) mod sealed { pub(crate) mod sealed {
@ -198,8 +204,11 @@ pub(crate) mod sealed {
pub trait OutputPin<T: Instance> {} pub trait OutputPin<T: Instance> {}
} }
/// Non-inverting pin trait.
pub trait NonInvertingPin<T: Instance>: sealed::NonInvertingPin<T> {} pub trait NonInvertingPin<T: Instance>: sealed::NonInvertingPin<T> {}
/// Inverting pin trait.
pub trait InvertingPin<T: Instance>: sealed::InvertingPin<T> {} pub trait InvertingPin<T: Instance>: sealed::InvertingPin<T> {}
/// Output pin trait.
pub trait OutputPin<T: Instance>: sealed::OutputPin<T> {} pub trait OutputPin<T: Instance>: sealed::OutputPin<T> {}
macro_rules! impl_opamp_external_output { macro_rules! impl_opamp_external_output {

View File

@ -1,3 +1,5 @@
//! Enums used in QSPI configuration.
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub(crate) enum QspiMode { pub(crate) enum QspiMode {

View File

@ -14,6 +14,7 @@ use crate::pac::quadspi::Quadspi as Regs;
use crate::rcc::RccPeripheral; use crate::rcc::RccPeripheral;
use crate::{peripherals, Peripheral}; use crate::{peripherals, Peripheral};
/// QSPI transfer configuration.
pub struct TransferConfig { pub struct TransferConfig {
/// Instraction width (IMODE) /// Instraction width (IMODE)
pub iwidth: QspiWidth, pub iwidth: QspiWidth,
@ -45,6 +46,7 @@ impl Default for TransferConfig {
} }
} }
/// QSPI driver configuration.
pub struct Config { pub struct Config {
/// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen. /// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen.
/// If you need other value the whose predefined use `Other` variant. /// If you need other value the whose predefined use `Other` variant.
@ -71,6 +73,7 @@ impl Default for Config {
} }
} }
/// QSPI driver.
#[allow(dead_code)] #[allow(dead_code)]
pub struct Qspi<'d, T: Instance, Dma> { pub struct Qspi<'d, T: Instance, Dma> {
_peri: PeripheralRef<'d, T>, _peri: PeripheralRef<'d, T>,
@ -85,6 +88,7 @@ pub struct Qspi<'d, T: Instance, Dma> {
} }
impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
/// Create a new QSPI driver for bank 1.
pub fn new_bk1( pub fn new_bk1(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
d0: impl Peripheral<P = impl BK1D0Pin<T>> + 'd, d0: impl Peripheral<P = impl BK1D0Pin<T>> + 'd,
@ -125,6 +129,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
) )
} }
/// Create a new QSPI driver for bank 2.
pub fn new_bk2( pub fn new_bk2(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
d0: impl Peripheral<P = impl BK2D0Pin<T>> + 'd, d0: impl Peripheral<P = impl BK2D0Pin<T>> + 'd,
@ -223,6 +228,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
} }
} }
/// Do a QSPI command.
pub fn command(&mut self, transaction: TransferConfig) { pub fn command(&mut self, transaction: TransferConfig) {
#[cfg(not(stm32h7))] #[cfg(not(stm32h7))]
T::REGS.cr().modify(|v| v.set_dmaen(false)); T::REGS.cr().modify(|v| v.set_dmaen(false));
@ -232,6 +238,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
T::REGS.fcr().modify(|v| v.set_ctcf(true)); T::REGS.fcr().modify(|v| v.set_ctcf(true));
} }
/// Blocking read data.
pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) { pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) {
#[cfg(not(stm32h7))] #[cfg(not(stm32h7))]
T::REGS.cr().modify(|v| v.set_dmaen(false)); T::REGS.cr().modify(|v| v.set_dmaen(false));
@ -256,6 +263,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
T::REGS.fcr().modify(|v| v.set_ctcf(true)); T::REGS.fcr().modify(|v| v.set_ctcf(true));
} }
/// Blocking write data.
pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) { pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) {
// STM32H7 does not have dmaen // STM32H7 does not have dmaen
#[cfg(not(stm32h7))] #[cfg(not(stm32h7))]
@ -278,6 +286,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
T::REGS.fcr().modify(|v| v.set_ctcf(true)); T::REGS.fcr().modify(|v| v.set_ctcf(true));
} }
/// Blocking read data, using DMA.
pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig)
where where
Dma: QuadDma<T>, Dma: QuadDma<T>,
@ -310,6 +319,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
transfer.blocking_wait(); transfer.blocking_wait();
} }
/// Blocking write data, using DMA.
pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig)
where where
Dma: QuadDma<T>, Dma: QuadDma<T>,
@ -379,6 +389,7 @@ pub(crate) mod sealed {
} }
} }
/// QSPI instance trait.
pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
pin_trait!(SckPin, Instance); pin_trait!(SckPin, Instance);

View File

@ -80,6 +80,7 @@ impl<'d, T: Instance> Rng<'d, T> {
let _ = self.next_u32(); let _ = self.next_u32();
} }
/// Reset the RNG.
#[cfg(not(rng_v1))] #[cfg(not(rng_v1))]
pub fn reset(&mut self) { pub fn reset(&mut self) {
T::regs().cr().write(|reg| { T::regs().cr().write(|reg| {

View File

@ -130,7 +130,7 @@ impl RtcTimeProvider {
let weekday = day_of_week_from_u8(dr.wdu()).map_err(RtcError::InvalidDateTime)?; let weekday = day_of_week_from_u8(dr.wdu()).map_err(RtcError::InvalidDateTime)?;
let day = bcd2_to_byte((dr.dt(), dr.du())); let day = bcd2_to_byte((dr.dt(), dr.du()));
let month = bcd2_to_byte((dr.mt() as u8, dr.mu())); let month = bcd2_to_byte((dr.mt() as u8, dr.mu()));
let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16; let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 2000_u16;
DateTime::from(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime) DateTime::from(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime)
}) })
@ -261,7 +261,7 @@ impl Rtc {
let (dt, du) = byte_to_bcd2(t.day() as u8); let (dt, du) = byte_to_bcd2(t.day() as u8);
let (mt, mu) = byte_to_bcd2(t.month() as u8); let (mt, mu) = byte_to_bcd2(t.month() as u8);
let yr = t.year() as u16; let yr = t.year() as u16;
let yr_offset = (yr - 1970_u16) as u8; let yr_offset = (yr - 2000_u16) as u8;
let (yt, yu) = byte_to_bcd2(yr_offset); let (yt, yu) = byte_to_bcd2(yr_offset);
use crate::pac::rtc::vals::Ampm; use crate::pac::rtc::vals::Ampm;

View File

@ -54,6 +54,7 @@ const SD_INIT_FREQ: Hertz = Hertz(400_000);
/// The signalling scheme used on the SDMMC bus /// The signalling scheme used on the SDMMC bus
#[non_exhaustive] #[non_exhaustive]
#[allow(missing_docs)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Signalling { pub enum Signalling {
@ -70,6 +71,9 @@ impl Default for Signalling {
} }
} }
/// Aligned data block for SDMMC transfers.
///
/// This is a 512-byte array, aligned to 4 bytes to satisfy DMA requirements.
#[repr(align(4))] #[repr(align(4))]
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
@ -94,17 +98,23 @@ impl DerefMut for DataBlock {
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error { pub enum Error {
/// Timeout reported by the hardware
Timeout, Timeout,
/// Timeout reported by the software driver.
SoftwareTimeout, SoftwareTimeout,
/// Unsupported card version.
UnsupportedCardVersion, UnsupportedCardVersion,
/// Unsupported card type.
UnsupportedCardType, UnsupportedCardType,
/// CRC error.
Crc, Crc,
DataCrcFail, /// No card inserted.
RxOverFlow,
NoCard, NoCard,
/// Bad clock supplied to the SDMMC peripheral.
BadClock, BadClock,
/// Signaling switch failed.
SignalingSwitchFailed, SignalingSwitchFailed,
PeripheralBusy, /// ST bit error.
#[cfg(sdmmc_v1)] #[cfg(sdmmc_v1)]
StBitErr, StBitErr,
} }
@ -283,6 +293,7 @@ pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma<T> = NoDma> {
#[cfg(sdmmc_v1)] #[cfg(sdmmc_v1)]
impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> { impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
/// Create a new SDMMC driver, with 1 data lane.
pub fn new_1bit( pub fn new_1bit(
sdmmc: impl Peripheral<P = T> + 'd, sdmmc: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@ -317,6 +328,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
) )
} }
/// Create a new SDMMC driver, with 4 data lanes.
pub fn new_4bit( pub fn new_4bit(
sdmmc: impl Peripheral<P = T> + 'd, sdmmc: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@ -363,6 +375,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
#[cfg(sdmmc_v2)] #[cfg(sdmmc_v2)]
impl<'d, T: Instance> Sdmmc<'d, T, NoDma> { impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
/// Create a new SDMMC driver, with 1 data lane.
pub fn new_1bit( pub fn new_1bit(
sdmmc: impl Peripheral<P = T> + 'd, sdmmc: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@ -396,6 +409,7 @@ impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
) )
} }
/// Create a new SDMMC driver, with 4 data lanes.
pub fn new_4bit( pub fn new_4bit(
sdmmc: impl Peripheral<P = T> + 'd, sdmmc: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@ -497,7 +511,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
} }
/// Data transfer is in progress /// Data transfer is in progress
#[inline(always)] #[inline]
fn data_active() -> bool { fn data_active() -> bool {
let regs = T::regs(); let regs = T::regs();
@ -509,7 +523,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
} }
/// Coammand transfer is in progress /// Coammand transfer is in progress
#[inline(always)] #[inline]
fn cmd_active() -> bool { fn cmd_active() -> bool {
let regs = T::regs(); let regs = T::regs();
@ -521,7 +535,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
} }
/// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2) /// Wait idle on CMDACT, RXACT and TXACT (v1) or DOSNACT and CPSMACT (v2)
#[inline(always)] #[inline]
fn wait_idle() { fn wait_idle() {
while Self::data_active() || Self::cmd_active() {} while Self::data_active() || Self::cmd_active() {}
} }
@ -837,7 +851,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
} }
/// Clear flags in interrupt clear register /// Clear flags in interrupt clear register
#[inline(always)] #[inline]
fn clear_interrupt_flags() { fn clear_interrupt_flags() {
let regs = T::regs(); let regs = T::regs();
regs.icr().write(|w| { regs.icr().write(|w| {
@ -1152,7 +1166,8 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
Ok(()) Ok(())
} }
#[inline(always)] /// Read a data block.
#[inline]
pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> { pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> {
let card_capacity = self.card()?.card_type; let card_capacity = self.card()?.card_type;
@ -1204,6 +1219,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
res res
} }
/// Write a data block.
pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> { pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> {
let card = self.card.as_mut().ok_or(Error::NoCard)?; let card = self.card.as_mut().ok_or(Error::NoCard)?;
@ -1283,7 +1299,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
/// ///
/// Returns Error::NoCard if [`init_card`](#method.init_card) /// Returns Error::NoCard if [`init_card`](#method.init_card)
/// has not previously succeeded /// has not previously succeeded
#[inline(always)] #[inline]
pub fn card(&self) -> Result<&Card, Error> { pub fn card(&self) -> Result<&Card, Error> {
self.card.as_ref().ok_or(Error::NoCard) self.card.as_ref().ok_or(Error::NoCard)
} }
@ -1419,7 +1435,9 @@ pub(crate) mod sealed {
pub trait Pins<T: Instance> {} pub trait Pins<T: Instance> {}
} }
/// SDMMC instance trait.
pub trait Instance: sealed::Instance + RccPeripheral + 'static {} pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
pin_trait!(CkPin, Instance); pin_trait!(CkPin, Instance);
pin_trait!(CmdPin, Instance); pin_trait!(CmdPin, Instance);
pin_trait!(D0Pin, Instance); pin_trait!(D0Pin, Instance);
@ -1434,7 +1452,10 @@ pin_trait!(D7Pin, Instance);
#[cfg(sdmmc_v1)] #[cfg(sdmmc_v1)]
dma_trait!(SdmmcDma, Instance); dma_trait!(SdmmcDma, Instance);
// SDMMCv2 uses internal DMA /// DMA instance trait.
///
/// This is only implemented for `NoDma`, since SDMMCv2 has DMA built-in, instead of
/// using ST's system-wide DMA peripheral.
#[cfg(sdmmc_v2)] #[cfg(sdmmc_v2)]
pub trait SdmmcDma<T: Instance> {} pub trait SdmmcDma<T: Instance> {}
#[cfg(sdmmc_v2)] #[cfg(sdmmc_v2)]
@ -1517,53 +1538,3 @@ foreach_peripheral!(
impl Instance for peripherals::$inst {} impl Instance for peripherals::$inst {}
}; };
); );
#[cfg(feature = "embedded-sdmmc")]
mod sdmmc_rs {
use embedded_sdmmc::{Block, BlockCount, BlockDevice, BlockIdx};
use super::*;
impl<'d, T: Instance, Dma: SdmmcDma<T>> BlockDevice for Sdmmc<'d, T, Dma> {
type Error = Error;
async fn read(
&mut self,
blocks: &mut [Block],
start_block_idx: BlockIdx,
_reason: &str,
) -> Result<(), Self::Error> {
let mut address = start_block_idx.0;
for block in blocks.iter_mut() {
let block: &mut [u8; 512] = &mut block.contents;
// NOTE(unsafe) Block uses align(4)
let block = unsafe { &mut *(block as *mut _ as *mut DataBlock) };
self.read_block(address, block).await?;
address += 1;
}
Ok(())
}
async fn write(&mut self, blocks: &[Block], start_block_idx: BlockIdx) -> Result<(), Self::Error> {
let mut address = start_block_idx.0;
for block in blocks.iter() {
let block: &[u8; 512] = &block.contents;
// NOTE(unsafe) DataBlock uses align 4
let block = unsafe { &*(block as *const _ as *const DataBlock) };
self.write_block(address, block).await?;
address += 1;
}
Ok(())
}
fn num_blocks(&self) -> Result<BlockCount, Self::Error> {
let card = self.card()?;
let count = card.csd.block_count();
Ok(BlockCount(count))
}
}
}

View File

@ -16,27 +16,38 @@ use crate::rcc::RccPeripheral;
use crate::time::Hertz; use crate::time::Hertz;
use crate::{peripherals, Peripheral}; use crate::{peripherals, Peripheral};
/// SPI error.
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error { pub enum Error {
/// Invalid framing.
Framing, Framing,
/// CRC error (only if hardware CRC checking is enabled).
Crc, Crc,
/// Mode fault
ModeFault, ModeFault,
/// Overrun.
Overrun, Overrun,
} }
// TODO move upwards in the tree /// SPI bit order
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum BitOrder { pub enum BitOrder {
/// Least significant bit first.
LsbFirst, LsbFirst,
/// Most significant bit first.
MsbFirst, MsbFirst,
} }
/// SPI configuration.
#[non_exhaustive] #[non_exhaustive]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct Config { pub struct Config {
/// SPI mode.
pub mode: Mode, pub mode: Mode,
/// Bit order.
pub bit_order: BitOrder, pub bit_order: BitOrder,
/// Clock frequency.
pub frequency: Hertz, pub frequency: Hertz,
} }
@ -73,6 +84,7 @@ impl Config {
} }
} }
/// SPI driver.
pub struct Spi<'d, T: Instance, Tx, Rx> { pub struct Spi<'d, T: Instance, Tx, Rx> {
_peri: PeripheralRef<'d, T>, _peri: PeripheralRef<'d, T>,
sck: Option<PeripheralRef<'d, AnyPin>>, sck: Option<PeripheralRef<'d, AnyPin>>,
@ -84,6 +96,7 @@ pub struct Spi<'d, T: Instance, Tx, Rx> {
} }
impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
/// Create a new SPI driver.
pub fn new( pub fn new(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
sck: impl Peripheral<P = impl SckPin<T>> + 'd, sck: impl Peripheral<P = impl SckPin<T>> + 'd,
@ -118,6 +131,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
) )
} }
/// Create a new SPI driver, in RX-only mode (only MISO pin, no MOSI).
pub fn new_rxonly( pub fn new_rxonly(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
sck: impl Peripheral<P = impl SckPin<T>> + 'd, sck: impl Peripheral<P = impl SckPin<T>> + 'd,
@ -143,6 +157,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
) )
} }
/// Create a new SPI driver, in TX-only mode (only MOSI pin, no MISO).
pub fn new_txonly( pub fn new_txonly(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
sck: impl Peripheral<P = impl SckPin<T>> + 'd, sck: impl Peripheral<P = impl SckPin<T>> + 'd,
@ -168,6 +183,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
) )
} }
/// Create a new SPI driver, in TX-only mode, without SCK pin.
///
/// This can be useful for bit-banging non-SPI protocols.
pub fn new_txonly_nosck( pub fn new_txonly_nosck(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
mosi: impl Peripheral<P = impl MosiPin<T>> + 'd, mosi: impl Peripheral<P = impl MosiPin<T>> + 'd,
@ -355,6 +373,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
Ok(()) Ok(())
} }
/// Get current SPI configuration.
pub fn get_current_config(&self) -> Config { pub fn get_current_config(&self) -> Config {
#[cfg(any(spi_v1, spi_f1, spi_v2))] #[cfg(any(spi_v1, spi_f1, spi_v2))]
let cfg = T::REGS.cr1().read(); let cfg = T::REGS.cr1().read();
@ -444,6 +463,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
self.current_word_size = word_size; self.current_word_size = word_size;
} }
/// SPI write, using DMA.
pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error>
where where
Tx: TxDma<T>, Tx: TxDma<T>,
@ -477,6 +497,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
Ok(()) Ok(())
} }
/// SPI read, using DMA.
pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error>
where where
Tx: TxDma<T>, Tx: TxDma<T>,
@ -580,6 +601,12 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
Ok(()) Ok(())
} }
/// Bidirectional transfer, using DMA.
///
/// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`.
///
/// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
/// If `write` is shorter it is padded with zero bytes.
pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error>
where where
Tx: TxDma<T>, Tx: TxDma<T>,
@ -588,6 +615,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
self.transfer_inner(read, write).await self.transfer_inner(read, write).await
} }
/// In-place bidirectional transfer, using DMA.
///
/// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error>
where where
Tx: TxDma<T>, Tx: TxDma<T>,
@ -596,6 +626,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
self.transfer_inner(data, data).await self.transfer_inner(data, data).await
} }
/// Blocking write.
pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> { pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
T::REGS.cr1().modify(|w| w.set_spe(true)); T::REGS.cr1().modify(|w| w.set_spe(true));
flush_rx_fifo(T::REGS); flush_rx_fifo(T::REGS);
@ -606,6 +637,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
Ok(()) Ok(())
} }
/// Blocking read.
pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
T::REGS.cr1().modify(|w| w.set_spe(true)); T::REGS.cr1().modify(|w| w.set_spe(true));
flush_rx_fifo(T::REGS); flush_rx_fifo(T::REGS);
@ -616,6 +648,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
Ok(()) Ok(())
} }
/// Blocking in-place bidirectional transfer.
///
/// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
T::REGS.cr1().modify(|w| w.set_spe(true)); T::REGS.cr1().modify(|w| w.set_spe(true));
flush_rx_fifo(T::REGS); flush_rx_fifo(T::REGS);
@ -626,6 +661,12 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
Ok(()) Ok(())
} }
/// Blocking bidirectional transfer.
///
/// This transfers both buffers at the same time, so it is NOT equivalent to `write` followed by `read`.
///
/// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
/// If `write` is shorter it is padded with zero bytes.
pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
T::REGS.cr1().modify(|w| w.set_spe(true)); T::REGS.cr1().modify(|w| w.set_spe(true));
flush_rx_fifo(T::REGS); flush_rx_fifo(T::REGS);
@ -946,6 +987,7 @@ pub(crate) mod sealed {
} }
} }
/// Word sizes usable for SPI.
pub trait Word: word::Word + sealed::Word {} pub trait Word: word::Word + sealed::Word {}
macro_rules! impl_word { macro_rules! impl_word {
@ -1025,7 +1067,9 @@ mod word_impl {
impl_word!(u32, 32 - 1); impl_word!(u32, 32 - 1);
} }
/// SPI instance trait.
pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
pin_trait!(SckPin, Instance); pin_trait!(SckPin, Instance);
pin_trait!(MosiPin, Instance); pin_trait!(MosiPin, Instance);
pin_trait!(MisoPin, Instance); pin_trait!(MisoPin, Instance);

View File

@ -8,14 +8,17 @@ use core::ops::{Div, Mul};
pub struct Hertz(pub u32); pub struct Hertz(pub u32);
impl Hertz { impl Hertz {
/// Create a `Hertz` from the given hertz.
pub const fn hz(hertz: u32) -> Self { pub const fn hz(hertz: u32) -> Self {
Self(hertz) Self(hertz)
} }
/// Create a `Hertz` from the given kilohertz.
pub const fn khz(kilohertz: u32) -> Self { pub const fn khz(kilohertz: u32) -> Self {
Self(kilohertz * 1_000) Self(kilohertz * 1_000)
} }
/// Create a `Hertz` from the given megahertz.
pub const fn mhz(megahertz: u32) -> Self { pub const fn mhz(megahertz: u32) -> Self {
Self(megahertz * 1_000_000) Self(megahertz * 1_000_000)
} }

View File

@ -13,15 +13,19 @@ use crate::gpio::{AnyPin, OutputType};
use crate::time::Hertz; use crate::time::Hertz;
use crate::Peripheral; use crate::Peripheral;
pub struct ComplementaryPwmPin<'d, Perip, Channel> { /// Complementary PWM pin wrapper.
///
/// This wraps a pin to make it usable with PWM.
pub struct ComplementaryPwmPin<'d, T, C> {
_pin: PeripheralRef<'d, AnyPin>, _pin: PeripheralRef<'d, AnyPin>,
phantom: PhantomData<(Perip, Channel)>, phantom: PhantomData<(T, C)>,
} }
macro_rules! complementary_channel_impl { macro_rules! complementary_channel_impl {
($new_chx:ident, $channel:ident, $pin_trait:ident) => { ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> { impl<'d, T: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, T, $channel> {
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd, output_type: OutputType) -> Self { #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")]
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self {
into_ref!(pin); into_ref!(pin);
critical_section::with(|_| { critical_section::with(|_| {
pin.set_low(); pin.set_low();
@ -43,11 +47,13 @@ complementary_channel_impl!(new_ch2, Ch2, Channel2ComplementaryPin);
complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin); complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin);
complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin); complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin);
/// PWM driver with support for standard and complementary outputs.
pub struct ComplementaryPwm<'d, T> { pub struct ComplementaryPwm<'d, T> {
inner: PeripheralRef<'d, T>, inner: PeripheralRef<'d, T>,
} }
impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
/// Create a new complementary PWM driver.
pub fn new( pub fn new(
tim: impl Peripheral<P = T> + 'd, tim: impl Peripheral<P = T> + 'd,
_ch1: Option<PwmPin<'d, T, Ch1>>, _ch1: Option<PwmPin<'d, T, Ch1>>,
@ -72,7 +78,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
let mut this = Self { inner: tim }; let mut this = Self { inner: tim };
this.inner.set_counting_mode(counting_mode); this.inner.set_counting_mode(counting_mode);
this.set_freq(freq); this.set_frequency(freq);
this.inner.start(); this.inner.start();
this.inner.enable_outputs(); this.inner.enable_outputs();
@ -88,17 +94,23 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
this this
} }
/// Enable the given channel.
pub fn enable(&mut self, channel: Channel) { pub fn enable(&mut self, channel: Channel) {
self.inner.enable_channel(channel, true); self.inner.enable_channel(channel, true);
self.inner.enable_complementary_channel(channel, true); self.inner.enable_complementary_channel(channel, true);
} }
/// Disable the given channel.
pub fn disable(&mut self, channel: Channel) { pub fn disable(&mut self, channel: Channel) {
self.inner.enable_complementary_channel(channel, false); self.inner.enable_complementary_channel(channel, false);
self.inner.enable_channel(channel, false); self.inner.enable_channel(channel, false);
} }
pub fn set_freq(&mut self, freq: Hertz) { /// Set PWM frequency.
///
/// Note: when you call this, the max duty value changes, so you will have to
/// call `set_duty` on all channels with the duty calculated based on the new max duty.
pub fn set_frequency(&mut self, freq: Hertz) {
let multiplier = if self.inner.get_counting_mode().is_center_aligned() { let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
2u8 2u8
} else { } else {
@ -107,15 +119,22 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
self.inner.set_frequency(freq * multiplier); self.inner.set_frequency(freq * multiplier);
} }
/// Get max duty value.
///
/// This value depends on the configured frequency and the timer's clock rate from RCC.
pub fn get_max_duty(&self) -> u16 { pub fn get_max_duty(&self) -> u16 {
self.inner.get_max_compare_value() + 1 self.inner.get_max_compare_value() + 1
} }
/// Set the duty for a given channel.
///
/// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
pub fn set_duty(&mut self, channel: Channel, duty: u16) { pub fn set_duty(&mut self, channel: Channel, duty: u16) {
assert!(duty <= self.get_max_duty()); assert!(duty <= self.get_max_duty());
self.inner.set_compare_value(channel, duty) self.inner.set_compare_value(channel, duty)
} }
/// Set the output polarity for a given channel.
pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
self.inner.set_output_polarity(channel, polarity); self.inner.set_output_polarity(channel, polarity);
self.inner.set_complementary_output_polarity(channel, polarity); self.inner.set_complementary_output_polarity(channel, polarity);

View File

@ -17,17 +17,27 @@ pub mod low_level {
} }
pub(crate) mod sealed { pub(crate) mod sealed {
use super::*; use super::*;
/// Basic 16-bit timer instance.
pub trait Basic16bitInstance: RccPeripheral { pub trait Basic16bitInstance: RccPeripheral {
/// Interrupt for this timer.
type Interrupt: interrupt::typelevel::Interrupt; type Interrupt: interrupt::typelevel::Interrupt;
/// Get access to the basic 16bit timer registers.
///
/// Note: This works even if the timer is more capable, because registers
/// for the less capable timers are a subset. This allows writing a driver
/// for a given set of capabilities, and having it transparently work with
/// more capable timers.
fn regs() -> crate::pac::timer::TimBasic; fn regs() -> crate::pac::timer::TimBasic;
/// Start the timer.
fn start(&mut self) { fn start(&mut self) {
Self::regs().cr1().modify(|r| r.set_cen(true)); Self::regs().cr1().modify(|r| r.set_cen(true));
} }
/// Stop the timer.
fn stop(&mut self) { fn stop(&mut self) {
Self::regs().cr1().modify(|r| r.set_cen(false)); Self::regs().cr1().modify(|r| r.set_cen(false));
} }
@ -63,6 +73,9 @@ pub(crate) mod sealed {
regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
} }
/// Clear update interrupt.
///
/// Returns whether the update interrupt flag was set.
fn clear_update_interrupt(&mut self) -> bool { fn clear_update_interrupt(&mut self) -> bool {
let regs = Self::regs(); let regs = Self::regs();
let sr = regs.sr().read(); let sr = regs.sr().read();
@ -76,14 +89,17 @@ pub(crate) mod sealed {
} }
} }
/// Enable/disable the update interrupt.
fn enable_update_interrupt(&mut self, enable: bool) { fn enable_update_interrupt(&mut self, enable: bool) {
Self::regs().dier().write(|r| r.set_uie(enable)); Self::regs().dier().write(|r| r.set_uie(enable));
} }
/// Enable/disable autoreload preload.
fn set_autoreload_preload(&mut self, enable: bool) { fn set_autoreload_preload(&mut self, enable: bool) {
Self::regs().cr1().modify(|r| r.set_arpe(enable)); Self::regs().cr1().modify(|r| r.set_arpe(enable));
} }
/// Get the timer frequency.
fn get_frequency(&self) -> Hertz { fn get_frequency(&self) -> Hertz {
let timer_f = Self::frequency(); let timer_f = Self::frequency();
@ -95,9 +111,17 @@ pub(crate) mod sealed {
} }
} }
/// Gneral-purpose 16-bit timer instance.
pub trait GeneralPurpose16bitInstance: Basic16bitInstance { pub trait GeneralPurpose16bitInstance: Basic16bitInstance {
/// Get access to the general purpose 16bit timer registers.
///
/// Note: This works even if the timer is more capable, because registers
/// for the less capable timers are a subset. This allows writing a driver
/// for a given set of capabilities, and having it transparently work with
/// more capable timers.
fn regs_gp16() -> crate::pac::timer::TimGp16; fn regs_gp16() -> crate::pac::timer::TimGp16;
/// Set counting mode.
fn set_counting_mode(&mut self, mode: CountingMode) { fn set_counting_mode(&mut self, mode: CountingMode) {
let (cms, dir) = mode.into(); let (cms, dir) = mode.into();
@ -110,19 +134,29 @@ pub(crate) mod sealed {
Self::regs_gp16().cr1().modify(|r| r.set_cms(cms)) Self::regs_gp16().cr1().modify(|r| r.set_cms(cms))
} }
/// Get counting mode.
fn get_counting_mode(&self) -> CountingMode { fn get_counting_mode(&self) -> CountingMode {
let cr1 = Self::regs_gp16().cr1().read(); let cr1 = Self::regs_gp16().cr1().read();
(cr1.cms(), cr1.dir()).into() (cr1.cms(), cr1.dir()).into()
} }
/// Set clock divider.
fn set_clock_division(&mut self, ckd: vals::Ckd) { fn set_clock_division(&mut self, ckd: vals::Ckd) {
Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd)); Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd));
} }
} }
/// Gneral-purpose 32-bit timer instance.
pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance {
/// Get access to the general purpose 32bit timer registers.
///
/// Note: This works even if the timer is more capable, because registers
/// for the less capable timers are a subset. This allows writing a driver
/// for a given set of capabilities, and having it transparently work with
/// more capable timers.
fn regs_gp32() -> crate::pac::timer::TimGp32; fn regs_gp32() -> crate::pac::timer::TimGp32;
/// Set timer frequency.
fn set_frequency(&mut self, frequency: Hertz) { fn set_frequency(&mut self, frequency: Hertz) {
let f = frequency.0; let f = frequency.0;
assert!(f > 0); assert!(f > 0);
@ -140,6 +174,7 @@ pub(crate) mod sealed {
regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
} }
/// Get timer frequency.
fn get_frequency(&self) -> Hertz { fn get_frequency(&self) -> Hertz {
let timer_f = Self::frequency(); let timer_f = Self::frequency();
@ -151,141 +186,177 @@ pub(crate) mod sealed {
} }
} }
/// Advanced control timer instance.
pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { pub trait AdvancedControlInstance: GeneralPurpose16bitInstance {
/// Get access to the advanced timer registers.
fn regs_advanced() -> crate::pac::timer::TimAdv; fn regs_advanced() -> crate::pac::timer::TimAdv;
} }
/// Capture/Compare 16-bit timer instance.
pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance { pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance {
/// Set input capture filter.
fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) { fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) {
let raw_channel = channel.raw(); let raw_channel = channel.index();
Self::regs_gp16() Self::regs_gp16()
.ccmr_input(raw_channel / 2) .ccmr_input(raw_channel / 2)
.modify(|r| r.set_icf(raw_channel % 2, icf)); .modify(|r| r.set_icf(raw_channel % 2, icf));
} }
/// Clear input interrupt.
fn clear_input_interrupt(&mut self, channel: Channel) { fn clear_input_interrupt(&mut self, channel: Channel) {
Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.raw(), false)); Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false));
} }
/// Enable input interrupt.
fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) {
Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.raw(), enable)); Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable));
} }
/// Set input capture prescaler.
fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) {
let raw_channel = channel.raw(); let raw_channel = channel.index();
Self::regs_gp16() Self::regs_gp16()
.ccmr_input(raw_channel / 2) .ccmr_input(raw_channel / 2)
.modify(|r| r.set_icpsc(raw_channel % 2, factor)); .modify(|r| r.set_icpsc(raw_channel % 2, factor));
} }
/// Set input TI selection.
fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) {
let raw_channel = channel.raw(); let raw_channel = channel.index();
Self::regs_gp16() Self::regs_gp16()
.ccmr_input(raw_channel / 2) .ccmr_input(raw_channel / 2)
.modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); .modify(|r| r.set_ccs(raw_channel % 2, tisel.into()));
} }
/// Set input capture mode.
fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) {
Self::regs_gp16().ccer().modify(|r| match mode { Self::regs_gp16().ccer().modify(|r| match mode {
InputCaptureMode::Rising => { InputCaptureMode::Rising => {
r.set_ccnp(channel.raw(), false); r.set_ccnp(channel.index(), false);
r.set_ccp(channel.raw(), false); r.set_ccp(channel.index(), false);
} }
InputCaptureMode::Falling => { InputCaptureMode::Falling => {
r.set_ccnp(channel.raw(), false); r.set_ccnp(channel.index(), false);
r.set_ccp(channel.raw(), true); r.set_ccp(channel.index(), true);
} }
InputCaptureMode::BothEdges => { InputCaptureMode::BothEdges => {
r.set_ccnp(channel.raw(), true); r.set_ccnp(channel.index(), true);
r.set_ccp(channel.raw(), true); r.set_ccp(channel.index(), true);
} }
}); });
} }
/// Enable timer outputs.
fn enable_outputs(&mut self); fn enable_outputs(&mut self);
/// Set output compare mode.
fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) {
let r = Self::regs_gp16(); let r = Self::regs_gp16();
let raw_channel: usize = channel.raw(); let raw_channel: usize = channel.index();
r.ccmr_output(raw_channel / 2) r.ccmr_output(raw_channel / 2)
.modify(|w| w.set_ocm(raw_channel % 2, mode.into())); .modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
} }
/// Set output polarity.
fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
Self::regs_gp16() Self::regs_gp16()
.ccer() .ccer()
.modify(|w| w.set_ccp(channel.raw(), polarity.into())); .modify(|w| w.set_ccp(channel.index(), polarity.into()));
} }
/// Enable/disable a channel.
fn enable_channel(&mut self, channel: Channel, enable: bool) { fn enable_channel(&mut self, channel: Channel, enable: bool) {
Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.raw(), enable)); Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable));
} }
/// Set compare value for a channel.
fn set_compare_value(&mut self, channel: Channel, value: u16) { fn set_compare_value(&mut self, channel: Channel, value: u16) {
Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value)); Self::regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value));
} }
/// Get capture value for a channel.
fn get_capture_value(&mut self, channel: Channel) -> u16 { fn get_capture_value(&mut self, channel: Channel) -> u16 {
Self::regs_gp16().ccr(channel.raw()).read().ccr() Self::regs_gp16().ccr(channel.index()).read().ccr()
} }
/// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
fn get_max_compare_value(&self) -> u16 { fn get_max_compare_value(&self) -> u16 {
Self::regs_gp16().arr().read().arr() Self::regs_gp16().arr().read().arr()
} }
/// Get compare value for a channel.
fn get_compare_value(&self, channel: Channel) -> u16 { fn get_compare_value(&self, channel: Channel) -> u16 {
Self::regs_gp16().ccr(channel.raw()).read().ccr() Self::regs_gp16().ccr(channel.index()).read().ccr()
} }
} }
/// Capture/Compare 16-bit timer instance with complementary pin support.
pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance { pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance {
/// Set complementary output polarity.
fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
Self::regs_advanced() Self::regs_advanced()
.ccer() .ccer()
.modify(|w| w.set_ccnp(channel.raw(), polarity.into())); .modify(|w| w.set_ccnp(channel.index(), polarity.into()));
} }
/// Set clock divider for the dead time.
fn set_dead_time_clock_division(&mut self, value: vals::Ckd) { fn set_dead_time_clock_division(&mut self, value: vals::Ckd) {
Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); Self::regs_advanced().cr1().modify(|w| w.set_ckd(value));
} }
/// Set dead time, as a fraction of the max duty value.
fn set_dead_time_value(&mut self, value: u8) { fn set_dead_time_value(&mut self, value: u8) {
Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value));
} }
/// Enable/disable a complementary channel.
fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) {
Self::regs_advanced() Self::regs_advanced()
.ccer() .ccer()
.modify(|w| w.set_ccne(channel.raw(), enable)); .modify(|w| w.set_ccne(channel.index(), enable));
} }
} }
/// Capture/Compare 32-bit timer instance.
pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance + CaptureCompare16bitInstance { pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance + CaptureCompare16bitInstance {
/// Set comapre value for a channel.
fn set_compare_value(&mut self, channel: Channel, value: u32) { fn set_compare_value(&mut self, channel: Channel, value: u32) {
Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value)); Self::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(value));
} }
/// Get capture value for a channel.
fn get_capture_value(&mut self, channel: Channel) -> u32 { fn get_capture_value(&mut self, channel: Channel) -> u32 {
Self::regs_gp32().ccr(channel.raw()).read().ccr() Self::regs_gp32().ccr(channel.index()).read().ccr()
} }
/// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
fn get_max_compare_value(&self) -> u32 { fn get_max_compare_value(&self) -> u32 {
Self::regs_gp32().arr().read().arr() Self::regs_gp32().arr().read().arr()
} }
/// Get compare value for a channel.
fn get_compare_value(&self, channel: Channel) -> u32 { fn get_compare_value(&self, channel: Channel) -> u32 {
Self::regs_gp32().ccr(channel.raw()).read().ccr() Self::regs_gp32().ccr(channel.index()).read().ccr()
} }
} }
} }
/// Timer channel.
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum Channel { pub enum Channel {
/// Channel 1.
Ch1, Ch1,
/// Channel 2.
Ch2, Ch2,
/// Channel 3.
Ch3, Ch3,
/// Channel 4.
Ch4, Ch4,
} }
impl Channel { impl Channel {
pub fn raw(&self) -> usize { /// Get the channel index (0..3)
pub fn index(&self) -> usize {
match self { match self {
Channel::Ch1 => 0, Channel::Ch1 => 0,
Channel::Ch2 => 1, Channel::Ch2 => 1,
@ -295,17 +366,25 @@ impl Channel {
} }
} }
/// Input capture mode.
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum InputCaptureMode { pub enum InputCaptureMode {
/// Rising edge only.
Rising, Rising,
/// Falling edge only.
Falling, Falling,
/// Both rising or falling edges.
BothEdges, BothEdges,
} }
/// Input TI selection.
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum InputTISelection { pub enum InputTISelection {
/// Normal
Normal, Normal,
/// Alternate
Alternate, Alternate,
/// TRC
TRC, TRC,
} }
@ -319,6 +398,7 @@ impl From<InputTISelection> for stm32_metapac::timer::vals::CcmrInputCcs {
} }
} }
/// Timer counting mode.
#[repr(u8)] #[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum CountingMode { pub enum CountingMode {
@ -345,6 +425,7 @@ pub enum CountingMode {
} }
impl CountingMode { impl CountingMode {
/// Return whether this mode is edge-aligned (up or down).
pub fn is_edge_aligned(&self) -> bool { pub fn is_edge_aligned(&self) -> bool {
match self { match self {
CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown => true, CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown => true,
@ -352,6 +433,7 @@ impl CountingMode {
} }
} }
/// Return whether this mode is center-aligned.
pub fn is_center_aligned(&self) -> bool { pub fn is_center_aligned(&self) -> bool {
match self { match self {
CountingMode::CenterAlignedDownInterrupts CountingMode::CenterAlignedDownInterrupts
@ -386,16 +468,34 @@ impl From<(vals::Cms, vals::Dir)> for CountingMode {
} }
} }
/// Output compare mode.
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum OutputCompareMode { pub enum OutputCompareMode {
/// The comparison between the output compare register TIMx_CCRx and
/// the counter TIMx_CNT has no effect on the outputs.
/// (this mode is used to generate a timing base).
Frozen, Frozen,
/// Set channel to active level on match. OCxREF signal is forced high when the
/// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx).
ActiveOnMatch, ActiveOnMatch,
/// Set channel to inactive level on match. OCxREF signal is forced low when the
/// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx).
InactiveOnMatch, InactiveOnMatch,
/// Toggle - OCxREF toggles when TIMx_CNT=TIMx_CCRx.
Toggle, Toggle,
/// Force inactive level - OCxREF is forced low.
ForceInactive, ForceInactive,
/// Force active level - OCxREF is forced high.
ForceActive, ForceActive,
/// PWM mode 1 - In upcounting, channel is active as long as TIMx_CNT<TIMx_CCRx
/// else inactive. In downcounting, channel is inactive (OCxREF=0) as long as
/// TIMx_CNT>TIMx_CCRx else active (OCxREF=1).
PwmMode1, PwmMode1,
/// PWM mode 2 - In upcounting, channel is inactive as long as
/// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as
/// TIMx_CNT>TIMx_CCRx else inactive.
PwmMode2, PwmMode2,
// TODO: there's more modes here depending on the chip family.
} }
impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm {
@ -413,9 +513,12 @@ impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm {
} }
} }
/// Timer output pin polarity.
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum OutputPolarity { pub enum OutputPolarity {
/// Active high (higher duty value makes the pin spend more time high).
ActiveHigh, ActiveHigh,
/// Active low (higher duty value makes the pin spend more time low).
ActiveLow, ActiveLow,
} }
@ -428,24 +531,31 @@ impl From<OutputPolarity> for bool {
} }
} }
/// Basic 16-bit timer instance.
pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {}
/// Gneral-purpose 16-bit timer instance.
pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {} pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {}
/// Gneral-purpose 32-bit timer instance.
pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {} pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {}
/// Advanced control timer instance.
pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {} pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {}
/// Capture/Compare 16-bit timer instance.
pub trait CaptureCompare16bitInstance: pub trait CaptureCompare16bitInstance:
sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static
{ {
} }
/// Capture/Compare 16-bit timer instance with complementary pin support.
pub trait ComplementaryCaptureCompare16bitInstance: pub trait ComplementaryCaptureCompare16bitInstance:
sealed::ComplementaryCaptureCompare16bitInstance + AdvancedControlInstance + 'static sealed::ComplementaryCaptureCompare16bitInstance + AdvancedControlInstance + 'static
{ {
} }
/// Capture/Compare 32-bit timer instance.
pub trait CaptureCompare32bitInstance: pub trait CaptureCompare32bitInstance:
sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static
{ {

View File

@ -9,23 +9,30 @@ use crate::gpio::sealed::AFType;
use crate::gpio::AnyPin; use crate::gpio::AnyPin;
use crate::Peripheral; use crate::Peripheral;
/// Counting direction
pub enum Direction { pub enum Direction {
/// Counting up.
Upcounting, Upcounting,
/// Counting down.
Downcounting, Downcounting,
} }
pub struct Ch1; /// Channel 1 marker type.
pub struct Ch2; pub enum Ch1 {}
/// Channel 2 marker type.
pub enum Ch2 {}
pub struct QeiPin<'d, Perip, Channel> { /// Wrapper for using a pin with QEI.
pub struct QeiPin<'d, T, Channel> {
_pin: PeripheralRef<'d, AnyPin>, _pin: PeripheralRef<'d, AnyPin>,
phantom: PhantomData<(Perip, Channel)>, phantom: PhantomData<(T, Channel)>,
} }
macro_rules! channel_impl { macro_rules! channel_impl {
($new_chx:ident, $channel:ident, $pin_trait:ident) => { ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
impl<'d, Perip: CaptureCompare16bitInstance> QeiPin<'d, Perip, $channel> { impl<'d, T: CaptureCompare16bitInstance> QeiPin<'d, T, $channel> {
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self { #[doc = concat!("Create a new ", stringify!($channel), " QEI pin instance.")]
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd) -> Self {
into_ref!(pin); into_ref!(pin);
critical_section::with(|_| { critical_section::with(|_| {
pin.set_low(); pin.set_low();
@ -45,11 +52,13 @@ macro_rules! channel_impl {
channel_impl!(new_ch1, Ch1, Channel1Pin); channel_impl!(new_ch1, Ch1, Channel1Pin);
channel_impl!(new_ch2, Ch2, Channel2Pin); channel_impl!(new_ch2, Ch2, Channel2Pin);
/// Quadrature decoder driver.
pub struct Qei<'d, T> { pub struct Qei<'d, T> {
_inner: PeripheralRef<'d, T>, _inner: PeripheralRef<'d, T>,
} }
impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> {
/// Create a new quadrature decoder driver.
pub fn new(tim: impl Peripheral<P = T> + 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { pub fn new(tim: impl Peripheral<P = T> + 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self {
Self::new_inner(tim) Self::new_inner(tim)
} }
@ -84,6 +93,7 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> {
Self { _inner: tim } Self { _inner: tim }
} }
/// Get direction.
pub fn read_direction(&self) -> Direction { pub fn read_direction(&self) -> Direction {
match T::regs_gp16().cr1().read().dir() { match T::regs_gp16().cr1().read().dir() {
vals::Dir::DOWN => Direction::Downcounting, vals::Dir::DOWN => Direction::Downcounting,
@ -91,6 +101,7 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> {
} }
} }
/// Get count.
pub fn count(&self) -> u16 { pub fn count(&self) -> u16 {
T::regs_gp16().cnt().read().cnt() T::regs_gp16().cnt().read().cnt()
} }

View File

@ -11,20 +11,28 @@ use crate::gpio::{AnyPin, OutputType};
use crate::time::Hertz; use crate::time::Hertz;
use crate::Peripheral; use crate::Peripheral;
pub struct Ch1; /// Channel 1 marker type.
pub struct Ch2; pub enum Ch1 {}
pub struct Ch3; /// Channel 2 marker type.
pub struct Ch4; pub enum Ch2 {}
/// Channel 3 marker type.
pub enum Ch3 {}
/// Channel 4 marker type.
pub enum Ch4 {}
pub struct PwmPin<'d, Perip, Channel> { /// PWM pin wrapper.
///
/// This wraps a pin to make it usable with PWM.
pub struct PwmPin<'d, T, C> {
_pin: PeripheralRef<'d, AnyPin>, _pin: PeripheralRef<'d, AnyPin>,
phantom: PhantomData<(Perip, Channel)>, phantom: PhantomData<(T, C)>,
} }
macro_rules! channel_impl { macro_rules! channel_impl {
($new_chx:ident, $channel:ident, $pin_trait:ident) => { ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> { impl<'d, T: CaptureCompare16bitInstance> PwmPin<'d, T, $channel> {
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd, output_type: OutputType) -> Self { #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")]
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self {
into_ref!(pin); into_ref!(pin);
critical_section::with(|_| { critical_section::with(|_| {
pin.set_low(); pin.set_low();
@ -46,11 +54,13 @@ channel_impl!(new_ch2, Ch2, Channel2Pin);
channel_impl!(new_ch3, Ch3, Channel3Pin); channel_impl!(new_ch3, Ch3, Channel3Pin);
channel_impl!(new_ch4, Ch4, Channel4Pin); channel_impl!(new_ch4, Ch4, Channel4Pin);
/// Simple PWM driver.
pub struct SimplePwm<'d, T> { pub struct SimplePwm<'d, T> {
inner: PeripheralRef<'d, T>, inner: PeripheralRef<'d, T>,
} }
impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
/// Create a new simple PWM driver.
pub fn new( pub fn new(
tim: impl Peripheral<P = T> + 'd, tim: impl Peripheral<P = T> + 'd,
_ch1: Option<PwmPin<'d, T, Ch1>>, _ch1: Option<PwmPin<'d, T, Ch1>>,
@ -71,7 +81,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
let mut this = Self { inner: tim }; let mut this = Self { inner: tim };
this.inner.set_counting_mode(counting_mode); this.inner.set_counting_mode(counting_mode);
this.set_freq(freq); this.set_frequency(freq);
this.inner.start(); this.inner.start();
this.inner.enable_outputs(); this.inner.enable_outputs();
@ -87,15 +97,21 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
this this
} }
/// Enable the given channel.
pub fn enable(&mut self, channel: Channel) { pub fn enable(&mut self, channel: Channel) {
self.inner.enable_channel(channel, true); self.inner.enable_channel(channel, true);
} }
/// Disable the given channel.
pub fn disable(&mut self, channel: Channel) { pub fn disable(&mut self, channel: Channel) {
self.inner.enable_channel(channel, false); self.inner.enable_channel(channel, false);
} }
pub fn set_freq(&mut self, freq: Hertz) { /// Set PWM frequency.
///
/// Note: when you call this, the max duty value changes, so you will have to
/// call `set_duty` on all channels with the duty calculated based on the new max duty.
pub fn set_frequency(&mut self, freq: Hertz) {
let multiplier = if self.inner.get_counting_mode().is_center_aligned() { let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
2u8 2u8
} else { } else {
@ -104,15 +120,22 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
self.inner.set_frequency(freq * multiplier); self.inner.set_frequency(freq * multiplier);
} }
/// Get max duty value.
///
/// This value depends on the configured frequency and the timer's clock rate from RCC.
pub fn get_max_duty(&self) -> u16 { pub fn get_max_duty(&self) -> u16 {
self.inner.get_max_compare_value() + 1 self.inner.get_max_compare_value() + 1
} }
/// Set the duty for a given channel.
///
/// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
pub fn set_duty(&mut self, channel: Channel, duty: u16) { pub fn set_duty(&mut self, channel: Channel, duty: u16) {
assert!(duty <= self.get_max_duty()); assert!(duty <= self.get_max_duty());
self.inner.set_compare_value(channel, duty) self.inner.set_compare_value(channel, duty)
} }
/// Set the output polarity for a given channel.
pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
self.inner.set_output_polarity(channel, polarity); self.inner.set_output_polarity(channel, polarity);
} }

View File

@ -82,6 +82,7 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt
} }
} }
/// Buffered UART State
pub struct State { pub struct State {
rx_waker: AtomicWaker, rx_waker: AtomicWaker,
rx_buf: RingBuffer, rx_buf: RingBuffer,
@ -91,6 +92,7 @@ pub struct State {
} }
impl State { impl State {
/// Create new state
pub const fn new() -> Self { pub const fn new() -> Self {
Self { Self {
rx_buf: RingBuffer::new(), rx_buf: RingBuffer::new(),
@ -101,15 +103,18 @@ impl State {
} }
} }
/// Bidirectional buffered UART
pub struct BufferedUart<'d, T: BasicInstance> { pub struct BufferedUart<'d, T: BasicInstance> {
rx: BufferedUartRx<'d, T>, rx: BufferedUartRx<'d, T>,
tx: BufferedUartTx<'d, T>, tx: BufferedUartTx<'d, T>,
} }
/// Tx-only buffered UART
pub struct BufferedUartTx<'d, T: BasicInstance> { pub struct BufferedUartTx<'d, T: BasicInstance> {
phantom: PhantomData<&'d mut T>, phantom: PhantomData<&'d mut T>,
} }
/// Rx-only buffered UART
pub struct BufferedUartRx<'d, T: BasicInstance> { pub struct BufferedUartRx<'d, T: BasicInstance> {
phantom: PhantomData<&'d mut T>, phantom: PhantomData<&'d mut T>,
} }
@ -142,6 +147,7 @@ impl<'d, T: BasicInstance> SetConfig for BufferedUartTx<'d, T> {
} }
impl<'d, T: BasicInstance> BufferedUart<'d, T> { impl<'d, T: BasicInstance> BufferedUart<'d, T> {
/// Create a new bidirectional buffered UART driver
pub fn new( pub fn new(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@ -158,6 +164,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
} }
/// Create a new bidirectional buffered UART driver with request-to-send and clear-to-send pins
pub fn new_with_rtscts( pub fn new_with_rtscts(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@ -185,6 +192,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
} }
/// Create a new bidirectional buffered UART driver with a driver-enable pin
#[cfg(not(any(usart_v1, usart_v2)))] #[cfg(not(any(usart_v1, usart_v2)))]
pub fn new_with_de( pub fn new_with_de(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
@ -246,10 +254,12 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> {
}) })
} }
/// Split the driver into a Tx and Rx part (useful for sending to separate tasks)
pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) { pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) {
(self.tx, self.rx) (self.tx, self.rx)
} }
/// Reconfigure the driver
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config)?; reconfigure::<T>(config)?;
@ -337,6 +347,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> {
} }
} }
/// Reconfigure the driver
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config)?; reconfigure::<T>(config)?;
@ -418,6 +429,7 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> {
} }
} }
/// Reconfigure the driver
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config)?; reconfigure::<T>(config)?;

View File

@ -1,5 +1,6 @@
//! Universal Synchronous/Asynchronous Receiver Transmitter (USART, UART, LPUART) //! Universal Synchronous/Asynchronous Receiver Transmitter (USART, UART, LPUART)
#![macro_use] #![macro_use]
#![warn(missing_docs)]
use core::future::poll_fn; use core::future::poll_fn;
use core::marker::PhantomData; use core::marker::PhantomData;
@ -77,21 +78,29 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt
#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Number of data bits
pub enum DataBits { pub enum DataBits {
/// 8 Data Bits
DataBits8, DataBits8,
/// 9 Data Bits
DataBits9, DataBits9,
} }
#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Parity
pub enum Parity { pub enum Parity {
/// No parity
ParityNone, ParityNone,
/// Even Parity
ParityEven, ParityEven,
/// Odd Parity
ParityOdd, ParityOdd,
} }
#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Number of stop bits
pub enum StopBits { pub enum StopBits {
#[doc = "1 stop bit"] #[doc = "1 stop bit"]
STOP1, STOP1,
@ -106,26 +115,37 @@ pub enum StopBits {
#[non_exhaustive] #[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Config Error
pub enum ConfigError { pub enum ConfigError {
/// Baudrate too low
BaudrateTooLow, BaudrateTooLow,
/// Baudrate too high
BaudrateTooHigh, BaudrateTooHigh,
/// Rx or Tx not enabled
RxOrTxNotEnabled, RxOrTxNotEnabled,
} }
#[non_exhaustive] #[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]
/// Config
pub struct Config { pub struct Config {
/// Baud rate
pub baudrate: u32, pub baudrate: u32,
/// Number of data bits
pub data_bits: DataBits, pub data_bits: DataBits,
/// Number of stop bits
pub stop_bits: StopBits, pub stop_bits: StopBits,
/// Parity type
pub parity: Parity, pub parity: Parity,
/// if true, on read-like method, if there is a latent error pending,
/// read will abort, the error reported and cleared /// If true: on a read-like method, if there is a latent error pending,
/// if false, the error is ignored and cleared /// the read will abort and the error will be reported and cleared
///
/// If false: the error is ignored and cleared
pub detect_previous_overrun: bool, pub detect_previous_overrun: bool,
/// Set this to true if the line is considered noise free. /// Set this to true if the line is considered noise free.
/// This will increase the receivers tolerance to clock deviations, /// This will increase the receivers tolerance to clock deviations,
/// but will effectively disable noise detection. /// but will effectively disable noise detection.
#[cfg(not(usart_v1))] #[cfg(not(usart_v1))]
pub assume_noise_free: bool, pub assume_noise_free: bool,
@ -188,6 +208,7 @@ enum ReadCompletionEvent {
Idle(usize), Idle(usize),
} }
/// Bidirectional UART Driver
pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> { pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> {
tx: UartTx<'d, T, TxDma>, tx: UartTx<'d, T, TxDma>,
rx: UartRx<'d, T, RxDma>, rx: UartRx<'d, T, RxDma>,
@ -203,6 +224,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> SetConfig for Uart<'d, T, TxDma, RxDma>
} }
} }
/// Tx-only UART Driver
pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> { pub struct UartTx<'d, T: BasicInstance, TxDma = NoDma> {
phantom: PhantomData<&'d mut T>, phantom: PhantomData<&'d mut T>,
tx_dma: PeripheralRef<'d, TxDma>, tx_dma: PeripheralRef<'d, TxDma>,
@ -217,6 +239,7 @@ impl<'d, T: BasicInstance, TxDma> SetConfig for UartTx<'d, T, TxDma> {
} }
} }
/// Rx-only UART Driver
pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> { pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> {
_peri: PeripheralRef<'d, T>, _peri: PeripheralRef<'d, T>,
rx_dma: PeripheralRef<'d, RxDma>, rx_dma: PeripheralRef<'d, RxDma>,
@ -247,6 +270,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
Self::new_inner(peri, tx, tx_dma, config) Self::new_inner(peri, tx, tx_dma, config)
} }
/// Create a new tx-only UART with a clear-to-send pin
pub fn new_with_cts( pub fn new_with_cts(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd, tx: impl Peripheral<P = impl TxPin<T>> + 'd,
@ -288,10 +312,12 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
}) })
} }
/// Reconfigure the driver
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config) reconfigure::<T>(config)
} }
/// Initiate an asynchronous UART write
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error>
where where
TxDma: crate::usart::TxDma<T>, TxDma: crate::usart::TxDma<T>,
@ -308,6 +334,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
Ok(()) Ok(())
} }
/// Perform a blocking UART write
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
let r = T::regs(); let r = T::regs();
for &b in buffer { for &b in buffer {
@ -317,6 +344,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
Ok(()) Ok(())
} }
/// Block until transmission complete
pub fn blocking_flush(&mut self) -> Result<(), Error> { pub fn blocking_flush(&mut self) -> Result<(), Error> {
let r = T::regs(); let r = T::regs();
while !sr(r).read().tc() {} while !sr(r).read().tc() {}
@ -338,6 +366,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
Self::new_inner(peri, rx, rx_dma, config) Self::new_inner(peri, rx, rx_dma, config)
} }
/// Create a new rx-only UART with a request-to-send pin
pub fn new_with_rts( pub fn new_with_rts(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@ -387,6 +416,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
}) })
} }
/// Reconfigure the driver
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config) reconfigure::<T>(config)
} }
@ -444,6 +474,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
Ok(sr.rxne()) Ok(sr.rxne())
} }
/// Initiate an asynchronous UART read
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error>
where where
RxDma: crate::usart::RxDma<T>, RxDma: crate::usart::RxDma<T>,
@ -453,6 +484,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
Ok(()) Ok(())
} }
/// Read a single u8 if there is one available, otherwise return WouldBlock
pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> { pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
let r = T::regs(); let r = T::regs();
if self.check_rx_flags()? { if self.check_rx_flags()? {
@ -462,6 +494,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
} }
} }
/// Perform a blocking read into `buffer`
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
let r = T::regs(); let r = T::regs();
for b in buffer { for b in buffer {
@ -471,6 +504,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
Ok(()) Ok(())
} }
/// Initiate an asynchronous read with idle line detection enabled
pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error>
where where
RxDma: crate::usart::RxDma<T>, RxDma: crate::usart::RxDma<T>,
@ -695,6 +729,7 @@ impl<'d, T: BasicInstance, TxDma> Drop for UartRx<'d, T, TxDma> {
} }
impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
/// Create a new bidirectional UART
pub fn new( pub fn new(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd, rx: impl Peripheral<P = impl RxPin<T>> + 'd,
@ -711,6 +746,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config)
} }
/// Create a new bidirectional UART with request-to-send and clear-to-send pins
pub fn new_with_rtscts( pub fn new_with_rtscts(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd, rx: impl Peripheral<P = impl RxPin<T>> + 'd,
@ -738,6 +774,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
} }
#[cfg(not(any(usart_v1, usart_v2)))] #[cfg(not(any(usart_v1, usart_v2)))]
/// Create a new bidirectional UART with a driver-enable pin
pub fn new_with_de( pub fn new_with_de(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd, rx: impl Peripheral<P = impl RxPin<T>> + 'd,
@ -813,6 +850,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
}) })
} }
/// Initiate an asynchronous write
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error>
where where
TxDma: crate::usart::TxDma<T>, TxDma: crate::usart::TxDma<T>,
@ -820,14 +858,17 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
self.tx.write(buffer).await self.tx.write(buffer).await
} }
/// Perform a blocking write
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> { pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
self.tx.blocking_write(buffer) self.tx.blocking_write(buffer)
} }
/// Block until transmission complete
pub fn blocking_flush(&mut self) -> Result<(), Error> { pub fn blocking_flush(&mut self) -> Result<(), Error> {
self.tx.blocking_flush() self.tx.blocking_flush()
} }
/// Initiate an asynchronous read into `buffer`
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error>
where where
RxDma: crate::usart::RxDma<T>, RxDma: crate::usart::RxDma<T>,
@ -835,14 +876,17 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
self.rx.read(buffer).await self.rx.read(buffer).await
} }
/// Read a single `u8` or return `WouldBlock`
pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> { pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
self.rx.nb_read() self.rx.nb_read()
} }
/// Perform a blocking read into `buffer`
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
self.rx.blocking_read(buffer) self.rx.blocking_read(buffer)
} }
/// Initiate an an asynchronous read with idle line detection enabled
pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error>
where where
RxDma: crate::usart::RxDma<T>, RxDma: crate::usart::RxDma<T>,
@ -1292,8 +1336,10 @@ pub(crate) mod sealed {
} }
} }
/// Basic UART driver instance
pub trait BasicInstance: Peripheral<P = Self> + sealed::BasicInstance + 'static + Send {} pub trait BasicInstance: Peripheral<P = Self> + sealed::BasicInstance + 'static + Send {}
/// Full UART driver instance
pub trait FullInstance: sealed::FullInstance {} pub trait FullInstance: sealed::FullInstance {}
pin_trait!(RxPin, BasicInstance); pin_trait!(RxPin, BasicInstance);

View File

@ -11,6 +11,7 @@ use super::{clear_interrupt_flags, rdr, reconfigure, sr, BasicInstance, Config,
use crate::dma::ReadableRingBuffer; use crate::dma::ReadableRingBuffer;
use crate::usart::{Regs, Sr}; use crate::usart::{Regs, Sr};
/// Rx-only Ring-buffered UART Driver
pub struct RingBufferedUartRx<'d, T: BasicInstance, RxDma: super::RxDma<T>> { pub struct RingBufferedUartRx<'d, T: BasicInstance, RxDma: super::RxDma<T>> {
_peri: PeripheralRef<'d, T>, _peri: PeripheralRef<'d, T>,
ring_buf: ReadableRingBuffer<'d, RxDma, u8>, ring_buf: ReadableRingBuffer<'d, RxDma, u8>,
@ -27,8 +28,8 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> SetConfig for RingBufferedUar
impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> { impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> {
/// Turn the `UartRx` into a buffered uart which can continously receive in the background /// Turn the `UartRx` into a buffered uart which can continously receive in the background
/// without the possibility of loosing bytes. The `dma_buf` is a buffer registered to the /// without the possibility of losing bytes. The `dma_buf` is a buffer registered to the
/// DMA controller, and must be sufficiently large, such that it will not overflow. /// DMA controller, and must be large enough to prevent overflows.
pub fn into_ring_buffered(self, dma_buf: &'d mut [u8]) -> RingBufferedUartRx<'d, T, RxDma> { pub fn into_ring_buffered(self, dma_buf: &'d mut [u8]) -> RingBufferedUartRx<'d, T, RxDma> {
assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
@ -49,6 +50,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> UartRx<'d, T, RxDma> {
} }
impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxDma> { impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxDma> {
/// Clear the ring buffer and start receiving in the background
pub fn start(&mut self) -> Result<(), Error> { pub fn start(&mut self) -> Result<(), Error> {
// Clear the ring buffer so that it is ready to receive data // Clear the ring buffer so that it is ready to receive data
self.ring_buf.clear(); self.ring_buf.clear();
@ -64,6 +66,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
Err(err) Err(err)
} }
/// Cleanly stop and reconfigure the driver
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
self.teardown_uart(); self.teardown_uart();
reconfigure::<T>(config) reconfigure::<T>(config)

View File

@ -1,3 +1,5 @@
//! Universal Serial Bus (USB)
use crate::interrupt; use crate::interrupt;
use crate::rcc::RccPeripheral; use crate::rcc::RccPeripheral;
@ -10,7 +12,9 @@ pub(crate) mod sealed {
} }
} }
/// USB instance trait.
pub trait Instance: sealed::Instance + RccPeripheral + 'static { pub trait Instance: sealed::Instance + RccPeripheral + 'static {
/// Interrupt for this USB instance.
type Interrupt: interrupt::typelevel::Interrupt; type Interrupt: interrupt::typelevel::Interrupt;
} }

View File

@ -244,6 +244,7 @@ struct EndpointData {
used_out: bool, used_out: bool,
} }
/// USB driver.
pub struct Driver<'d, T: Instance> { pub struct Driver<'d, T: Instance> {
phantom: PhantomData<&'d mut T>, phantom: PhantomData<&'d mut T>,
alloc: [EndpointData; EP_COUNT], alloc: [EndpointData; EP_COUNT],
@ -251,6 +252,7 @@ pub struct Driver<'d, T: Instance> {
} }
impl<'d, T: Instance> Driver<'d, T> { impl<'d, T: Instance> Driver<'d, T> {
/// Create a new USB driver.
pub fn new( pub fn new(
_usb: impl Peripheral<P = T> + 'd, _usb: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@ -465,6 +467,7 @@ impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
} }
} }
/// USB bus.
pub struct Bus<'d, T: Instance> { pub struct Bus<'d, T: Instance> {
phantom: PhantomData<&'d mut T>, phantom: PhantomData<&'d mut T>,
ep_types: [EpType; EP_COUNT - 1], ep_types: [EpType; EP_COUNT - 1],
@ -640,6 +643,7 @@ trait Dir {
fn waker(i: usize) -> &'static AtomicWaker; fn waker(i: usize) -> &'static AtomicWaker;
} }
/// Marker type for the "IN" direction.
pub enum In {} pub enum In {}
impl Dir for In { impl Dir for In {
fn dir() -> Direction { fn dir() -> Direction {
@ -652,6 +656,7 @@ impl Dir for In {
} }
} }
/// Marker type for the "OUT" direction.
pub enum Out {} pub enum Out {}
impl Dir for Out { impl Dir for Out {
fn dir() -> Direction { fn dir() -> Direction {
@ -664,6 +669,7 @@ impl Dir for Out {
} }
} }
/// USB endpoint.
pub struct Endpoint<'d, T: Instance, D> { pub struct Endpoint<'d, T: Instance, D> {
_phantom: PhantomData<(&'d mut T, D)>, _phantom: PhantomData<(&'d mut T, D)>,
info: EndpointInfo, info: EndpointInfo,
@ -813,6 +819,7 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
} }
} }
/// USB control pipe.
pub struct ControlPipe<'d, T: Instance> { pub struct ControlPipe<'d, T: Instance> {
_phantom: PhantomData<&'d mut T>, _phantom: PhantomData<&'d mut T>,
max_packet_size: u16, max_packet_size: u16,

View File

@ -20,7 +20,9 @@ pub(crate) mod sealed {
} }
} }
/// USB OTG instance.
pub trait Instance: sealed::Instance + RccPeripheral { pub trait Instance: sealed::Instance + RccPeripheral {
/// Interrupt for this USB OTG instance.
type Interrupt: interrupt::typelevel::Interrupt; type Interrupt: interrupt::typelevel::Interrupt;
} }

View File

@ -204,6 +204,7 @@ pub enum PhyType {
} }
impl PhyType { impl PhyType {
/// Get whether this PHY is any of the internal types.
pub fn internal(&self) -> bool { pub fn internal(&self) -> bool {
match self { match self {
PhyType::InternalFullSpeed | PhyType::InternalHighSpeed => true, PhyType::InternalFullSpeed | PhyType::InternalHighSpeed => true,
@ -211,6 +212,7 @@ impl PhyType {
} }
} }
/// Get whether this PHY is any of the high-speed types.
pub fn high_speed(&self) -> bool { pub fn high_speed(&self) -> bool {
match self { match self {
PhyType::InternalFullSpeed => false, PhyType::InternalFullSpeed => false,
@ -218,7 +220,7 @@ impl PhyType {
} }
} }
pub fn to_dspd(&self) -> vals::Dspd { fn to_dspd(&self) -> vals::Dspd {
match self { match self {
PhyType::InternalFullSpeed => vals::Dspd::FULL_SPEED_INTERNAL, PhyType::InternalFullSpeed => vals::Dspd::FULL_SPEED_INTERNAL,
PhyType::InternalHighSpeed => vals::Dspd::HIGH_SPEED, PhyType::InternalHighSpeed => vals::Dspd::HIGH_SPEED,
@ -230,6 +232,7 @@ impl PhyType {
/// Indicates that [State::ep_out_buffers] is empty. /// Indicates that [State::ep_out_buffers] is empty.
const EP_OUT_BUFFER_EMPTY: u16 = u16::MAX; const EP_OUT_BUFFER_EMPTY: u16 = u16::MAX;
/// USB OTG driver state.
pub struct State<const EP_COUNT: usize> { pub struct State<const EP_COUNT: usize> {
/// Holds received SETUP packets. Available if [State::ep0_setup_ready] is true. /// Holds received SETUP packets. Available if [State::ep0_setup_ready] is true.
ep0_setup_data: UnsafeCell<[u8; 8]>, ep0_setup_data: UnsafeCell<[u8; 8]>,
@ -247,6 +250,7 @@ unsafe impl<const EP_COUNT: usize> Send for State<EP_COUNT> {}
unsafe impl<const EP_COUNT: usize> Sync for State<EP_COUNT> {} unsafe impl<const EP_COUNT: usize> Sync for State<EP_COUNT> {}
impl<const EP_COUNT: usize> State<EP_COUNT> { impl<const EP_COUNT: usize> State<EP_COUNT> {
/// Create a new State.
pub const fn new() -> Self { pub const fn new() -> Self {
const NEW_AW: AtomicWaker = AtomicWaker::new(); const NEW_AW: AtomicWaker = AtomicWaker::new();
const NEW_BUF: UnsafeCell<*mut u8> = UnsafeCell::new(0 as _); const NEW_BUF: UnsafeCell<*mut u8> = UnsafeCell::new(0 as _);
@ -271,6 +275,7 @@ struct EndpointData {
fifo_size_words: u16, fifo_size_words: u16,
} }
/// USB driver config.
#[non_exhaustive] #[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Config { pub struct Config {
@ -297,6 +302,7 @@ impl Default for Config {
} }
} }
/// USB driver.
pub struct Driver<'d, T: Instance> { pub struct Driver<'d, T: Instance> {
config: Config, config: Config,
phantom: PhantomData<&'d mut T>, phantom: PhantomData<&'d mut T>,
@ -527,6 +533,7 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> {
} }
} }
/// USB bus.
pub struct Bus<'d, T: Instance> { pub struct Bus<'d, T: Instance> {
config: Config, config: Config,
phantom: PhantomData<&'d mut T>, phantom: PhantomData<&'d mut T>,
@ -1092,6 +1099,7 @@ trait Dir {
fn dir() -> Direction; fn dir() -> Direction;
} }
/// Marker type for the "IN" direction.
pub enum In {} pub enum In {}
impl Dir for In { impl Dir for In {
fn dir() -> Direction { fn dir() -> Direction {
@ -1099,6 +1107,7 @@ impl Dir for In {
} }
} }
/// Marker type for the "OUT" direction.
pub enum Out {} pub enum Out {}
impl Dir for Out { impl Dir for Out {
fn dir() -> Direction { fn dir() -> Direction {
@ -1106,6 +1115,7 @@ impl Dir for Out {
} }
} }
/// USB endpoint.
pub struct Endpoint<'d, T: Instance, D> { pub struct Endpoint<'d, T: Instance, D> {
_phantom: PhantomData<(&'d mut T, D)>, _phantom: PhantomData<(&'d mut T, D)>,
info: EndpointInfo, info: EndpointInfo,
@ -1299,6 +1309,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
} }
} }
/// USB control pipe.
pub struct ControlPipe<'d, T: Instance> { pub struct ControlPipe<'d, T: Instance> {
_phantom: PhantomData<&'d mut T>, _phantom: PhantomData<&'d mut T>,
max_packet_size: u16, max_packet_size: u16,

View File

@ -6,6 +6,7 @@ use stm32_metapac::iwdg::vals::{Key, Pr};
use crate::rcc::LSI_FREQ; use crate::rcc::LSI_FREQ;
/// Independent watchdog (IWDG) driver.
pub struct IndependentWatchdog<'d, T: Instance> { pub struct IndependentWatchdog<'d, T: Instance> {
wdg: PhantomData<&'d mut T>, wdg: PhantomData<&'d mut T>,
} }
@ -64,10 +65,12 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> {
IndependentWatchdog { wdg: PhantomData } IndependentWatchdog { wdg: PhantomData }
} }
/// Unleash (start) the watchdog.
pub fn unleash(&mut self) { pub fn unleash(&mut self) {
T::regs().kr().write(|w| w.set_key(Key::START)); T::regs().kr().write(|w| w.set_key(Key::START));
} }
/// Pet (reload, refresh) the watchdog.
pub fn pet(&mut self) { pub fn pet(&mut self) {
T::regs().kr().write(|w| w.set_key(Key::RESET)); T::regs().kr().write(|w| w.set_key(Key::RESET));
} }
@ -79,6 +82,7 @@ mod sealed {
} }
} }
/// IWDG instance trait.
pub trait Instance: sealed::Instance {} pub trait Instance: sealed::Instance {}
foreach_peripheral!( foreach_peripheral!(

View File

@ -111,6 +111,20 @@ where
poll_fn(move |cx| self.poll_wait(cx)) poll_fn(move |cx| self.poll_wait(cx))
} }
/// non-blocking method to try and take the signal value.
pub fn try_take(&self) -> Option<T> {
self.state.lock(|cell| {
let state = cell.replace(State::None);
match state {
State::Signaled(res) => Some(res),
state => {
cell.set(state);
None
}
}
})
}
/// non-blocking method to check whether this signal has been signaled. /// non-blocking method to check whether this signal has been signaled.
pub fn signaled(&self) -> bool { pub fn signaled(&self) -> bool {
self.state.lock(|cell| { self.state.lock(|cell| {

View File

@ -47,9 +47,6 @@ impl Timer {
/// ///
/// Example: /// Example:
/// ``` no_run /// ``` no_run
/// # #![feature(type_alias_impl_trait)]
/// #
/// # fn foo() {}
/// use embassy_time::{Duration, Timer}; /// use embassy_time::{Duration, Timer};
/// ///
/// #[embassy_executor::task] /// #[embassy_executor::task]
@ -132,8 +129,6 @@ impl Future for Timer {
/// ///
/// For instance, consider the following code fragment. /// For instance, consider the following code fragment.
/// ``` no_run /// ``` no_run
/// # #![feature(type_alias_impl_trait)]
/// #
/// use embassy_time::{Duration, Timer}; /// use embassy_time::{Duration, Timer};
/// # fn foo() {} /// # fn foo() {}
/// ///
@ -152,8 +147,6 @@ impl Future for Timer {
/// Example using ticker, which will consistently call `foo` once a second. /// Example using ticker, which will consistently call `foo` once a second.
/// ///
/// ``` no_run /// ``` no_run
/// # #![feature(type_alias_impl_trait)]
/// #
/// use embassy_time::{Duration, Ticker}; /// use embassy_time::{Duration, Ticker};
/// # fn foo(){} /// # fn foo(){}
/// ///

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] }
embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [] }
embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] } embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] }
embassy-boot = { version = "0.1.0", path = "../../../../embassy-boot/boot", features = [] } embassy-boot = { version = "0.1.0", path = "../../../../embassy-boot/boot", features = [] }

View File

@ -1,7 +1,6 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![macro_use] #![macro_use]
#![feature(type_alias_impl_trait)]
use embassy_boot_nrf::{FirmwareUpdater, FirmwareUpdaterConfig}; use embassy_boot_nrf::{FirmwareUpdater, FirmwareUpdaterConfig};
use embassy_embedded_hal::adapter::BlockingAsync; use embassy_embedded_hal::adapter::BlockingAsync;

View File

@ -1,7 +1,6 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![macro_use] #![macro_use]
#![feature(type_alias_impl_trait)]
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_nrf::gpio::{Level, Output, OutputDrive}; use embassy_nrf::gpio::{Level, Output, OutputDrive};

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] } embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers", "arch-cortex-m", "executor-thread"] }
embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [] }
embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", ] } embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", ] }
embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot/rp", features = [] } embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot/rp", features = [] }

View File

@ -1,6 +1,5 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)]
use core::cell::RefCell; use core::cell::RefCell;

View File

@ -1,6 +1,5 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)]
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_rp::gpio; use embassy_rp::gpio;

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f303re", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32" }

View File

@ -1,6 +1,5 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)]
#[cfg(feature = "defmt-rtt")] #[cfg(feature = "defmt-rtt")]
use defmt_rtt::*; use defmt_rtt::*;

View File

@ -1,6 +1,5 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)]
#[cfg(feature = "defmt-rtt")] #[cfg(feature = "defmt-rtt")]
use defmt_rtt::*; use defmt_rtt::*;

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32f767zi", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] }

View File

@ -1,6 +1,5 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)]
use core::cell::RefCell; use core::cell::RefCell;

View File

@ -1,6 +1,5 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)]
#[cfg(feature = "defmt-rtt")] #[cfg(feature = "defmt-rtt")]
use defmt_rtt::*; use defmt_rtt::*;

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32h743zi", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] }

View File

@ -1,6 +1,5 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)]
use core::cell::RefCell; use core::cell::RefCell;

View File

@ -1,6 +1,5 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)]
#[cfg(feature = "defmt-rtt")] #[cfg(feature = "defmt-rtt")]
use defmt_rtt::*; use defmt_rtt::*;

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l072cz", "time-driver-any", "exti", "memory-x"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] }

View File

@ -1,6 +1,5 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)]
#[cfg(feature = "defmt-rtt")] #[cfg(feature = "defmt-rtt")]
use defmt_rtt::*; use defmt_rtt::*;

View File

@ -1,6 +1,5 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)]
#[cfg(feature = "defmt-rtt")] #[cfg(feature = "defmt-rtt")]
use defmt_rtt::*; use defmt_rtt::*;

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l151cb-a", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] }

View File

@ -1,6 +1,5 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)]
#[cfg(feature = "defmt-rtt")] #[cfg(feature = "defmt-rtt")]
use defmt_rtt::*; use defmt_rtt::*;

View File

@ -1,6 +1,5 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)]
#[cfg(feature = "defmt-rtt")] #[cfg(feature = "defmt-rtt")]
use defmt_rtt::*; use defmt_rtt::*;

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32l475vg", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] }

View File

@ -1,6 +1,5 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)]
#[cfg(feature = "defmt-rtt")] #[cfg(feature = "defmt-rtt")]
use defmt_rtt::*; use defmt_rtt::*;

View File

@ -1,6 +1,5 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)]
#[cfg(feature = "defmt-rtt")] #[cfg(feature = "defmt-rtt")]
use defmt_rtt::*; use defmt_rtt::*;

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" } embassy-sync = { version = "0.5.0", path = "../../../../embassy-sync" }
embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } embassy-executor = { version = "0.4.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "integrated-timers"] }
embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] } embassy-time = { version = "0.2", path = "../../../../embassy-time", features = [ "tick-hz-32_768"] }
embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["stm32wb55rg", "time-driver-any", "exti"] }
embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = [] }

View File

@ -1,6 +1,5 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![feature(type_alias_impl_trait)]
use core::cell::RefCell; use core::cell::RefCell;

Some files were not shown because too many files have changed in this diff Show More