Compare commits

..

72 Commits

Author SHA1 Message Date
a2ebede411 Add half duplex support 2023-12-22 17:03:35 +01:00
4695e46a59 make usb-dfu work with usb serial 2023-12-22 15:29:17 +01:00
595ad10769 erase the whole flash at start of dfu 2023-12-22 11:54:23 +01:00
bde8d435ce Update embassy-boot/boot/src/firmware_updater/blocking.rs 2023-12-21 18:28:51 +01:00
46fca02b82 Update embassy-boot/boot/src/firmware_updater/blocking.rs 2023-12-21 18:26:33 +01:00
48c802859f Update embassy-boot/boot/src/firmware_updater/blocking.rs 2023-12-21 18:24:41 +01:00
5a6eaa5f74 Update embassy-boot/boot/src/firmware_updater/blocking.rs 2023-12-21 18:22:43 +01:00
189fb06ff7 Update embassy-boot/boot/src/firmware_updater/blocking.rs 2023-12-21 18:22:17 +01:00
cfa7f7aa02 Update embassy-boot/boot/src/firmware_updater/blocking.rs 2023-12-21 18:20:54 +01:00
ecb018f51c Update embassy-boot/boot/src/firmware_updater/blocking.rs 2023-12-21 18:18:43 +01:00
97e73210c6 Update embassy-boot/boot/src/firmware_updater/blocking.rs 2023-12-21 18:17:38 +01:00
96acde1096 Update embassy-boot/boot/src/firmware_updater/blocking.rs 2023-12-21 18:14:51 +01:00
25aba4bb68 Update embassy-boot/boot/src/firmware_updater/blocking.rs 2023-12-21 17:59:35 +01:00
343d6b99d4 Update embassy-boot/boot/src/firmware_updater/blocking.rs 2023-12-21 17:43:27 +01:00
ab18ba6d90 erase once. write multiple 2023-12-21 17:38:54 +01:00
Dario Nieuwenhuis
87c03037e3
Merge pull request #2342 from embassy-rs/no-more-nightly
ci: use beta, add secondary nightly ci.
2023-12-21 14:44:56 +00:00
Dario Nieuwenhuis
8b36a32ed5 ci: use beta, add secondary nightly ci. 2023-12-21 15:03:57 +01:00
Dario Nieuwenhuis
90aebb5828
Merge pull request #2341 from bugadani/faq
FAQ: Remove Xtensa specifier
2023-12-21 13:34:21 +00:00
Dániel Buga
cf0e5e32ad Remove Xtensa specifier 2023-12-21 14:27:58 +01:00
Ulf Lilleengen
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
Ulf Lilleengen
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
Ulf Lilleengen
0acf7b09c3 chore: replace make_static! macro usage with non-macro version 2023-12-21 10:29:57 +01:00
eZio Pan
745d618ab7 note on circular mode DMA 2023-12-21 17:03:10 +08:00
Ulf Lilleengen
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
Dario Nieuwenhuis
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
Dario Nieuwenhuis
d6fda686bc net-esp-hosted: use released noproto version. 2023-12-20 14:13:52 +01:00
Ulf Lilleengen
896690c415 fix: remove git dependency in embassy-boot 2023-12-20 13:46:43 +01:00
Ulf Lilleengen
76c600365d
Merge pull request #2334 from embassy-rs/embassy-net-adin1110-docs
docs: embassy-net-adin1110
2023-12-20 12:44:19 +00:00
Ulf Lilleengen
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
Ulf Lilleengen
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
Ulf Lilleengen
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
Ulf Lilleengen
93bb34d8d1 fix: expose less 2023-12-20 13:39:45 +01:00
Ulf Lilleengen
51a67cb69a fix: expose less 2023-12-20 13:34:34 +01:00
Dario Nieuwenhuis
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
Dario Nieuwenhuis
22ee868f04
Merge pull request #2335 from embassy-rs/remove-embedded-sdmmc
remove embedded-sdmmc
2023-12-20 12:32:04 +00:00
Ulf Lilleengen
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
Ulf Lilleengen
b8777eaea2 better keep missing docs for into 2023-12-20 13:12:32 +01:00
Rasmus Melchior Jacobsen
13c107e815 Put waiting state back if any 2023-12-20 13:09:16 +01:00
Ulf Lilleengen
b0583b17cb fix: make non-public instead 2023-12-20 13:08:06 +01:00
Ulf Lilleengen
246c49621c docs: embassy-net-adin1110 2023-12-20 12:52:35 +01:00
Ulf Lilleengen
c3b827d8cd fix: add readme and fix remaining warnings 2023-12-20 12:24:51 +01:00
Ulf Lilleengen
4dfae9328e add missing guards 2023-12-20 12:18:02 +01:00
Ulf Lilleengen
73f8cd7ade fix: add repository to manifest 2023-12-20 12:16:01 +01:00
Ulf Lilleengen
4a2dd7b944 docs: document public apis of wiznet driver 2023-12-20 12:14:25 +01:00
Ulf Lilleengen
afb01e3fc5 docs: document embassy-net-tuntap 2023-12-20 12:08:26 +01:00
Ulf Lilleengen
89cfdcb9f5 fix suddenly ending comment 2023-12-20 12:06:49 +01:00
Ulf Lilleengen
abea4dde3d docs: document most of esp-hosted driver 2023-12-20 10:15:18 +01:00
Ulf Lilleengen
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
Ulf Lilleengen
fc6e70caa5 docs: document public apis of embassy-net-driver-channel 2023-12-20 09:24:10 +01:00
Rasmus Melchior Jacobsen
f9d0daad80 feat(embassy-sync): Add try_take() to signal 2023-12-20 08:37:15 +01:00
Dario Nieuwenhuis
97e919ea64
Merge pull request #2326 from embassy-rs/salty-update
Salty update
2023-12-19 21:30:32 +00:00
Dario Nieuwenhuis
c7841a37fa boot: update ed25519-dalek in dev-dependencies. 2023-12-19 22:26:50 +01:00
Dario Nieuwenhuis
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
Ulf Lilleengen
4567b87482 cargo fmt 2023-12-19 21:21:52 +01:00
Ulf Lilleengen
12de90e13d fix: update ed25519-dalek to new version 2023-12-19 21:20:30 +01:00
dragonn
871ed538b1 fix stm32 rtc year from 1970 base 2000 2023-12-19 21:17:42 +01:00
Ulf Lilleengen
efd5dbe019 fix: build warnings 2023-12-19 20:25:20 +01:00
Ulf Lilleengen
9d46ee0758 fix: update salty to released version 2023-12-19 20:24:55 +01:00
Dario Nieuwenhuis
e5912972ec
Merge pull request #2325 from embassy-rs/stm32-docs
stm32: finish docs.
2023-12-19 17:07:53 +00:00
Dario Nieuwenhuis
c8c8b89104 stm32: doc everything else. 2023-12-19 18:03:20 +01:00
Dario Nieuwenhuis
189b15c426 stm32/timer: docs. 2023-12-19 17:35:38 +01:00
Dario Nieuwenhuis
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
Dario Nieuwenhuis
7ec1ed4de3
Merge pull request #2324 from barnabywalters/stm32-usart-docs
stm32: Documented usart public API
2023-12-19 16:58:27 +01:00
Barnaby Walters
6564c04531 Reset .vscode/settings.json (doh) 2023-12-19 16:42:51 +01:00
Barnaby Walters
f97ef61ef8 Documented usart public API 2023-12-19 16:41:00 +01:00
Ulf Lilleengen
9ddf8b08e4 docs: document usb-logger and usb-dfu 2023-12-19 16:33:05 +01:00
Dario Nieuwenhuis
71584409d9
Merge pull request #2321 from embassy-rs/stm32-docs
stm32: document hrtim, qspi, sdmmc, spi.
2023-12-19 15:29:26 +00:00
Dario Nieuwenhuis
1ea87ec6e7 stm32: document hrtim, qspi, sdmmc, spi. 2023-12-19 16:21:51 +01:00
Dario Nieuwenhuis
7d9a76da00
Merge pull request #2313 from eZioPan/update-metapac6
match up with "DMA cleanup" metapac change
2023-12-19 15:20:15 +00:00
Ulf Lilleengen
c995732b0e
Merge pull request #2320 from embassy-rs/cyw43-docs
docs: document public apis for cyw43 driver
2023-12-19 15:12:45 +00:00
eZio Pan
3e2e109437 update metapac dep 2023-12-19 19:09:06 +08:00
eZio Pan
254d587385 match up with metapac change 2023-12-19 17:12:34 +08:00
428 changed files with 1393 additions and 1046 deletions

View File

@ -7,6 +7,7 @@ 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
# needed for "dumb HTTP" transport support
# used when pointing stm32-metapac to a CI-built one.
@ -21,9 +22,7 @@ fi
hashtime restore /ci/cache/filetime.json || true
hashtime save /ci/cache/filetime.json
sed -i 's/channel.*/channel = "beta"/g' rust-toolchain.toml
./ci_stable.sh
./ci-nightly.sh
# Save 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_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-embedded-hal/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": "thumbv7em-none-eabi",
//"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf",
"rust-analyzer.cargo.features": [
// Uncomment if the example has a "nightly" feature.
"nightly",
],
"rust-analyzer.linkedProjects": [
// Uncomment ONE line for the chip you want to work on.
// 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/nrf5340/Cargo.toml",
// "examples/nrf-rtos-trace/Cargo.toml",
@ -49,4 +45,4 @@
// "examples/stm32wl/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"
fi
find . -name '*.rs' -not -path '*target*' | xargs rustfmt --check --skip-children --unstable-features --edition 2021
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 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-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 arch-cortex-m \
--- 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 arch-cortex-m,executor-thread \
--- 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 arch-cortex-m,executor-interrupt \
--- 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 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,integrated-timers \
--- 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 arch-riscv32,integrated-timers \
--- 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 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-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 \
@ -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 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 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 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 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 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 \
@ -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-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-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/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 \

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_main]
#![feature(type_alias_impl_trait)]
use defmt::*;
use embassy_executor::Spawner;

View File

@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
cortex-m = "0.7"
cortex-m-rt = "0.7"
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-rtt = "0.3.0"

View File

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

View File

@ -35,7 +35,7 @@ For Cortex-M targets, consider making sure that ALL of the following features ar
* `executor-thread`
* `nightly`
For Xtensa ESP32, consider using the executors and `#[main]` macro provided by your appropriate link:https://crates.io/crates/esp-hal-common[HAL crate].
For ESP32, consider using the executors and `#[main]` macro provided by your appropriate link:https://crates.io/crates/esp-hal-common[HAL crate].
== Why is my binary so big?

View File

@ -26,25 +26,22 @@ features = ["defmt"]
defmt = { version = "0.3", optional = true }
digest = "0.10"
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-sync = { version = "0.5.0", path = "../../embassy-sync" }
embedded-storage = "0.3.1"
embedded-storage-async = { version = "0.4.1" }
salty = { git = "https://github.com/ycrypto/salty.git", rev = "a9f17911a5024698406b75c0fac56ab5ccf6a8c7", optional = true }
signature = { version = "1.6.4", default-features = false }
salty = { version = "0.3", optional = true }
signature = { version = "2.0", default-features = false }
[dev-dependencies]
log = "0.4"
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"] }
sha1 = "0.10.5"
critical-section = { version = "1.1.1", features = ["std"] }
[dev-dependencies.ed25519-dalek]
default_features = false
features = ["rand", "std", "u32_backend"]
ed25519-dalek = { version = "2", default_features = false, features = ["std", "rand_core", "digest"] }
[features]
ed25519-dalek = ["dep:ed25519-dalek", "_verify"]

View File

@ -1,6 +1,6 @@
use digest::typenum::U64;
use digest::{FixedOutput, HashMarker, OutputSizeUser, Update};
use ed25519_dalek::Digest as _;
use ed25519_dalek::Digest;
pub struct Sha512(ed25519_dalek::Sha512);
@ -12,7 +12,7 @@ impl Default for Sha512 {
impl Update for Sha512 {
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")]
pub async fn verify_and_mark_updated(
&mut self,
_public_key: &[u8],
_signature: &[u8],
_public_key: &[u8; 32],
_signature: &[u8; 64],
_update_len: u32,
) -> Result<(), FirmwareUpdaterError> {
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")]
{
use ed25519_dalek::{PublicKey, Signature, SignatureError, Verifier};
use ed25519_dalek::{Signature, SignatureError, Verifier, VerifyingKey};
use crate::digest_adapters::ed25519_dalek::Sha512;
let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into());
let public_key = PublicKey::from_bytes(_public_key).map_err(into_signature_error)?;
let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?;
let public_key = VerifyingKey::from_bytes(_public_key).map_err(into_signature_error)?;
let signature = Signature::from_bytes(_signature);
let mut chunk_buf = [0; 2];
let mut message = [0; 64];
@ -106,7 +106,6 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> FirmwareUpdater<'d, DFU, STATE> {
}
#[cfg(feature = "ed25519-salty")]
{
use salty::constants::{PUBLICKEY_SERIALIZED_LENGTH, SIGNATURE_SERIALIZED_LENGTH};
use salty::{PublicKey, Signature};
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())
}
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 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 public_key = PublicKey::try_from(_public_key).map_err(into_signature_error)?;
let signature = Signature::try_from(_signature).map_err(into_signature_error)?;
let mut message = [0; 64];
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")]
pub fn verify_and_mark_updated(
&mut self,
_public_key: &[u8],
_signature: &[u8],
_public_key: &[u8; 32],
_signature: &[u8; 64],
_update_len: u32,
) -> Result<(), FirmwareUpdaterError> {
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")]
{
use ed25519_dalek::{PublicKey, Signature, SignatureError, Verifier};
use ed25519_dalek::{Signature, SignatureError, Verifier, VerifyingKey};
use crate::digest_adapters::ed25519_dalek::Sha512;
let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into());
let public_key = PublicKey::from_bytes(_public_key).map_err(into_signature_error)?;
let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?;
let public_key = VerifyingKey::from_bytes(_public_key).map_err(into_signature_error)?;
let signature = Signature::from_bytes(_signature);
let mut message = [0; 64];
let mut chunk_buf = [0; 2];
@ -113,7 +113,6 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE>
}
#[cfg(feature = "ed25519-salty")]
{
use salty::constants::{PUBLICKEY_SERIALIZED_LENGTH, SIGNATURE_SERIALIZED_LENGTH};
use salty::{PublicKey, Signature};
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())
}
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 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 public_key = PublicKey::try_from(_public_key).map_err(into_signature_error)?;
let signature = Signature::try_from(_signature).map_err(into_signature_error)?;
let mut message = [0; 64];
let mut chunk_buf = [0; 2];
@ -187,10 +184,12 @@ impl<'d, DFU: NorFlash, STATE: NorFlash> BlockingFirmwareUpdater<'d, DFU, STATE>
///
/// Failing to meet alignment and size requirements may result in a panic.
pub fn write_firmware(&mut self, offset: usize, data: &[u8]) -> Result<(), FirmwareUpdaterError> {
assert!(data.len() >= DFU::ERASE_SIZE);
//assert!(data.len() >= DFU::ERASE_SIZE);
self.state.verify_booted()?;
self.dfu.erase(offset as u32, (offset + data.len()) as u32)?;
if offset == 0 {
self.dfu.erase(0, self.dfu.capacity() as u32)?;
}
self.dfu.write(offset as u32, data)?;

View File

@ -275,21 +275,19 @@ mod tests {
// The following key setup is based on:
// 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;
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 mut digest = Sha512::new();
digest.update(&firmware);
let message = digest.finalize();
let signature: Signature = keypair.sign(&message);
use ed25519_dalek::PublicKey;
let public_key: PublicKey = keypair.public;
let public_key = keypair.verifying_key();
// Setup flash
let flash = BlockingTestFlash::new(BootLoaderConfig {

View File

@ -4,6 +4,12 @@ name = "embassy-boot-nrf"
version = "0.1.0"
description = "Bootloader lib for nRF chips"
license = "MIT OR Apache-2.0"
repository = "https://github.com/embassy-rs/embassy"
categories = [
"embedded",
"no-std",
"asynchronous",
]
[package.metadata.embassy_docs]
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" }
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]
defmt = [

View File

@ -4,6 +4,12 @@ name = "embassy-boot-rp"
version = "0.1.0"
description = "Bootloader lib for RP2040 chips"
license = "MIT OR Apache-2.0"
repository = "https://github.com/embassy-rs/embassy"
categories = [
"embedded",
"no-std",
"asynchronous",
]
[package.metadata.embassy_docs]
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"
description = "Bootloader lib for STM32 chips"
license = "MIT OR Apache-2.0"
repository = "https://github.com/embassy-rs/embassy"
categories = [
"embedded",
"no-std",
"asynchronous",
]
[package.metadata.embassy_docs]
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]
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/"
features = ["nightly", "defmt"]
features = ["defmt"]
flavors = [
{ name = "std", target = "x86_64-unknown-linux-gnu", features = ["arch-std", "executor-thread"] },
{ name = "wasm", target = "wasm32-unknown-unknown", features = ["arch-wasm", "executor-thread"] },
@ -25,7 +25,7 @@ flavors = [
[package.metadata.docs.rs]
default-target = "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]
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"]
license = "MIT OR Apache-2.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
repository = "https://github.com/embassy-rs/embassy"
[dependencies]
heapless = "0.8"

View File

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

View File

@ -5,6 +5,7 @@
#![allow(clippy::missing_errors_doc)]
#![allow(clippy::missing_panics_doc)]
#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
// must go first!
mod fmt;
@ -26,8 +27,9 @@ use embedded_hal_async::digital::Wait;
use embedded_hal_async::spi::{Error, Operation, SpiDevice};
use heapless::Vec;
pub use mdio::MdioBus;
pub use phy::{Phy10BaseT1x, RegsC22, RegsC45};
pub use regs::{Config0, Config2, SpiRegisters as sr, Status0, Status1};
pub use phy::Phy10BaseT1x;
use phy::{RegsC22, RegsC45};
use regs::{Config0, Config2, SpiRegisters as sr, Status0, Status1};
use crate::fmt::Bytes;
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> {
/// Run the driver.
#[allow(clippy::too_many_lines)]
pub async fn run(mut self) -> ! {
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>
pub trait MdioBus {
/// Error type.
type Error;
/// Read, Clause 22

View File

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

View File

@ -1,5 +1,6 @@
#![no_std]
#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
// must go first!
mod fmt;
@ -15,6 +16,9 @@ use embassy_sync::blocking_mutex::Mutex;
use embassy_sync::waitqueue::WakerRegistration;
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> {
rx: [PacketBuf<MTU>; N_RX],
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> {
const NEW_PACKET: PacketBuf<MTU> = PacketBuf::new();
/// Create a new channel state.
pub const fn new() -> Self {
Self {
rx: [Self::NEW_PACKET; N_RX],
@ -39,33 +44,45 @@ struct StateInner<'d, const MTU: usize> {
shared: Mutex<NoopRawMutex, RefCell<Shared>>,
}
/// State of the LinkState
struct Shared {
link_state: LinkState,
waker: WakerRegistration,
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> {
tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<MTU>>,
rx_chan: zerocopy_channel::Sender<'d, NoopRawMutex, PacketBuf<MTU>>,
shared: &'d Mutex<NoopRawMutex, RefCell<Shared>>,
}
/// State runner.
///
/// Holds the shared state of the channel such as link state.
#[derive(Clone, Copy)]
pub struct StateRunner<'d> {
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> {
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> {
tx_chan: zerocopy_channel::Receiver<'d, NoopRawMutex, PacketBuf<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>) {
(
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>) {
(
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> {
StateRunner { shared: self.shared }
}
/// Set the link state.
pub fn set_link_state(&mut self, state: LinkState) {
self.shared.lock(|s| {
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) {
self.shared.lock(|s| {
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] {
let p = self.rx_chan.send().await;
&mut p.buf
}
/// Check if there is space for more inbound packets right now.
pub fn try_rx_buf(&mut self) -> Option<&mut [u8]> {
let p = self.rx_chan.try_send()?;
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]> {
match self.rx_chan.poll_send(cx) {
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) {
let p = self.rx_chan.try_send().unwrap();
p.len = len;
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] {
let p = self.tx_chan.receive().await;
&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]> {
let p = self.tx_chan.try_receive()?;
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]> {
match self.tx_chan.poll_receive(cx) {
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) {
self.tx_chan.receive_done();
}
}
impl<'d> StateRunner<'d> {
/// Set link state.
pub fn set_link_state(&self, state: LinkState) {
self.shared.lock(|s| {
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) {
self.shared.lock(|s| {
let s = &mut *s.borrow_mut();
@ -170,16 +201,19 @@ impl<'d> StateRunner<'d> {
}
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] {
let p = self.rx_chan.send().await;
&mut p.buf
}
/// Check if there is space for more inbound packets right now.
pub fn try_rx_buf(&mut self) -> Option<&mut [u8]> {
let p = self.rx_chan.try_send()?;
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]> {
match self.rx_chan.poll_send(cx) {
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) {
let p = self.rx_chan.try_send().unwrap();
p.len = len;
@ -195,16 +230,19 @@ impl<'d, const MTU: usize> RxRunner<'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] {
let p = self.tx_chan.receive().await;
&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]> {
let p = self.tx_chan.try_receive()?;
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]> {
match self.tx_chan.poll_receive(cx) {
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) {
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>(
state: &'d mut State<MTU, N_RX, N_TX>,
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> {
len: usize,
buf: [u8; MTU],
}
impl<const MTU: usize> PacketBuf<MTU> {
/// Create a new packet buffer.
pub const fn new() -> Self {
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> {
rx: zerocopy_channel::Receiver<'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> {
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> {
tx: zerocopy_channel::Sender<'a, NoopRawMutex, PacketBuf<MTU>>,
}

View File

@ -2,6 +2,10 @@
name = "embassy-net-esp-hosted"
version = "0.1.0"
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]
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-async = { version = "=1.0.0-rc.3" }
noproto = { git="https://github.com/embassy-rs/noproto", rev = "f5e6d1f325b6ad4e344f60452b09576e24671f62", default-features = false, features = ["derive"] }
#noproto = { version = "0.1", path = "/home/dirbaio/noproto", default-features = false, features = ["derive"] }
noproto = "0.1.0"
heapless = "0.8"
[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::proto::{self, CtrlMsg};
/// Errors reported by control.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
/// The operation failed with the given error code.
Failed(u32),
/// The operation timed out.
Timeout,
/// Internal error.
Internal,
}
/// Handle for managing the network and WiFI state.
pub struct Control<'a> {
state_ch: ch::StateRunner<'a>,
shared: &'a Shared,
}
/// WiFi mode.
#[allow(unused)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
enum WifiMode {
/// No mode.
None = 0,
/// Client station.
Sta = 1,
/// Access point mode.
Ap = 2,
/// Repeater mode.
ApSta = 3,
}
pub use proto::CtrlWifiSecProt as Security;
/// WiFi status.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Status {
/// Service Set Identifier.
pub ssid: String<32>,
/// Basic Service Set Identifier.
pub bssid: [u8; 6],
/// Received Signal Strength Indicator.
pub rssi: i32,
/// WiFi channel.
pub channel: u32,
/// Security mode.
pub security: Security,
}
@ -65,6 +81,7 @@ impl<'a> Control<'a> {
Self { state_ch, shared }
}
/// Initialize device.
pub async fn init(&mut self) -> Result<(), Error> {
debug!("wait for init event...");
self.shared.init_wait().await;
@ -82,6 +99,7 @@ impl<'a> Control<'a> {
Ok(())
}
/// Get the current status.
pub async fn get_status(&mut self) -> Result<Status, Error> {
let req = proto::CtrlMsgReqGetApConfig {};
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> {
let req = proto::CtrlMsgReqConnectAp {
ssid: unwrap!(String::try_from(ssid)),
@ -108,6 +127,7 @@ impl<'a> Control<'a> {
Ok(())
}
/// Disconnect from any currently connected network.
pub async fn disconnect(&mut self) -> Result<(), Error> {
let req = proto::CtrlMsgReqGetStatus {};
ioctl!(self, ReqDisconnectAp, RespDisconnectAp, req, resp);

View File

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

View File

@ -4,7 +4,7 @@ use heapless::{String, Vec};
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ScanResult {
pub(crate) struct ScanResult {
#[noproto(tag = "1")]
pub ssid: String<32>,
#[noproto(tag = "2")]
@ -19,7 +19,7 @@ pub struct ScanResult {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ConnectedStaList {
pub(crate) struct ConnectedStaList {
#[noproto(tag = "1")]
pub mac: String<32>,
#[noproto(tag = "2")]
@ -29,14 +29,14 @@ pub struct ConnectedStaList {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqGetMacAddress {
pub(crate) struct CtrlMsgReqGetMacAddress {
#[noproto(tag = "1")]
pub mode: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespGetMacAddress {
pub(crate) struct CtrlMsgRespGetMacAddress {
#[noproto(tag = "1")]
pub mac: String<32>,
#[noproto(tag = "2")]
@ -45,11 +45,11 @@ pub struct CtrlMsgRespGetMacAddress {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqGetMode {}
pub(crate) struct CtrlMsgReqGetMode {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespGetMode {
pub(crate) struct CtrlMsgRespGetMode {
#[noproto(tag = "1")]
pub mode: u32,
#[noproto(tag = "2")]
@ -58,32 +58,32 @@ pub struct CtrlMsgRespGetMode {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqSetMode {
pub(crate) struct CtrlMsgReqSetMode {
#[noproto(tag = "1")]
pub mode: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespSetMode {
pub(crate) struct CtrlMsgRespSetMode {
#[noproto(tag = "1")]
pub resp: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqGetStatus {}
pub(crate) struct CtrlMsgReqGetStatus {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespGetStatus {
pub(crate) struct CtrlMsgRespGetStatus {
#[noproto(tag = "1")]
pub resp: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqSetMacAddress {
pub(crate) struct CtrlMsgReqSetMacAddress {
#[noproto(tag = "1")]
pub mac: String<32>,
#[noproto(tag = "2")]
@ -92,18 +92,18 @@ pub struct CtrlMsgReqSetMacAddress {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespSetMacAddress {
pub(crate) struct CtrlMsgRespSetMacAddress {
#[noproto(tag = "1")]
pub resp: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqGetApConfig {}
pub(crate) struct CtrlMsgReqGetApConfig {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespGetApConfig {
pub(crate) struct CtrlMsgRespGetApConfig {
#[noproto(tag = "1")]
pub ssid: String<32>,
#[noproto(tag = "2")]
@ -120,7 +120,7 @@ pub struct CtrlMsgRespGetApConfig {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqConnectAp {
pub(crate) struct CtrlMsgReqConnectAp {
#[noproto(tag = "1")]
pub ssid: String<32>,
#[noproto(tag = "2")]
@ -135,7 +135,7 @@ pub struct CtrlMsgReqConnectAp {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespConnectAp {
pub(crate) struct CtrlMsgRespConnectAp {
#[noproto(tag = "1")]
pub resp: u32,
#[noproto(tag = "2")]
@ -144,11 +144,11 @@ pub struct CtrlMsgRespConnectAp {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqGetSoftApConfig {}
pub(crate) struct CtrlMsgReqGetSoftApConfig {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespGetSoftApConfig {
pub(crate) struct CtrlMsgRespGetSoftApConfig {
#[noproto(tag = "1")]
pub ssid: String<32>,
#[noproto(tag = "2")]
@ -169,7 +169,7 @@ pub struct CtrlMsgRespGetSoftApConfig {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqStartSoftAp {
pub(crate) struct CtrlMsgReqStartSoftAp {
#[noproto(tag = "1")]
pub ssid: String<32>,
#[noproto(tag = "2")]
@ -188,7 +188,7 @@ pub struct CtrlMsgReqStartSoftAp {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespStartSoftAp {
pub(crate) struct CtrlMsgRespStartSoftAp {
#[noproto(tag = "1")]
pub resp: u32,
#[noproto(tag = "2")]
@ -197,11 +197,11 @@ pub struct CtrlMsgRespStartSoftAp {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqScanResult {}
pub(crate) struct CtrlMsgReqScanResult {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespScanResult {
pub(crate) struct CtrlMsgRespScanResult {
#[noproto(tag = "1")]
pub count: u32,
#[noproto(repeated, tag = "2")]
@ -212,11 +212,11 @@ pub struct CtrlMsgRespScanResult {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqSoftApConnectedSta {}
pub(crate) struct CtrlMsgReqSoftApConnectedSta {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespSoftApConnectedSta {
pub(crate) struct CtrlMsgRespSoftApConnectedSta {
#[noproto(tag = "1")]
pub num: u32,
#[noproto(repeated, tag = "2")]
@ -227,43 +227,43 @@ pub struct CtrlMsgRespSoftApConnectedSta {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqOtaBegin {}
pub(crate) struct CtrlMsgReqOtaBegin {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespOtaBegin {
pub(crate) struct CtrlMsgRespOtaBegin {
#[noproto(tag = "1")]
pub resp: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqOtaWrite {
pub(crate) struct CtrlMsgReqOtaWrite {
#[noproto(tag = "1")]
pub ota_data: Vec<u8, 1024>,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespOtaWrite {
pub(crate) struct CtrlMsgRespOtaWrite {
#[noproto(tag = "1")]
pub resp: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqOtaEnd {}
pub(crate) struct CtrlMsgReqOtaEnd {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespOtaEnd {
pub(crate) struct CtrlMsgRespOtaEnd {
#[noproto(tag = "1")]
pub resp: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqVendorIeData {
pub(crate) struct CtrlMsgReqVendorIeData {
#[noproto(tag = "1")]
pub element_id: u32,
#[noproto(tag = "2")]
@ -278,7 +278,7 @@ pub struct CtrlMsgReqVendorIeData {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqSetSoftApVendorSpecificIe {
pub(crate) struct CtrlMsgReqSetSoftApVendorSpecificIe {
#[noproto(tag = "1")]
pub enable: bool,
#[noproto(tag = "2")]
@ -291,32 +291,32 @@ pub struct CtrlMsgReqSetSoftApVendorSpecificIe {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespSetSoftApVendorSpecificIe {
pub(crate) struct CtrlMsgRespSetSoftApVendorSpecificIe {
#[noproto(tag = "1")]
pub resp: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqSetWifiMaxTxPower {
pub(crate) struct CtrlMsgReqSetWifiMaxTxPower {
#[noproto(tag = "1")]
pub wifi_max_tx_power: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespSetWifiMaxTxPower {
pub(crate) struct CtrlMsgRespSetWifiMaxTxPower {
#[noproto(tag = "1")]
pub resp: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqGetWifiCurrTxPower {}
pub(crate) struct CtrlMsgReqGetWifiCurrTxPower {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespGetWifiCurrTxPower {
pub(crate) struct CtrlMsgRespGetWifiCurrTxPower {
#[noproto(tag = "1")]
pub wifi_curr_tx_power: u32,
#[noproto(tag = "2")]
@ -325,7 +325,7 @@ pub struct CtrlMsgRespGetWifiCurrTxPower {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqConfigHeartbeat {
pub(crate) struct CtrlMsgReqConfigHeartbeat {
#[noproto(tag = "1")]
pub enable: bool,
#[noproto(tag = "2")]
@ -334,7 +334,7 @@ pub struct CtrlMsgReqConfigHeartbeat {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespConfigHeartbeat {
pub(crate) struct CtrlMsgRespConfigHeartbeat {
#[noproto(tag = "1")]
pub resp: u32,
}
@ -342,28 +342,28 @@ pub struct CtrlMsgRespConfigHeartbeat {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgEventEspInit {
pub(crate) struct CtrlMsgEventEspInit {
#[noproto(tag = "1")]
pub init_data: Vec<u8, 64>,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgEventHeartbeat {
pub(crate) struct CtrlMsgEventHeartbeat {
#[noproto(tag = "1")]
pub hb_num: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgEventStationDisconnectFromAp {
pub(crate) struct CtrlMsgEventStationDisconnectFromAp {
#[noproto(tag = "1")]
pub resp: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgEventStationDisconnectFromEspSoftAp {
pub(crate) struct CtrlMsgEventStationDisconnectFromEspSoftAp {
#[noproto(tag = "1")]
pub resp: u32,
#[noproto(tag = "2")]
@ -372,7 +372,7 @@ pub struct CtrlMsgEventStationDisconnectFromEspSoftAp {
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsg {
pub(crate) struct CtrlMsg {
/// msg_type could be req, resp or Event
#[noproto(tag = "1")]
pub msg_type: CtrlMsgType,
@ -390,7 +390,7 @@ pub struct CtrlMsg {
/// union of all msg ids
#[derive(Debug, Clone, Eq, PartialEq, noproto::Oneof)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlMsgPayload {
pub(crate) enum CtrlMsgPayload {
/// * Requests *
#[noproto(tag = "101")]
ReqGetMacAddress(CtrlMsgReqGetMacAddress),
@ -492,7 +492,7 @@ pub enum CtrlMsgPayload {
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlVendorIeType {
pub(crate) enum CtrlVendorIeType {
#[default]
Beacon = 0,
ProbeReq = 1,
@ -504,7 +504,7 @@ pub enum CtrlVendorIeType {
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlVendorIeid {
pub(crate) enum CtrlVendorIeid {
#[default]
Id0 = 0,
Id1 = 1,
@ -513,7 +513,7 @@ pub enum CtrlVendorIeid {
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlWifiMode {
pub(crate) enum CtrlWifiMode {
#[default]
None = 0,
Sta = 1,
@ -524,7 +524,7 @@ pub enum CtrlWifiMode {
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlWifiBw {
pub(crate) enum CtrlWifiBw {
#[default]
BwInvalid = 0,
Ht20 = 1,
@ -534,13 +534,15 @@ pub enum CtrlWifiBw {
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlWifiPowerSave {
pub(crate) enum CtrlWifiPowerSave {
#[default]
PsInvalid = 0,
MinModem = 1,
MaxModem = 2,
}
/// Wifi Security Settings
#[allow(missing_docs)]
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)]
#[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)]
#[repr(u32)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlStatus {
pub(crate) enum CtrlStatus {
#[default]
Connected = 0,
NotConnected = 1,
@ -573,7 +575,7 @@ pub enum CtrlStatus {
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlMsgType {
pub(crate) enum CtrlMsgType {
#[default]
MsgTypeInvalid = 0,
Req = 1,
@ -585,7 +587,7 @@ pub enum CtrlMsgType {
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlMsgId {
pub(crate) enum CtrlMsgId {
#[default]
MsgIdInvalid = 0,
/// * 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"]
license = "MIT OR Apache-2.0"
edition = "2021"
repository = "https://github.com/embassy-rs/embassy"
[dependencies]
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
@ -16,4 +17,4 @@ libc = "0.2.101"
[package.metadata.embassy_docs]
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/"
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::{Read, Write};
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 log::*;
/// Get the MTU of the given interface.
pub const SIOCGIFMTU: libc::c_ulong = 0x8921;
/// Get the index of the given interface.
pub const _SIOCGIFINDEX: libc::c_ulong = 0x8933;
/// Capture all packages.
pub const _ETH_P_ALL: libc::c_short = 0x0003;
/// Set the interface flags.
pub const TUNSETIFF: libc::c_ulong = 0x400454CA;
/// TUN device.
pub const _IFF_TUN: libc::c_int = 0x0001;
/// TAP device.
pub const IFF_TAP: libc::c_int = 0x0002;
/// No packet information.
pub const IFF_NO_PI: libc::c_int = 0x1000;
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)
}
/// A TUN/TAP device.
#[derive(Debug)]
pub struct TunTap {
fd: libc::c_int,
@ -60,6 +70,7 @@ impl AsRawFd for TunTap {
}
impl TunTap {
/// Create a new TUN/TAP device.
pub fn new(name: &str) -> io::Result<TunTap> {
unsafe {
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 {
device: Async<TunTap>,
}
impl TunTapDevice {
/// Create a new TUN/TAP device.
pub fn new(name: &str) -> io::Result<TunTapDevice> {
Ok(Self {
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"]
license = "MIT OR Apache-2.0"
edition = "2021"
repository = "https://github.com/embassy-rs/embassy"
[dependencies]
embedded-hal = { version = "1.0.0-rc.3" }

View File

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

View File

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

View File

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

View File

@ -1,6 +1,7 @@
#![no_std]
#![allow(async_fn_in_trait)]
#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
pub mod chip;
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.
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) -> ! {
let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split();
let mut tick = Ticker::every(Duration::from_millis(500));

View File

@ -411,10 +411,12 @@ impl<D: Driver> Stack<D> {
/// ```ignore
/// let config = embassy_net::Config::dhcpv4(Default::default());
///// 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,
/// config,
/// make_static!(embassy_net::StackResources::<2>::new()),
/// RESOURCES.init(embassy_net::StackResources::new()),
/// seed
/// ));
/// // Launch network task that runs `stack.run().await`

View File

@ -87,5 +87,5 @@ pio = {version= "0.2.1" }
rp2040-boot2 = "0.3"
[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" }

View File

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

View File

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

View File

@ -26,7 +26,7 @@ aligned = "0.4.1"
bit_field = "0.10.2"
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"] }
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"] }
rand_core = "0.6.3"
sdio-host = "0.5.0"
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
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"
bxcan = "0.7.0"
nb = "1.0.0"
@ -76,7 +75,7 @@ critical-section = { version = "1.1", features = ["std"] }
[build-dependencies]
proc-macro2 = "1.0.36"
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]

View File

@ -23,6 +23,10 @@ use crate::pac::bdma::{regs, vals};
#[non_exhaustive]
pub struct TransferOptions {
/// 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,
/// Enable half transfer interrupt
pub half_transfer_ir: bool,
@ -303,20 +307,14 @@ impl<'a, C: Channel> Transfer<'a, C> {
ch.cr().write(|w| {
w.set_psize(data_size.into());
w.set_msize(data_size.into());
if incr_mem {
w.set_minc(vals::Inc::ENABLED);
} else {
w.set_minc(vals::Inc::DISABLED);
}
w.set_minc(incr_mem);
w.set_dir(dir.into());
w.set_teie(true);
w.set_tcie(options.complete_transfer_ir);
w.set_htie(options.half_transfer_ir);
w.set_circ(options.circular);
if options.circular {
w.set_circ(vals::Circ::ENABLED);
debug!("Setting circular mode");
} else {
w.set_circ(vals::Circ::DISABLED);
}
w.set_pl(vals::Pl::VERYHIGH);
w.set_en(true);
@ -352,7 +350,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
pub fn is_running(&mut self) -> bool {
let ch = self.channel.regs().ch(self.channel.num());
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;
en && (circular || !tcif)
}
@ -467,12 +465,12 @@ impl<'a, C: Channel, W: Word> ReadableRingBuffer<'a, C, W> {
let mut w = regs::Cr(0);
w.set_psize(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_teie(true);
w.set_htie(true);
w.set_tcie(true);
w.set_circ(vals::Circ::ENABLED);
w.set_circ(true);
w.set_pl(vals::Pl::VERYHIGH);
w.set_en(true);
@ -625,12 +623,12 @@ impl<'a, C: Channel, W: Word> WritableRingBuffer<'a, C, W> {
let mut w = regs::Cr(0);
w.set_psize(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_teie(true);
w.set_htie(true);
w.set_tcie(true);
w.set_circ(vals::Circ::ENABLED);
w.set_circ(true);
w.set_pl(vals::Pl::VERYHIGH);
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.
pub fifo_threshold: Option<FifoThreshold>,
/// 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,
/// Enable half transfer interrupt
pub half_transfer_ir: bool,
@ -382,18 +386,13 @@ impl<'a, C: Channel> Transfer<'a, C> {
w.set_msize(data_size.into());
w.set_psize(data_size.into());
w.set_pl(vals::Pl::VERYHIGH);
w.set_minc(match incr_mem {
true => vals::Inc::INCREMENTED,
false => vals::Inc::FIXED,
});
w.set_pinc(vals::Inc::FIXED);
w.set_minc(incr_mem);
w.set_pinc(false);
w.set_teie(true);
w.set_tcie(options.complete_transfer_ir);
w.set_circ(options.circular);
if options.circular {
w.set_circ(vals::Circ::ENABLED);
debug!("Setting circular mode");
} else {
w.set_circ(vals::Circ::DISABLED);
}
#[cfg(dma_v1)]
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_psize(data_size.into());
w.set_pl(vals::Pl::VERYHIGH);
w.set_minc(vals::Inc::INCREMENTED);
w.set_pinc(vals::Inc::FIXED);
w.set_minc(true);
w.set_pinc(false);
w.set_teie(true);
w.set_tcie(true);
#[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_psize(data_size.into());
w.set_pl(vals::Pl::VERYHIGH);
w.set_minc(vals::Inc::INCREMENTED);
w.set_pinc(vals::Inc::FIXED);
w.set_minc(true);
w.set_pinc(false);
w.set_teie(true);
w.set_htie(options.half_transfer_ir);
w.set_tcie(true);
w.set_circ(vals::Circ::ENABLED);
w.set_circ(true);
#[cfg(dma_v1)]
w.set_trbuff(true);
#[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_psize(data_size.into());
w.set_pl(vals::Pl::VERYHIGH);
w.set_minc(vals::Inc::INCREMENTED);
w.set_pinc(vals::Inc::FIXED);
w.set_minc(true);
w.set_pinc(false);
w.set_teie(true);
w.set_htie(options.half_transfer_ir);
w.set_tcie(true);
w.set_circ(vals::Circ::ENABLED);
w.set_circ(true);
#[cfg(dma_v1)]
w.set_trbuff(true);
#[cfg(dma_v2)]

View File

@ -16,6 +16,7 @@ use crate::interrupt::Priority;
use crate::pac;
use crate::pac::gpdma::vals;
/// GPDMA transfer options.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[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;
/// DMA channel.
#[cfg(dmamux)]
pub trait Channel: sealed::Channel + Peripheral<P = Self> + 'static + super::dmamux::MuxChannel {}
/// DMA channel.
#[cfg(not(dmamux))]
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"]
pub struct Transfer<'a, C: Channel> {
channel: PeripheralRef<'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>(
channel: impl Peripheral<P = C> + 'a,
request: Request,
@ -147,6 +153,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
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>(
channel: impl Peripheral<P = C> + 'a,
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>(
channel: impl Peripheral<P = C> + 'a,
request: Request,
@ -182,6 +190,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
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>(
channel: impl Peripheral<P = C> + 'a,
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>(
channel: impl Peripheral<P = C> + 'a,
request: Request,
@ -297,6 +307,9 @@ impl<'a, C: Channel> Transfer<'a, C> {
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) {
let ch = self.channel.regs().ch(self.channel.num());
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 {
let ch = self.channel.regs().ch(self.channel.num());
let sr = ch.sr().read();
@ -317,6 +334,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
ch.br1().read().bndt()
}
/// Blocking wait until the transfer finishes.
pub fn blocking_wait(mut self) {
while self.is_running() {}

View File

@ -15,38 +15,42 @@ use crate::rcc::get_freqs;
use crate::time::Hertz;
use crate::Peripheral;
pub enum Source {
Master,
ChA,
ChB,
ChC,
ChD,
ChE,
#[cfg(hrtim_v2)]
ChF,
}
/// HRTIM burst controller instance.
pub struct BurstController<T: Instance> {
phantom: PhantomData<T>,
}
/// HRTIM master instance.
pub struct Master<T: Instance> {
phantom: PhantomData<T>,
}
/// HRTIM channel A instance.
pub struct ChA<T: Instance> {
phantom: PhantomData<T>,
}
/// HRTIM channel B instance.
pub struct ChB<T: Instance> {
phantom: PhantomData<T>,
}
/// HRTIM channel C instance.
pub struct ChC<T: Instance> {
phantom: PhantomData<T>,
}
/// HRTIM channel D instance.
pub struct ChD<T: Instance> {
phantom: PhantomData<T>,
}
/// HRTIM channel E instance.
pub struct ChE<T: Instance> {
phantom: PhantomData<T>,
}
/// HRTIM channel F instance.
#[cfg(hrtim_v2)]
pub struct ChF<T: Instance> {
phantom: PhantomData<T>,
@ -60,22 +64,26 @@ mod sealed {
}
}
/// Advanced channel instance trait.
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>,
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>,
phantom: PhantomData<(Perip, Channel)>,
phantom: PhantomData<(T, C)>,
}
macro_rules! advanced_channel_impl {
($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => {
impl<'d, Perip: Instance> PwmPin<'d, Perip, $channel<Perip>> {
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self {
impl<'d, T: Instance> PwmPin<'d, T, $channel<T>> {
#[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);
critical_section::with(|_| {
pin.set_low();
@ -90,8 +98,9 @@ macro_rules! advanced_channel_impl {
}
}
impl<'d, Perip: Instance> ComplementaryPwmPin<'d, Perip, $channel<Perip>> {
pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self {
impl<'d, T: Instance> ComplementaryPwmPin<'d, T, $channel<T>> {
#[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);
critical_section::with(|_| {
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
pub struct AdvancedPwm<'d, T: Instance> {
_inner: PeripheralRef<'d, T>,
/// Master instance.
pub master: Master<T>,
/// Burst controller.
pub burst_controller: BurstController<T>,
/// Channel A.
pub ch_a: ChA<T>,
/// Channel B.
pub ch_b: ChB<T>,
/// Channel C.
pub ch_c: ChC<T>,
/// Channel D.
pub ch_d: ChD<T>,
/// Channel E.
pub ch_e: ChE<T>,
/// Channel F.
#[cfg(hrtim_v2)]
pub ch_f: ChF<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(
tim: impl Peripheral<P = T> + 'd,
_cha: Option<PwmPin<'d, T, ChA<T>>>,
@ -200,13 +220,7 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> {
}
}
impl<T: Instance> BurstController<T> {
pub fn set_source(&mut self, _source: Source) {
todo!("burst mode control registers not implemented")
}
}
/// Represents a fixed-frequency bridge converter
/// Fixed-frequency bridge converter driver.
///
/// 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
@ -225,6 +239,7 @@ pub struct BridgeConverter<T: Instance, C: AdvancedChannel<T>> {
}
impl<T: Instance, C: AdvancedChannel<T>> BridgeConverter<T, C> {
/// Create a new HRTIM bridge converter driver.
pub fn new(_channel: C, frequency: Hertz) -> Self {
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) {
T::regs().mcr().modify(|w| w.set_tcen(C::raw(), true));
}
/// Stop HRTIM.
pub fn stop(&mut self) {
T::regs().mcr().modify(|w| w.set_tcen(C::raw(), false));
}
/// Enable burst mode.
pub fn enable_burst_mode(&mut self) {
T::regs().tim(C::raw()).outr().modify(|w| {
// 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) {
T::regs().tim(C::raw()).outr().modify(|w| {
// 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,
/// 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> {
/// Create a new variable-frequency resonant converter driver.
pub fn new(_channel: C, min_frequency: Hertz, max_frequency: Hertz) -> Self {
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);
}
/// Set the timer period.
pub fn set_period(&mut self, period: u16) {
assert!(period < self.max_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
fn set_channel_dead_time(channel: usize, dead_time: u16) {
let regs = Self::regs();
@ -148,13 +147,10 @@ pub(crate) mod sealed {
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 {}
foreach_interrupt! {

View File

@ -1,3 +1,5 @@
//! Inter-Process Communication Controller (IPCC)
use core::future::poll_fn;
use core::sync::atomic::{compiler_fence, Ordering};
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 {}
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]
#[derive(Clone, Copy, Default)]
pub struct Config {
@ -79,6 +83,8 @@ pub struct Config {
// reserved for future use
}
/// Channel.
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub enum IpccChannel {
@ -90,9 +96,11 @@ pub enum IpccChannel {
Channel6 = 5,
}
/// IPCC driver.
pub struct Ipcc;
impl Ipcc {
/// Enable IPCC.
pub fn enable(_config: Config) {
IPCC::enable_and_reset();
IPCC::set_cpu2(true);

View File

@ -1,5 +1,6 @@
#![cfg_attr(not(test), no_std)]
#![allow(async_fn_in_trait)]
#![warn(missing_docs)]
//! ## Feature flags
#![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(unused_imports)]
#![allow(non_snake_case)]
#![allow(missing_docs)]
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
/// 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
/// enter such low-power modes (currently, only `STOP2`) when idle.
///
/// 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
/// exceptions to this rule:
///
/// * `GPIO`
/// * `RCC`
///
/// 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
/// [`time_driver::MIN_STOP_PAUSE`] in the future.
///
/// 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
/// of the `RTC` peripheral to the executor. This will typically look like
///
/// ```rust,no_run
/// use embassy_executor::Spawner;
/// use embassy_stm32::low_power::Executor;
/// use embassy_stm32::rtc::{Rtc, RtcConfig};
/// use static_cell::make_static;
///
/// #[cortex_m_rt::entry]
/// fn main() -> ! {
/// Executor::take().run(|spawner| {
/// unwrap!(spawner.spawn(async_main(spawner)));
/// });
/// }
///
/// #[embassy_executor::task]
/// async fn async_main(spawner: Spawner) {
/// // initialize the platform...
/// let mut config = embassy_stm32::Config::default();
/// let p = embassy_stm32::init(config);
///
/// // give the RTC to the executor...
/// let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
/// let rtc = make_static!(rtc);
/// embassy_stm32::low_power::stop_with_rtc(rtc);
///
/// // your application here...
/// }
/// ```
//! Low-power support.
//!
//! The STM32 line of microcontrollers support various deep-sleep modes which exploit clock-gating
//! 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
//! enter such low-power modes (currently, only `STOP2`) when idle.
//!
//! 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
//! exceptions to this rule:
//!
//! * `GPIO`
//! * `RCC`
//!
//! 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
//! [`time_driver::MIN_STOP_PAUSE`] in the future.
//!
//! 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
//! of the `RTC` peripheral to the executor. This will typically look like
//!
//! ```rust,no_run
//! use embassy_executor::Spawner;
//! use embassy_stm32::low_power::Executor;
//! use embassy_stm32::rtc::{Rtc, RtcConfig};
//! use static_cell::StaticCell;
//!
//! #[cortex_m_rt::entry]
//! fn main() -> ! {
//! Executor::take().run(|spawner| {
//! unwrap!(spawner.spawn(async_main(spawner)));
//! });
//! }
//!
//! #[embassy_executor::task]
//! async fn async_main(spawner: Spawner) {
//! // initialize the platform...
//! let mut config = embassy_stm32::Config::default();
//! let p = embassy_stm32::init(config);
//!
//! // give the RTC to the executor...
//! let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
//! static RTC: StaticCell<Rtc> = StaticCell::new();
//! let rtc = RTC.init(rtc);
//! embassy_stm32::low_power::stop_with_rtc(rtc);
//!
//! // your application here...
//! }
//! ```
use core::arch::asm;
use core::marker::PhantomData;
use core::sync::atomic::{compiler_fence, Ordering};
@ -64,6 +68,7 @@ static mut EXECUTOR: Option<Executor> = None;
foreach_interrupt! {
(RTC, rtc, $block:ident, WKUP, $irq:ident) => {
#[interrupt]
#[allow(non_snake_case)]
unsafe fn $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();
}
/// Configure STOP mode with RTC.
pub fn stop_with_rtc(rtc: &'static 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 {
match unsafe { EXECUTOR.as_mut().unwrap() }.stop_mode() {
Some(StopMode::Stop2) => true,
@ -87,10 +97,13 @@ pub fn stop_ready(stop_mode: StopMode) -> bool {
}
}
/// Available stop modes.
#[non_exhaustive]
#[derive(PartialEq)]
pub enum StopMode {
/// STOP 1
Stop1,
/// STOP 2
Stop2,
}

View File

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

View File

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

View File

@ -14,6 +14,7 @@ use crate::pac::quadspi::Quadspi as Regs;
use crate::rcc::RccPeripheral;
use crate::{peripherals, Peripheral};
/// QSPI transfer configuration.
pub struct TransferConfig {
/// Instraction width (IMODE)
pub iwidth: QspiWidth,
@ -45,6 +46,7 @@ impl Default for TransferConfig {
}
}
/// QSPI driver configuration.
pub struct Config {
/// 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.
@ -71,6 +73,7 @@ impl Default for Config {
}
}
/// QSPI driver.
#[allow(dead_code)]
pub struct Qspi<'d, T: Instance, Dma> {
_peri: PeripheralRef<'d, T>,
@ -85,6 +88,7 @@ pub struct Qspi<'d, T: Instance, Dma> {
}
impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
/// Create a new QSPI driver for bank 1.
pub fn new_bk1(
peri: impl Peripheral<P = 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(
peri: impl Peripheral<P = 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) {
#[cfg(not(stm32h7))]
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));
}
/// Blocking read data.
pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) {
#[cfg(not(stm32h7))]
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));
}
/// Blocking write data.
pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) {
// STM32H7 does not have dmaen
#[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));
}
/// Blocking read data, using DMA.
pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig)
where
Dma: QuadDma<T>,
@ -310,6 +319,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
transfer.blocking_wait();
}
/// Blocking write data, using DMA.
pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig)
where
Dma: QuadDma<T>,
@ -379,6 +389,7 @@ pub(crate) mod sealed {
}
}
/// QSPI instance trait.
pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
pin_trait!(SckPin, Instance);

View File

@ -80,6 +80,7 @@ impl<'d, T: Instance> Rng<'d, T> {
let _ = self.next_u32();
}
/// Reset the RNG.
#[cfg(not(rng_v1))]
pub fn reset(&mut self) {
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 day = bcd2_to_byte((dr.dt(), dr.du()));
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)
})
@ -261,7 +261,7 @@ impl Rtc {
let (dt, du) = byte_to_bcd2(t.day() as u8);
let (mt, mu) = byte_to_bcd2(t.month() as u8);
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);
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
#[non_exhaustive]
#[allow(missing_docs)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
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))]
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@ -94,17 +98,23 @@ impl DerefMut for DataBlock {
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
/// Timeout reported by the hardware
Timeout,
/// Timeout reported by the software driver.
SoftwareTimeout,
/// Unsupported card version.
UnsupportedCardVersion,
/// Unsupported card type.
UnsupportedCardType,
/// CRC error.
Crc,
DataCrcFail,
RxOverFlow,
/// No card inserted.
NoCard,
/// Bad clock supplied to the SDMMC peripheral.
BadClock,
/// Signaling switch failed.
SignalingSwitchFailed,
PeripheralBusy,
/// ST bit error.
#[cfg(sdmmc_v1)]
StBitErr,
}
@ -283,6 +293,7 @@ pub struct Sdmmc<'d, T: Instance, Dma: SdmmcDma<T> = NoDma> {
#[cfg(sdmmc_v1)]
impl<'d, T: Instance, Dma: SdmmcDma<T>> Sdmmc<'d, T, Dma> {
/// Create a new SDMMC driver, with 1 data lane.
pub fn new_1bit(
sdmmc: impl Peripheral<P = 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(
sdmmc: impl Peripheral<P = 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)]
impl<'d, T: Instance> Sdmmc<'d, T, NoDma> {
/// Create a new SDMMC driver, with 1 data lane.
pub fn new_1bit(
sdmmc: impl Peripheral<P = 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(
sdmmc: impl Peripheral<P = 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
#[inline(always)]
#[inline]
fn data_active() -> bool {
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
#[inline(always)]
#[inline]
fn cmd_active() -> bool {
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)
#[inline(always)]
#[inline]
fn wait_idle() {
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
#[inline(always)]
#[inline]
fn clear_interrupt_flags() {
let regs = T::regs();
regs.icr().write(|w| {
@ -1152,7 +1166,8 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
Ok(())
}
#[inline(always)]
/// Read a data block.
#[inline]
pub async fn read_block(&mut self, block_idx: u32, buffer: &mut DataBlock) -> Result<(), Error> {
let card_capacity = self.card()?.card_type;
@ -1204,6 +1219,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
res
}
/// Write a data block.
pub async fn write_block(&mut self, block_idx: u32, buffer: &DataBlock) -> Result<(), Error> {
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)
/// has not previously succeeded
#[inline(always)]
#[inline]
pub fn card(&self) -> Result<&Card, Error> {
self.card.as_ref().ok_or(Error::NoCard)
}
@ -1419,7 +1435,9 @@ pub(crate) mod sealed {
pub trait Pins<T: Instance> {}
}
/// SDMMC instance trait.
pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
pin_trait!(CkPin, Instance);
pin_trait!(CmdPin, Instance);
pin_trait!(D0Pin, Instance);
@ -1434,7 +1452,10 @@ pin_trait!(D7Pin, Instance);
#[cfg(sdmmc_v1)]
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)]
pub trait SdmmcDma<T: Instance> {}
#[cfg(sdmmc_v2)]
@ -1517,53 +1538,3 @@ foreach_peripheral!(
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::{peripherals, Peripheral};
/// SPI error.
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
/// Invalid framing.
Framing,
/// CRC error (only if hardware CRC checking is enabled).
Crc,
/// Mode fault
ModeFault,
/// Overrun.
Overrun,
}
// TODO move upwards in the tree
/// SPI bit order
#[derive(Copy, Clone)]
pub enum BitOrder {
/// Least significant bit first.
LsbFirst,
/// Most significant bit first.
MsbFirst,
}
/// SPI configuration.
#[non_exhaustive]
#[derive(Copy, Clone)]
pub struct Config {
/// SPI mode.
pub mode: Mode,
/// Bit order.
pub bit_order: BitOrder,
/// Clock frequency.
pub frequency: Hertz,
}
@ -73,6 +84,7 @@ impl Config {
}
}
/// SPI driver.
pub struct Spi<'d, T: Instance, Tx, Rx> {
_peri: PeripheralRef<'d, T>,
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> {
/// Create a new SPI driver.
pub fn new(
peri: impl Peripheral<P = 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(
peri: impl Peripheral<P = 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(
peri: impl Peripheral<P = 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(
peri: impl Peripheral<P = 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(())
}
/// Get current SPI configuration.
pub fn get_current_config(&self) -> Config {
#[cfg(any(spi_v1, spi_f1, spi_v2))]
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;
}
/// SPI write, using DMA.
pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error>
where
Tx: TxDma<T>,
@ -477,6 +497,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
Ok(())
}
/// SPI read, using DMA.
pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error>
where
Tx: TxDma<T>,
@ -580,6 +601,12 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
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>
where
Tx: TxDma<T>,
@ -588,6 +615,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
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>
where
Tx: TxDma<T>,
@ -596,6 +626,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
self.transfer_inner(data, data).await
}
/// Blocking write.
pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
T::REGS.cr1().modify(|w| w.set_spe(true));
flush_rx_fifo(T::REGS);
@ -606,6 +637,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
Ok(())
}
/// Blocking read.
pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
T::REGS.cr1().modify(|w| w.set_spe(true));
flush_rx_fifo(T::REGS);
@ -616,6 +648,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
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> {
T::REGS.cr1().modify(|w| w.set_spe(true));
flush_rx_fifo(T::REGS);
@ -626,6 +661,12 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> {
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> {
T::REGS.cr1().modify(|w| w.set_spe(true));
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 {}
macro_rules! impl_word {
@ -1025,7 +1067,9 @@ mod word_impl {
impl_word!(u32, 32 - 1);
}
/// SPI instance trait.
pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
pin_trait!(SckPin, Instance);
pin_trait!(MosiPin, Instance);
pin_trait!(MisoPin, Instance);

View File

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

View File

@ -13,15 +13,19 @@ use crate::gpio::{AnyPin, OutputType};
use crate::time::Hertz;
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>,
phantom: PhantomData<(Perip, Channel)>,
phantom: PhantomData<(T, C)>,
}
macro_rules! complementary_channel_impl {
($new_chx:ident, $channel:ident, $pin_trait:ident) => {
impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> {
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd, output_type: OutputType) -> Self {
impl<'d, T: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, T, $channel> {
#[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);
critical_section::with(|_| {
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_ch4, Ch4, Channel4ComplementaryPin);
/// PWM driver with support for standard and complementary outputs.
pub struct ComplementaryPwm<'d, T> {
inner: PeripheralRef<'d, T>,
}
impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
/// Create a new complementary PWM driver.
pub fn new(
tim: impl Peripheral<P = T> + 'd,
_ch1: Option<PwmPin<'d, T, Ch1>>,
@ -72,7 +78,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
let mut this = Self { inner: tim };
this.inner.set_counting_mode(counting_mode);
this.set_freq(freq);
this.set_frequency(freq);
this.inner.start();
this.inner.enable_outputs();
@ -88,17 +94,23 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
this
}
/// Enable the given channel.
pub fn enable(&mut self, channel: Channel) {
self.inner.enable_channel(channel, true);
self.inner.enable_complementary_channel(channel, true);
}
/// Disable the given channel.
pub fn disable(&mut self, channel: Channel) {
self.inner.enable_complementary_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() {
2u8
} else {
@ -107,15 +119,22 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
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 {
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) {
assert!(duty <= self.get_max_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) {
self.inner.set_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 {
use super::*;
/// Basic 16-bit timer instance.
pub trait Basic16bitInstance: RccPeripheral {
/// Interrupt for this timer.
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;
/// Start the timer.
fn start(&mut self) {
Self::regs().cr1().modify(|r| r.set_cen(true));
}
/// Stop the timer.
fn stop(&mut self) {
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));
}
/// Clear update interrupt.
///
/// Returns whether the update interrupt flag was set.
fn clear_update_interrupt(&mut self) -> bool {
let regs = Self::regs();
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) {
Self::regs().dier().write(|r| r.set_uie(enable));
}
/// Enable/disable autoreload preload.
fn set_autoreload_preload(&mut self, enable: bool) {
Self::regs().cr1().modify(|r| r.set_arpe(enable));
}
/// Get the timer frequency.
fn get_frequency(&self) -> Hertz {
let timer_f = Self::frequency();
@ -95,9 +111,17 @@ pub(crate) mod sealed {
}
}
/// Gneral-purpose 16-bit timer instance.
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;
/// Set counting mode.
fn set_counting_mode(&mut self, mode: CountingMode) {
let (cms, dir) = mode.into();
@ -110,19 +134,29 @@ pub(crate) mod sealed {
Self::regs_gp16().cr1().modify(|r| r.set_cms(cms))
}
/// Get counting mode.
fn get_counting_mode(&self) -> CountingMode {
let cr1 = Self::regs_gp16().cr1().read();
(cr1.cms(), cr1.dir()).into()
}
/// Set clock divider.
fn set_clock_division(&mut self, ckd: vals::Ckd) {
Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd));
}
}
/// Gneral-purpose 32-bit timer instance.
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;
/// Set timer frequency.
fn set_frequency(&mut self, frequency: Hertz) {
let f = frequency.0;
assert!(f > 0);
@ -140,6 +174,7 @@ pub(crate) mod sealed {
regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
}
/// Get timer frequency.
fn get_frequency(&self) -> Hertz {
let timer_f = Self::frequency();
@ -151,141 +186,177 @@ pub(crate) mod sealed {
}
}
/// Advanced control timer instance.
pub trait AdvancedControlInstance: GeneralPurpose16bitInstance {
/// Get access to the advanced timer registers.
fn regs_advanced() -> crate::pac::timer::TimAdv;
}
/// Capture/Compare 16-bit timer instance.
pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance {
/// Set input capture filter.
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()
.ccmr_input(raw_channel / 2)
.modify(|r| r.set_icf(raw_channel % 2, icf));
}
/// Clear input interrupt.
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) {
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) {
let raw_channel = channel.raw();
let raw_channel = channel.index();
Self::regs_gp16()
.ccmr_input(raw_channel / 2)
.modify(|r| r.set_icpsc(raw_channel % 2, factor));
}
/// Set input TI selection.
fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) {
let raw_channel = channel.raw();
let raw_channel = channel.index();
Self::regs_gp16()
.ccmr_input(raw_channel / 2)
.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) {
Self::regs_gp16().ccer().modify(|r| match mode {
InputCaptureMode::Rising => {
r.set_ccnp(channel.raw(), false);
r.set_ccp(channel.raw(), false);
r.set_ccnp(channel.index(), false);
r.set_ccp(channel.index(), false);
}
InputCaptureMode::Falling => {
r.set_ccnp(channel.raw(), false);
r.set_ccp(channel.raw(), true);
r.set_ccnp(channel.index(), false);
r.set_ccp(channel.index(), true);
}
InputCaptureMode::BothEdges => {
r.set_ccnp(channel.raw(), true);
r.set_ccp(channel.raw(), true);
r.set_ccnp(channel.index(), true);
r.set_ccp(channel.index(), true);
}
});
}
/// Enable timer outputs.
fn enable_outputs(&mut self);
/// Set output compare mode.
fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) {
let r = Self::regs_gp16();
let raw_channel: usize = channel.raw();
let raw_channel: usize = channel.index();
r.ccmr_output(raw_channel / 2)
.modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
}
/// Set output polarity.
fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
Self::regs_gp16()
.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) {
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) {
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 {
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 {
Self::regs_gp16().arr().read().arr()
}
/// Get compare value for a channel.
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 {
/// Set complementary output polarity.
fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
Self::regs_advanced()
.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) {
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) {
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) {
Self::regs_advanced()
.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 {
/// Set comapre value for a channel.
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 {
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 {
Self::regs_gp32().arr().read().arr()
}
/// Get compare value for a channel.
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)]
pub enum Channel {
/// Channel 1.
Ch1,
/// Channel 2.
Ch2,
/// Channel 3.
Ch3,
/// Channel 4.
Ch4,
}
impl Channel {
pub fn raw(&self) -> usize {
/// Get the channel index (0..3)
pub fn index(&self) -> usize {
match self {
Channel::Ch1 => 0,
Channel::Ch2 => 1,
@ -295,17 +366,25 @@ impl Channel {
}
}
/// Input capture mode.
#[derive(Clone, Copy)]
pub enum InputCaptureMode {
/// Rising edge only.
Rising,
/// Falling edge only.
Falling,
/// Both rising or falling edges.
BothEdges,
}
/// Input TI selection.
#[derive(Clone, Copy)]
pub enum InputTISelection {
/// Normal
Normal,
/// Alternate
Alternate,
/// TRC
TRC,
}
@ -319,6 +398,7 @@ impl From<InputTISelection> for stm32_metapac::timer::vals::CcmrInputCcs {
}
}
/// Timer counting mode.
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum CountingMode {
@ -345,6 +425,7 @@ pub enum CountingMode {
}
impl CountingMode {
/// Return whether this mode is edge-aligned (up or down).
pub fn is_edge_aligned(&self) -> bool {
match self {
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 {
match self {
CountingMode::CenterAlignedDownInterrupts
@ -386,16 +468,34 @@ impl From<(vals::Cms, vals::Dir)> for CountingMode {
}
}
/// Output compare mode.
#[derive(Clone, Copy)]
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,
/// 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,
/// 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,
/// Toggle - OCxREF toggles when TIMx_CNT=TIMx_CCRx.
Toggle,
/// Force inactive level - OCxREF is forced low.
ForceInactive,
/// Force active level - OCxREF is forced high.
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,
/// 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,
// TODO: there's more modes here depending on the chip family.
}
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)]
pub enum OutputPolarity {
/// Active high (higher duty value makes the pin spend more time high).
ActiveHigh,
/// Active low (higher duty value makes the pin spend more time low).
ActiveLow,
}
@ -428,24 +531,31 @@ impl From<OutputPolarity> for bool {
}
}
/// Basic 16-bit timer instance.
pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {}
/// Gneral-purpose 16-bit timer instance.
pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {}
/// Gneral-purpose 32-bit timer instance.
pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {}
/// Advanced control timer instance.
pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {}
/// Capture/Compare 16-bit timer instance.
pub trait CaptureCompare16bitInstance:
sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static
{
}
/// Capture/Compare 16-bit timer instance with complementary pin support.
pub trait ComplementaryCaptureCompare16bitInstance:
sealed::ComplementaryCaptureCompare16bitInstance + AdvancedControlInstance + 'static
{
}
/// Capture/Compare 32-bit timer instance.
pub trait CaptureCompare32bitInstance:
sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static
{

View File

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

View File

@ -11,20 +11,28 @@ use crate::gpio::{AnyPin, OutputType};
use crate::time::Hertz;
use crate::Peripheral;
pub struct Ch1;
pub struct Ch2;
pub struct Ch3;
pub struct Ch4;
/// Channel 1 marker type.
pub enum Ch1 {}
/// Channel 2 marker type.
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>,
phantom: PhantomData<(Perip, Channel)>,
phantom: PhantomData<(T, C)>,
}
macro_rules! channel_impl {
($new_chx:ident, $channel:ident, $pin_trait:ident) => {
impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> {
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd, output_type: OutputType) -> Self {
impl<'d, T: CaptureCompare16bitInstance> PwmPin<'d, T, $channel> {
#[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);
critical_section::with(|_| {
pin.set_low();
@ -46,11 +54,13 @@ channel_impl!(new_ch2, Ch2, Channel2Pin);
channel_impl!(new_ch3, Ch3, Channel3Pin);
channel_impl!(new_ch4, Ch4, Channel4Pin);
/// Simple PWM driver.
pub struct SimplePwm<'d, T> {
inner: PeripheralRef<'d, T>,
}
impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
/// Create a new simple PWM driver.
pub fn new(
tim: impl Peripheral<P = T> + 'd,
_ch1: Option<PwmPin<'d, T, Ch1>>,
@ -71,7 +81,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
let mut this = Self { inner: tim };
this.inner.set_counting_mode(counting_mode);
this.set_freq(freq);
this.set_frequency(freq);
this.inner.start();
this.inner.enable_outputs();
@ -87,15 +97,21 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
this
}
/// Enable the given channel.
pub fn enable(&mut self, channel: Channel) {
self.inner.enable_channel(channel, true);
}
/// Disable the given channel.
pub fn disable(&mut self, channel: Channel) {
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() {
2u8
} else {
@ -104,15 +120,22 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
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 {
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) {
assert!(duty <= self.get_max_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) {
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 {
rx_waker: AtomicWaker,
rx_buf: RingBuffer,
@ -91,6 +92,7 @@ pub struct State {
}
impl State {
/// Create new state
pub const fn new() -> Self {
Self {
rx_buf: RingBuffer::new(),
@ -101,15 +103,18 @@ impl State {
}
}
/// Bidirectional buffered UART
pub struct BufferedUart<'d, T: BasicInstance> {
rx: BufferedUartRx<'d, T>,
tx: BufferedUartTx<'d, T>,
}
/// Tx-only buffered UART
pub struct BufferedUartTx<'d, T: BasicInstance> {
phantom: PhantomData<&'d mut T>,
}
/// Rx-only buffered UART
pub struct BufferedUartRx<'d, T: BasicInstance> {
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> {
/// Create a new bidirectional buffered UART driver
pub fn new(
peri: impl Peripheral<P = 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)
}
/// Create a new bidirectional buffered UART driver with request-to-send and clear-to-send pins
pub fn new_with_rtscts(
peri: impl Peripheral<P = 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)
}
/// Create a new bidirectional buffered UART driver with a driver-enable pin
#[cfg(not(any(usart_v1, usart_v2)))]
pub fn new_with_de(
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>) {
(self.tx, self.rx)
}
/// Reconfigure the driver
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
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> {
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> {
reconfigure::<T>(config)?;

View File

@ -1,5 +1,6 @@
//! Universal Synchronous/Asynchronous Receiver Transmitter (USART, UART, LPUART)
#![macro_use]
#![warn(missing_docs)]
use core::future::poll_fn;
use core::marker::PhantomData;
@ -77,21 +78,29 @@ impl<T: BasicInstance> interrupt::typelevel::Handler<T::Interrupt> for Interrupt
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Number of data bits
pub enum DataBits {
/// 8 Data Bits
DataBits8,
/// 9 Data Bits
DataBits9,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Parity
pub enum Parity {
/// No parity
ParityNone,
/// Even Parity
ParityEven,
/// Odd Parity
ParityOdd,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Number of stop bits
pub enum StopBits {
#[doc = "1 stop bit"]
STOP1,
@ -106,26 +115,37 @@ pub enum StopBits {
#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Config Error
pub enum ConfigError {
/// Baudrate too low
BaudrateTooLow,
/// Baudrate too high
BaudrateTooHigh,
/// Rx or Tx not enabled
RxOrTxNotEnabled,
}
#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
/// Config
pub struct Config {
/// Baud rate
pub baudrate: u32,
/// Number of data bits
pub data_bits: DataBits,
/// Number of stop bits
pub stop_bits: StopBits,
/// Parity type
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 false, the error is ignored and cleared
/// If true: on a read-like method, if there is a latent error pending,
/// 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,
/// 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.
#[cfg(not(usart_v1))]
pub assume_noise_free: bool,
@ -141,6 +161,10 @@ pub struct Config {
/// Set this to true to invert RX pin signal values (V<sub>DD</sub> =0/mark, Gnd = 1/idle).
#[cfg(any(usart_v3, usart_v4))]
pub invert_rx: bool,
/// enable single wire half duplex communication. Only the tx pin is used. Needs an external
/// pull up
pub half_duplex: bool,
}
impl Default for Config {
@ -160,6 +184,7 @@ impl Default for Config {
invert_tx: false,
#[cfg(any(usart_v3, usart_v4))]
invert_rx: false,
half_duplex: false,
}
}
}
@ -188,6 +213,7 @@ enum ReadCompletionEvent {
Idle(usize),
}
/// Bidirectional UART Driver
pub struct Uart<'d, T: BasicInstance, TxDma = NoDma, RxDma = NoDma> {
tx: UartTx<'d, T, TxDma>,
rx: UartRx<'d, T, RxDma>,
@ -203,6 +229,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> {
phantom: PhantomData<&'d mut T>,
tx_dma: PeripheralRef<'d, TxDma>,
@ -217,6 +244,7 @@ impl<'d, T: BasicInstance, TxDma> SetConfig for UartTx<'d, T, TxDma> {
}
}
/// Rx-only UART Driver
pub struct UartRx<'d, T: BasicInstance, RxDma = NoDma> {
_peri: PeripheralRef<'d, T>,
rx_dma: PeripheralRef<'d, RxDma>,
@ -247,6 +275,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
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(
peri: impl Peripheral<P = T> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
@ -288,10 +317,12 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
})
}
/// Reconfigure the driver
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config)
}
/// Initiate an asynchronous UART write
pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error>
where
TxDma: crate::usart::TxDma<T>,
@ -308,6 +339,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
Ok(())
}
/// Perform a blocking UART write
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
let r = T::regs();
for &b in buffer {
@ -317,6 +349,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> {
Ok(())
}
/// Block until transmission complete
pub fn blocking_flush(&mut self) -> Result<(), Error> {
let r = T::regs();
while !sr(r).read().tc() {}
@ -338,6 +371,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
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(
peri: impl Peripheral<P = T> + 'd,
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
@ -387,6 +421,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
})
}
/// Reconfigure the driver
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
reconfigure::<T>(config)
}
@ -444,6 +479,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
Ok(sr.rxne())
}
/// Initiate an asynchronous UART read
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error>
where
RxDma: crate::usart::RxDma<T>,
@ -453,6 +489,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
Ok(())
}
/// Read a single u8 if there is one available, otherwise return WouldBlock
pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
let r = T::regs();
if self.check_rx_flags()? {
@ -462,6 +499,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> {
let r = T::regs();
for b in buffer {
@ -471,6 +509,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> {
Ok(())
}
/// Initiate an asynchronous read with idle line detection enabled
pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error>
where
RxDma: crate::usart::RxDma<T>,
@ -695,6 +734,7 @@ impl<'d, T: BasicInstance, TxDma> Drop for UartRx<'d, T, TxDma> {
}
impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
/// Create a new bidirectional UART
pub fn new(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
@ -711,6 +751,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
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(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
@ -738,6 +779,7 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
}
#[cfg(not(any(usart_v1, usart_v2)))]
/// Create a new bidirectional UART with a driver-enable pin
pub fn new_with_de(
peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
@ -774,19 +816,27 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
let r = T::regs();
// Some chips do not have swap_rx_tx bit
cfg_if::cfg_if! {
if #[cfg(any(usart_v3, usart_v4))] {
if config.swap_rx_tx {
let (rx, tx) = (tx, rx);
rx.set_as_af(rx.af_num(), AFType::Input);
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
if config.half_duplex {
if config.swap_rx_tx {
rx.set_as_af(rx.af_num(), AFType::OutputOpenDrain);
} else {
tx.set_as_af(tx.af_num(), AFType::OutputOpenDrain);
}
} else {
cfg_if::cfg_if! {
if #[cfg(any(usart_v3, usart_v4))] {
if config.swap_rx_tx {
let (rx, tx) = (tx, rx);
rx.set_as_af(rx.af_num(), AFType::Input);
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
} else {
rx.set_as_af(rx.af_num(), AFType::Input);
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
}
} else {
rx.set_as_af(rx.af_num(), AFType::Input);
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
}
} else {
rx.set_as_af(rx.af_num(), AFType::Input);
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
}
}
@ -813,6 +863,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>
where
TxDma: crate::usart::TxDma<T>,
@ -820,14 +871,17 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
self.tx.write(buffer).await
}
/// Perform a blocking write
pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
self.tx.blocking_write(buffer)
}
/// Block until transmission complete
pub fn blocking_flush(&mut self) -> Result<(), Error> {
self.tx.blocking_flush()
}
/// Initiate an asynchronous read into `buffer`
pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error>
where
RxDma: crate::usart::RxDma<T>,
@ -835,14 +889,17 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> {
self.rx.read(buffer).await
}
/// Read a single `u8` or return `WouldBlock`
pub fn nb_read(&mut self) -> Result<u8, nb::Error<Error>> {
self.rx.nb_read()
}
/// Perform a blocking read into `buffer`
pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
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>
where
RxDma: crate::usart::RxDma<T>,
@ -995,6 +1052,7 @@ fn configure(
#[cfg(not(usart_v1))]
r.cr3().modify(|w| {
w.set_onebit(config.assume_noise_free);
w.set_hdsel(config.half_duplex);
});
r.cr1().write(|w| {
@ -1292,8 +1350,10 @@ pub(crate) mod sealed {
}
}
/// Basic UART driver instance
pub trait BasicInstance: Peripheral<P = Self> + sealed::BasicInstance + 'static + Send {}
/// Full UART driver instance
pub trait FullInstance: sealed::FullInstance {}
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::usart::{Regs, Sr};
/// Rx-only Ring-buffered UART Driver
pub struct RingBufferedUartRx<'d, T: BasicInstance, RxDma: super::RxDma<T>> {
_peri: PeripheralRef<'d, T>,
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> {
/// 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
/// DMA controller, and must be sufficiently large, such that it will not overflow.
/// without the possibility of losing bytes. The `dma_buf` is a buffer registered to the
/// 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> {
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> {
/// Clear the ring buffer and start receiving in the background
pub fn start(&mut self) -> Result<(), Error> {
// Clear the ring buffer so that it is ready to receive data
self.ring_buf.clear();
@ -64,6 +66,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma<T>> RingBufferedUartRx<'d, T, RxD
Err(err)
}
/// Cleanly stop and reconfigure the driver
pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> {
self.teardown_uart();
reconfigure::<T>(config)

View File

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

View File

@ -244,6 +244,7 @@ struct EndpointData {
used_out: bool,
}
/// USB driver.
pub struct Driver<'d, T: Instance> {
phantom: PhantomData<&'d mut T>,
alloc: [EndpointData; EP_COUNT],
@ -251,6 +252,7 @@ pub struct Driver<'d, T: Instance> {
}
impl<'d, T: Instance> Driver<'d, T> {
/// Create a new USB driver.
pub fn new(
_usb: impl Peripheral<P = 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> {
phantom: PhantomData<&'d mut T>,
ep_types: [EpType; EP_COUNT - 1],
@ -640,6 +643,7 @@ trait Dir {
fn waker(i: usize) -> &'static AtomicWaker;
}
/// Marker type for the "IN" direction.
pub enum In {}
impl Dir for In {
fn dir() -> Direction {
@ -652,6 +656,7 @@ impl Dir for In {
}
}
/// Marker type for the "OUT" direction.
pub enum Out {}
impl Dir for Out {
fn dir() -> Direction {
@ -664,6 +669,7 @@ impl Dir for Out {
}
}
/// USB endpoint.
pub struct Endpoint<'d, T: Instance, D> {
_phantom: PhantomData<(&'d mut T, D)>,
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> {
_phantom: PhantomData<&'d mut T>,
max_packet_size: u16,

View File

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

View File

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

View File

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

View File

@ -111,6 +111,20 @@ where
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.
pub fn signaled(&self) -> bool {
self.state.lock(|cell| {

View File

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

20
embassy-usb-dfu/README.md Normal file
View File

@ -0,0 +1,20 @@
# embassy-usb-dfu
An implementation of the USB DFU 1.1 protocol using embassy-boot. It has 2 components depending on which feature is enabled by the user.
* DFU protocol mode, enabled by the `dfu` feature. This mode corresponds to the transfer phase DFU protocol described by the USB IF. It supports DFU_DNLOAD requests if marked by the user, and will automatically reset the chip once a DFU transaction has been completed. It also responds to DFU_GETSTATUS, DFU_GETSTATE, DFU_ABORT, and DFU_CLRSTATUS with no user intervention.
* DFU runtime mode, enabled by the `application feature`. This mode allows users to expose a DFU interface on their USB device, informing the host of the capability to DFU over USB, and allowing the host to reset the device into its bootloader to complete a DFU operation. Supports DFU_GETSTATUS and DFU_DETACH. When detach/reset is seen by the device as described by the standard, will write a new DFU magic number into the bootloader state in flash, and reset the system.
## Minimum supported Rust version (MSRV)
Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release.
## 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

@ -24,6 +24,7 @@ pub struct Control<'d, STATE: NorFlash, RST: Reset> {
}
impl<'d, STATE: NorFlash, RST: Reset> Control<'d, STATE, RST> {
/// Create a new DFU instance to expose a DFU interface.
pub fn new(firmware_state: BlockingFirmwareState<'d, STATE>, attrs: DfuAttributes) -> Self {
Control {
firmware_state,
@ -72,6 +73,8 @@ impl<'d, STATE: NorFlash, RST: Reset> Handler for Control<'d, STATE, RST> {
self.detach_start = Some(Instant::now());
self.timeout = Some(Duration::from_millis(req.value as u64));
self.state = State::AppDetach;
// hack to make it work together with usb serial logging
self.reset();
Some(OutResponse::Accepted)
}
_ => None,

View File

@ -1,3 +1,4 @@
//! USB DFU constants.
pub(crate) const USB_CLASS_APPN_SPEC: u8 = 0xFE;
pub(crate) const APPN_SPEC_SUBCLASS_DFU: u8 = 0x01;
#[allow(unused)]
@ -18,10 +19,15 @@ defmt::bitflags! {
#[cfg(not(feature = "defmt"))]
bitflags::bitflags! {
/// Attributes supported by the DFU controller.
pub struct DfuAttributes: u8 {
/// Generate WillDetache sequence on bus.
const WILL_DETACH = 0b0000_1000;
/// Device can communicate during manifestation phase.
const MANIFESTATION_TOLERANT = 0b0000_0100;
/// Capable of upload.
const CAN_UPLOAD = 0b0000_0010;
/// Capable of download.
const CAN_DOWNLOAD = 0b0000_0001;
}
}
@ -29,7 +35,7 @@ bitflags::bitflags! {
#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
#[allow(unused)]
pub enum State {
pub(crate) enum State {
AppIdle = 0,
AppDetach = 1,
DfuIdle = 2,
@ -46,7 +52,7 @@ pub enum State {
#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
#[allow(unused)]
pub enum Status {
pub(crate) enum Status {
Ok = 0x00,
ErrTarget = 0x01,
ErrFile = 0x02,
@ -67,7 +73,7 @@ pub enum Status {
#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
pub enum Request {
pub(crate) enum Request {
Detach = 0,
Dnload = 1,
Upload = 2,

View File

@ -23,6 +23,7 @@ pub struct Control<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_S
}
impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Control<'d, DFU, STATE, RST, BLOCK_SIZE> {
/// Create a new DFU instance to handle DFU transfers.
pub fn new(updater: BlockingFirmwareUpdater<'d, DFU, STATE>, attrs: DfuAttributes) -> Self {
Self {
updater,

View File

@ -1,12 +1,14 @@
#![no_std]
#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
mod fmt;
pub mod consts;
#[cfg(feature = "dfu")]
mod bootloader;
mod dfu;
#[cfg(feature = "dfu")]
pub use self::bootloader::*;
pub use self::dfu::*;
#[cfg(feature = "application")]
mod application;
@ -17,7 +19,7 @@ pub use self::application::*;
all(feature = "dfu", feature = "application"),
not(any(feature = "dfu", feature = "application"))
))]
compile_error!("usb-dfu must be compiled with exactly one of `bootloader`, or `application` features");
compile_error!("usb-dfu must be compiled with exactly one of `dfu`, or `application` features");
/// Provides a platform-agnostic interface for initiating a system reset.
///
@ -26,9 +28,11 @@ compile_error!("usb-dfu must be compiled with exactly one of `bootloader`, or `a
///
/// If alternate behaviour is desired, a custom implementation of Reset can be provided as a type argument to the usb_dfu function.
pub trait Reset {
/// Reset the device.
fn sys_reset() -> !;
}
/// Reset immediately.
#[cfg(feature = "esp32c3-hal")]
pub struct ResetImmediate;
@ -40,6 +44,7 @@ impl Reset for ResetImmediate {
}
}
/// Reset immediately.
#[cfg(feature = "cortex-m")]
pub struct ResetImmediate;

View File

@ -13,3 +13,17 @@ async fn logger_task(driver: Driver<'static, USB>) {
embassy_usb_logger::run!(1024, log::LevelFilter::Info, driver);
}
```
## Minimum supported Rust version (MSRV)
Embassy is guaranteed to compile on the latest stable Rust version at the time of release. It might compile with older versions but that may change in any new patch release.
## 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

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
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-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", ] }
embassy-boot = { version = "0.1.0", path = "../../../../embassy-boot/boot", features = [] }

View File

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

View File

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

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
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-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", ] }
embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot/rp", features = [] }

View File

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

View File

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

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
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-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" }

View File

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

View File

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

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
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-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 = [] }

View File

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

View File

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

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
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-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 = [] }

View File

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

View File

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

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
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-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 = [] }

View File

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

View File

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

View File

@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
[dependencies]
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-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 = [] }

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