Compare commits
239 Commits
Author | SHA1 | Date | |
---|---|---|---|
3b7fec6efc | |||
731df8be49 | |||
2849bfcc6b | |||
a4b20fc943 | |||
8bb48f3083 | |||
d7ce823d79 | |||
e7ab044935 | |||
0c4cddfafb | |||
e561e673c2 | |||
09dfcd6b66 | |||
bb8a1b7f1f | |||
b012a67df7 | |||
40f30fa4cd | |||
f197aa9419 | |||
80a740bc72 | |||
ad524373ed | |||
9badf740d8 | |||
6e901846df | |||
c0a6c78a14 | |||
58280048e3 | |||
00824af82b | |||
adf9ffb109 | |||
bc203ebe4b | |||
e042b3056d | |||
9dc927250c | |||
b856d760f4 | |||
a742a80171 | |||
90ade1b311 | |||
a931dfd9ad | |||
eff61648fe | |||
9228a6334b | |||
3c9dfbbc9d | |||
ce0add61f8 | |||
bf6e06060b | |||
eb12114345 | |||
4b252586e5 | |||
5f6a915a32 | |||
923f1851ee | |||
bd267a6479 | |||
f3aa0cfe5a | |||
6ea5aa347d | |||
8c13126cff | |||
81da9ca621 | |||
729338875c | |||
f98c8886b2 | |||
a1036e111e | |||
2af97e7595 | |||
2008030a8b | |||
480328d07e | |||
05218a52e6 | |||
d2a2734752 | |||
5ad34404af | |||
a7b1e51650 | |||
70005c3956 | |||
93adbb9922 | |||
e80df91e02 | |||
5cb58754d4 | |||
5c83179071 | |||
49608714aa | |||
f116ca83e0 | |||
6e5f3f9515 | |||
5924cc8b49 | |||
0d49aaf8ca | |||
5dd9e9b3b7 | |||
d42cfda2db | |||
d1f4511cd1 | |||
fa8d5da4a5 | |||
7bc57ca3f7 | |||
7ad102695d | |||
4999de6f82 | |||
9b8bdad403 | |||
3c3fb0a529 | |||
dc4c27aead | |||
74eb519810 | |||
61dc36b1f2 | |||
55a0a15be2 | |||
fc8f96fea5 | |||
08175f191a | |||
8da987cfbb | |||
1be5f193c3 | |||
4a632e08b7 | |||
6cdee93934 | |||
5c8c1b2146 | |||
2addfc4b86 | |||
92df87781d | |||
a35d149cb1 | |||
c52320f467 | |||
2f9b59c5cf | |||
ce91fb2bfc | |||
95b3d9eb3b | |||
f1e7205055 | |||
6627824c02 | |||
d62533879c | |||
e1a8caffa4 | |||
dffdb9268b | |||
22e820b743 | |||
aa14f18d3f | |||
39f1b26a39 | |||
e70143ef8f | |||
d6654bf8b5 | |||
322a4a8401 | |||
ee5591017b | |||
b1b32f079b | |||
e8a462768e | |||
ce0d787781 | |||
fa2e63f74b | |||
23f3889167 | |||
a72a91ab06 | |||
b9ef831ff7 | |||
e538aeacc8 | |||
6b3745fc47 | |||
6200d22438 | |||
901d31e8f8 | |||
79146c4bd5 | |||
d9eae79f3e | |||
3d1b4116ec | |||
901f0257bd | |||
fec4194ae6 | |||
f866735802 | |||
20ea76c19c | |||
e1951f3ddf | |||
8b5fb254c0 | |||
624f786203 | |||
a57e48459e | |||
c604d8a8f1 | |||
be0c52bf5e | |||
44bb405683 | |||
e8587e2fba | |||
5d8817d109 | |||
c79a84a98a | |||
96edbd84fb | |||
dc400a0539 | |||
04b09a2acb | |||
481d2998ef | |||
4b695120fc | |||
bd9021ca1d | |||
6e63c8d4bf | |||
70acc093dd | |||
f7c2db245f | |||
2543bcafaf | |||
9f2fc04caa | |||
f32bfafa61 | |||
e03239e88d | |||
7d5e62d4a7 | |||
65d36f9f99 | |||
347ff18644 | |||
1e80fd81f7 | |||
52e269edbb | |||
c849620cd6 | |||
6f83acc010 | |||
2b7b7a917d | |||
f1488864eb | |||
7cf327130e | |||
02b0523199 | |||
47175198c0 | |||
4b20e6c258 | |||
83b4c01273 | |||
e313ca4ae8 | |||
ad64d7b20b | |||
5626a28af2 | |||
766ae724cb | |||
00b9f9acef | |||
d46920dce6 | |||
e1ed492577 | |||
2405aff11f | |||
a402aed3d1 | |||
c573959a95 | |||
561696dfad | |||
b1abaa380f | |||
e640933e2f | |||
183824fbdd | |||
5d0c40f61d | |||
fdfe12fe1c | |||
4bfbcd6c72 | |||
0da793e5de | |||
0dcb34fc7d | |||
feaeee1e83 | |||
a6ef314be1 | |||
daeb497045 | |||
88eb5cca71 | |||
cd128c20fa | |||
087ef918bf | |||
75cae09e79 | |||
bbe1d96045 | |||
3ddc9cd110 | |||
de2773afdd | |||
2930be5e17 | |||
09f087e53e | |||
044b837caa | |||
ad0a306ea5 | |||
b5fffbf66f | |||
537e2f3b44 | |||
80d7193b5b | |||
8315cf064e | |||
a2a26f489b | |||
f27620cc0b | |||
2911774849 | |||
6da75ea285 | |||
aa2fa29b89 | |||
c28a6bdd0b | |||
5a158b94bd | |||
c091ed2f63 | |||
45e9e51bdc | |||
7c77d2bd94 | |||
f76d94098d | |||
07233ca5b4 | |||
9fb14379c3 | |||
309c3d6b47 | |||
f1f4943ca5 | |||
1b20ba27b1 | |||
f5e96a9d60 | |||
e8b961232b | |||
85a9f5816f | |||
7bcc7e8962 | |||
b118c4cc1b | |||
f090a38dde | |||
dcd1a91966 | |||
49847ff432 | |||
b9d4b18f14 | |||
3a1ed823f8 | |||
9c647dd0e8 | |||
582ef90994 | |||
5e381d49da | |||
af59fa0a7e | |||
4907ccaa4d | |||
2c38dd17b9 | |||
d36e7abb71 | |||
e11db9fa59 | |||
f877a5889d | |||
db54edf56c | |||
4072a16af6 | |||
44a5c32ea4 | |||
b9889ad3b5 | |||
527bdc57b9 | |||
de01fe352b | |||
70662ec4ba | |||
f033089625 | |||
6d8a5c6c20 | |||
3aedbce5c2 |
4
.github/ci/build-stable.sh
vendored
4
.github/ci/build-stable.sh
vendored
@ -8,6 +8,10 @@ export RUSTUP_HOME=/ci/cache/rustup
|
|||||||
export CARGO_HOME=/ci/cache/cargo
|
export CARGO_HOME=/ci/cache/cargo
|
||||||
export CARGO_TARGET_DIR=/ci/cache/target
|
export CARGO_TARGET_DIR=/ci/cache/target
|
||||||
|
|
||||||
|
# needed for "dumb HTTP" transport support
|
||||||
|
# used when pointing stm32-metapac to a CI-built one.
|
||||||
|
export CARGO_NET_GIT_FETCH_WITH_CLI=true
|
||||||
|
|
||||||
hashtime restore /ci/cache/filetime.json || true
|
hashtime restore /ci/cache/filetime.json || true
|
||||||
hashtime save /ci/cache/filetime.json
|
hashtime save /ci/cache/filetime.json
|
||||||
|
|
||||||
|
4
.github/ci/build.sh
vendored
4
.github/ci/build.sh
vendored
@ -14,6 +14,10 @@ if [ -f /ci/secrets/teleprobe-token.txt ]; then
|
|||||||
export TELEPROBE_CACHE=/ci/cache/teleprobe_cache.json
|
export TELEPROBE_CACHE=/ci/cache/teleprobe_cache.json
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# needed for "dumb HTTP" transport support
|
||||||
|
# used when pointing stm32-metapac to a CI-built one.
|
||||||
|
export CARGO_NET_GIT_FETCH_WITH_CLI=true
|
||||||
|
|
||||||
hashtime restore /ci/cache/filetime.json || true
|
hashtime restore /ci/cache/filetime.json || true
|
||||||
hashtime save /ci/cache/filetime.json
|
hashtime save /ci/cache/filetime.json
|
||||||
|
|
||||||
|
2
.github/ci/doc.sh
vendored
2
.github/ci/doc.sh
vendored
@ -48,8 +48,8 @@ kubectl cp webroot/static $POD:/data
|
|||||||
|
|
||||||
# build and upload stm32 last
|
# build and upload stm32 last
|
||||||
# so that it doesn't prevent other crates from getting docs updates when it breaks.
|
# so that it doesn't prevent other crates from getting docs updates when it breaks.
|
||||||
|
|
||||||
rm -rf webroot
|
rm -rf webroot
|
||||||
docserver-builder -i ./embassy-stm32 -o webroot/crates/embassy-stm32/git.zup
|
docserver-builder -i ./embassy-stm32 -o webroot/crates/embassy-stm32/git.zup
|
||||||
|
|
||||||
POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name})
|
POD=$(kubectl -n embassy get po -l app=docserver -o jsonpath={.items[0].metadata.name})
|
||||||
kubectl cp webroot/crates $POD:/data
|
kubectl cp webroot/crates $POD:/data
|
||||||
|
4
.github/ci/test.sh
vendored
4
.github/ci/test.sh
vendored
@ -8,6 +8,10 @@ export RUSTUP_HOME=/ci/cache/rustup
|
|||||||
export CARGO_HOME=/ci/cache/cargo
|
export CARGO_HOME=/ci/cache/cargo
|
||||||
export CARGO_TARGET_DIR=/ci/cache/target
|
export CARGO_TARGET_DIR=/ci/cache/target
|
||||||
|
|
||||||
|
# needed for "dumb HTTP" transport support
|
||||||
|
# used when pointing stm32-metapac to a CI-built one.
|
||||||
|
export CARGO_NET_GIT_FETCH_WITH_CLI=true
|
||||||
|
|
||||||
hashtime restore /ci/cache/filetime.json || true
|
hashtime restore /ci/cache/filetime.json || true
|
||||||
hashtime save /ci/cache/filetime.json
|
hashtime save /ci/cache/filetime.json
|
||||||
|
|
||||||
|
345
ci.sh
345
ci.sh
@ -15,165 +15,194 @@ fi
|
|||||||
find . -name '*.rs' -not -path '*target*' | xargs rustfmt --check --skip-children --unstable-features --edition 2021
|
find . -name '*.rs' -not -path '*target*' | xargs rustfmt --check --skip-children --unstable-features --edition 2021
|
||||||
|
|
||||||
cargo batch \
|
cargo batch \
|
||||||
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly \
|
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/stm32wb55rg # \
|
||||||
--- 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-sync/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
|
|
||||||
--- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \
|
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \
|
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \
|
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,nightly \
|
|
||||||
--- 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-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ieee802154 \
|
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,medium-ieee802154 \
|
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,nightly \
|
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet \
|
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet,nightly \
|
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,nightly \
|
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet,nightly \
|
|
||||||
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet,medium-ieee802154,nightly \
|
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52805,gpiote,time-driver-rtc1 \
|
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52810,gpiote,time-driver-rtc1 \
|
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52811,gpiote,time-driver-rtc1 \
|
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52820,gpiote,time-driver-rtc1 \
|
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52832,gpiote,time-driver-rtc1,reset-pin-as-gpio \
|
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52833,gpiote,time-driver-rtc1,unstable-traits,nfc-pins-as-gpio \
|
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,nrf9160-s,gpiote,time-driver-rtc1 \
|
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,nrf9160-ns,gpiote,time-driver-rtc1,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,nrf5340-app-s,gpiote,time-driver-rtc1,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,nrf5340-app-ns,gpiote,time-driver-rtc1 \
|
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,nrf5340-net,gpiote,time-driver-rtc1,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52840,gpiote,time-driver-rtc1 \
|
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52840,log,gpiote,time-driver-rtc1 \
|
|
||||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52840,defmt,gpiote,time-driver-rtc1,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits,defmt \
|
|
||||||
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits,log \
|
|
||||||
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly \
|
|
||||||
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,intrinsics \
|
|
||||||
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,qspi-as-gpio \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,time-driver-any \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,time-driver-any \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f410tb,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f411ce,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f413vh,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,unstable-traits,embedded-sdmmc \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f730i8,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l422cb,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wb15cc,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l072cz,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l041f6,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f398ve,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f378cc,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32g0c1ve,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f217zg,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,stm32l552ze,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32wl54jc-cm0p,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wle5jb,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32g474pe,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f107vc,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f103re,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f100c4,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32h503rb,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32h562ag,defmt,exti,time-driver-any,unstable-traits \
|
|
||||||
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features ''\
|
|
||||||
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log' \
|
|
||||||
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \
|
|
||||||
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log,firmware-logs' \
|
|
||||||
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt,firmware-logs' \
|
|
||||||
--- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features '' \
|
|
||||||
--- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'overclock' \
|
|
||||||
--- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,nightly \
|
|
||||||
--- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,nightly \
|
|
||||||
--- build --release --manifest-path embassy-boot/rp/Cargo.toml --target thumbv6m-none-eabi --features nightly \
|
|
||||||
--- build --release --manifest-path embassy-boot/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4,nightly \
|
|
||||||
--- build --release --manifest-path docs/modules/ROOT/examples/basic/Cargo.toml --target thumbv7em-none-eabi \
|
|
||||||
--- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-pac/Cargo.toml --target thumbv7em-none-eabi \
|
|
||||||
--- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-hal/Cargo.toml --target thumbv7em-none-eabi \
|
|
||||||
--- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-irq/Cargo.toml --target thumbv7em-none-eabi \
|
|
||||||
--- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml --target thumbv7em-none-eabi \
|
|
||||||
--- build --release --manifest-path 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 \
|
|
||||||
--- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f1 \
|
|
||||||
--- build --release --manifest-path examples/stm32f2/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f2 \
|
|
||||||
--- build --release --manifest-path examples/stm32f3/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f3 \
|
|
||||||
--- build --release --manifest-path examples/stm32f334/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f334 \
|
|
||||||
--- build --release --manifest-path examples/stm32f4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f4 \
|
|
||||||
--- build --release --manifest-path examples/stm32f7/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f7 \
|
|
||||||
--- build --release --manifest-path examples/stm32c0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32c0 \
|
|
||||||
--- build --release --manifest-path examples/stm32g0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32g0 \
|
|
||||||
--- build --release --manifest-path examples/stm32g4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32g4 \
|
|
||||||
--- build --release --manifest-path examples/stm32h5/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h5 \
|
|
||||||
--- build --release --manifest-path examples/stm32h7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7 \
|
|
||||||
--- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32l0 \
|
|
||||||
--- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32l1 \
|
|
||||||
--- build --release --manifest-path examples/stm32l4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32l4 \
|
|
||||||
--- build --release --manifest-path examples/stm32l5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32l5 \
|
|
||||||
--- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \
|
|
||||||
--- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wb \
|
|
||||||
--- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl \
|
|
||||||
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --out-dir out/examples/boot/nrf \
|
|
||||||
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --out-dir out/examples/boot/nrf \
|
|
||||||
--- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/rp \
|
|
||||||
--- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f3 \
|
|
||||||
--- build --release --manifest-path examples/boot/application/stm32f7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f7 \
|
|
||||||
--- build --release --manifest-path examples/boot/application/stm32h7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32h7 \
|
|
||||||
--- build --release --manifest-path examples/boot/application/stm32l0/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/stm32l0 \
|
|
||||||
--- build --release --manifest-path examples/boot/application/stm32l1/Cargo.toml --target thumbv7m-none-eabi --features skip-include --out-dir out/examples/boot/stm32l1 \
|
|
||||||
--- build --release --manifest-path examples/boot/application/stm32l4/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32l4 \
|
|
||||||
--- build --release --manifest-path examples/boot/application/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --features skip-include --out-dir out/examples/boot/stm32wl \
|
|
||||||
--- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
|
|
||||||
--- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \
|
|
||||||
--- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \
|
|
||||||
--- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \
|
|
||||||
--- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \
|
|
||||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/stm32f103c8 \
|
|
||||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --out-dir out/tests/stm32f429zi \
|
|
||||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g491re --out-dir out/tests/stm32g491re \
|
|
||||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g071rb --out-dir out/tests/stm32g071rb \
|
|
||||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32c031c6 --out-dir out/tests/stm32c031c6 \
|
|
||||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi --out-dir out/tests/stm32h755zi \
|
|
||||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/stm32wb55rg \
|
|
||||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h563zi --out-dir out/tests/stm32h563zi \
|
|
||||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585ai --out-dir out/tests/stm32u585ai \
|
|
||||||
--- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \
|
|
||||||
--- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \
|
|
||||||
--- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \
|
|
||||||
$BUILD_EXTRA
|
|
||||||
|
|
||||||
|
# --- 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-sync/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
|
||||||
|
# --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \
|
||||||
|
# --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \
|
||||||
|
# --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \
|
||||||
|
# --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,nightly \
|
||||||
|
# --- 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-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ieee802154 \
|
||||||
|
# --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,medium-ieee802154 \
|
||||||
|
# --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,nightly \
|
||||||
|
# --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet \
|
||||||
|
# --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet,nightly \
|
||||||
|
# --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,nightly \
|
||||||
|
# --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet,nightly \
|
||||||
|
# --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet,medium-ieee802154,nightly \
|
||||||
|
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52805,gpiote,time-driver-rtc1 \
|
||||||
|
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52810,gpiote,time-driver-rtc1 \
|
||||||
|
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52811,gpiote,time-driver-rtc1 \
|
||||||
|
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52820,gpiote,time-driver-rtc1 \
|
||||||
|
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52832,gpiote,time-driver-rtc1,reset-pin-as-gpio \
|
||||||
|
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52833,gpiote,time-driver-rtc1,unstable-traits,nfc-pins-as-gpio \
|
||||||
|
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,nrf9160-s,gpiote,time-driver-rtc1 \
|
||||||
|
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,nrf9160-ns,gpiote,time-driver-rtc1,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,nrf5340-app-s,gpiote,time-driver-rtc1,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,nrf5340-app-ns,gpiote,time-driver-rtc1 \
|
||||||
|
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,nrf5340-net,gpiote,time-driver-rtc1,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52840,gpiote,time-driver-rtc1 \
|
||||||
|
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52840,log,gpiote,time-driver-rtc1 \
|
||||||
|
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52840,defmt,gpiote,time-driver-rtc1,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits,defmt \
|
||||||
|
# --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits,log \
|
||||||
|
# --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly \
|
||||||
|
# --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,intrinsics \
|
||||||
|
# --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,qspi-as-gpio \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,time-driver-any \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,time-driver-any \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f401ve,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f405zg,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f407zg,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f410tb,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f411ce,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f412zg,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f413vh,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f415zg,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f417zg,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f423zh,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f427zi,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,unstable-traits,embedded-sdmmc \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f437zi,log,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f439zi,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f446ze,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f469zi,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f479zi,defmt,exti,time-driver-any,unstable-traits,embedded-sdmmc \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f730i8,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h753zi,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h735zg,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l422cb,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wb15cc,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l072cz,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l041f6,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l073cz,defmt,exti,time-driver-any,unstable-traits,low-power \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f398ve,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f378cc,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32g0c1ve,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f217zg,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,stm32l552ze,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32wl54jc-cm0p,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wle5jb,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32g474pe,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f107vc,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f103re,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f100c4,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32h503rb,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32h562ag,defmt,exti,time-driver-any,unstable-traits \
|
||||||
|
# --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features ''\
|
||||||
|
# --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log' \
|
||||||
|
# --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \
|
||||||
|
# --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log,firmware-logs' \
|
||||||
|
# --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt,firmware-logs' \
|
||||||
|
# --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features '' \
|
||||||
|
# --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'overclock' \
|
||||||
|
# --- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,nightly \
|
||||||
|
# --- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,nightly \
|
||||||
|
# --- build --release --manifest-path embassy-boot/rp/Cargo.toml --target thumbv6m-none-eabi --features nightly \
|
||||||
|
# --- build --release --manifest-path embassy-boot/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4,nightly \
|
||||||
|
# --- build --release --manifest-path docs/modules/ROOT/examples/basic/Cargo.toml --target thumbv7em-none-eabi \
|
||||||
|
# --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-pac/Cargo.toml --target thumbv7em-none-eabi \
|
||||||
|
# --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-hal/Cargo.toml --target thumbv7em-none-eabi \
|
||||||
|
# --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-irq/Cargo.toml --target thumbv7em-none-eabi \
|
||||||
|
# --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml --target thumbv7em-none-eabi \
|
||||||
|
# --- build --release --manifest-path 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 \
|
||||||
|
# --- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f1 \
|
||||||
|
# --- build --release --manifest-path examples/stm32f2/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f2 \
|
||||||
|
# --- build --release --manifest-path examples/stm32f3/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f3 \
|
||||||
|
# --- build --release --manifest-path examples/stm32f334/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f334 \
|
||||||
|
# --- build --release --manifest-path examples/stm32f4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f4 \
|
||||||
|
# --- build --release --manifest-path examples/stm32f7/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f7 \
|
||||||
|
# --- build --release --manifest-path examples/stm32c0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32c0 \
|
||||||
|
# --- build --release --manifest-path examples/stm32g0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32g0 \
|
||||||
|
# --- build --release --manifest-path examples/stm32g4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32g4 \
|
||||||
|
# --- build --release --manifest-path examples/stm32h5/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h5 \
|
||||||
|
# --- build --release --manifest-path examples/stm32h7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7 \
|
||||||
|
# --- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32l0 \
|
||||||
|
# --- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32l1 \
|
||||||
|
# --- build --release --manifest-path examples/stm32l4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32l4 \
|
||||||
|
# --- build --release --manifest-path examples/stm32l5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32l5 \
|
||||||
|
# --- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \
|
||||||
|
# --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wb \
|
||||||
|
# --- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32wba \
|
||||||
|
# --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl \
|
||||||
|
# --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --out-dir out/examples/boot/nrf52840 \
|
||||||
|
# --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --out-dir out/examples/boot/nrf9160 \
|
||||||
|
# --- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/rp \
|
||||||
|
# --- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f3 \
|
||||||
|
# --- build --release --manifest-path examples/boot/application/stm32f7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f7 \
|
||||||
|
# --- build --release --manifest-path examples/boot/application/stm32h7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32h7 \
|
||||||
|
# --- build --release --manifest-path examples/boot/application/stm32l0/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/stm32l0 \
|
||||||
|
# --- build --release --manifest-path examples/boot/application/stm32l1/Cargo.toml --target thumbv7m-none-eabi --features skip-include --out-dir out/examples/boot/stm32l1 \
|
||||||
|
# --- build --release --manifest-path examples/boot/application/stm32l4/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32l4 \
|
||||||
|
# --- build --release --manifest-path examples/boot/application/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --features skip-include --out-dir out/examples/boot/stm32wl \
|
||||||
|
# --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
|
||||||
|
# --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \
|
||||||
|
# --- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \
|
||||||
|
# --- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \
|
||||||
|
# --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \
|
||||||
|
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/stm32f103c8 \
|
||||||
|
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --out-dir out/tests/stm32f429zi \
|
||||||
|
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g491re --out-dir out/tests/stm32g491re \
|
||||||
|
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g071rb --out-dir out/tests/stm32g071rb \
|
||||||
|
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32c031c6 --out-dir out/tests/stm32c031c6 \
|
||||||
|
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi --out-dir out/tests/stm32h755zi \
|
||||||
|
#
|
||||||
|
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h563zi --out-dir out/tests/stm32h563zi \
|
||||||
|
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585ai --out-dir out/tests/stm32u585ai \
|
||||||
|
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l073rz --out-dir out/tests/stm32l073rz \
|
||||||
|
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l152re --out-dir out/tests/stm32l152re \
|
||||||
|
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4a6zg --out-dir out/tests/stm32l4a6zg \
|
||||||
|
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4r5zi --out-dir out/tests/stm32l4r5zi \
|
||||||
|
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze --out-dir out/tests/stm32l552ze \
|
||||||
|
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f767zi --out-dir out/tests/stm32f767zi \
|
||||||
|
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f207zg --out-dir out/tests/stm32f207zg \
|
||||||
|
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303ze --out-dir out/tests/stm32f303ze \
|
||||||
|
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l496zg --out-dir out/tests/stm32l496zg \
|
||||||
|
# --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \
|
||||||
|
# --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \
|
||||||
|
# --- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \
|
||||||
|
# $BUILD_EXTRA
|
||||||
|
|
||||||
|
rm /ci/cache/teleprobe_cache.json
|
||||||
|
|
||||||
if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
|
if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
|
||||||
echo No teleprobe token found, skipping running HIL tests
|
echo No teleprobe token found, skipping running HIL tests
|
||||||
|
@ -12,7 +12,7 @@ firmware-logs = []
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-time = { version = "0.1.3", path = "../embassy-time"}
|
embassy-time = { version = "0.1.3", path = "../embassy-time"}
|
||||||
embassy-sync = { version = "0.2.0", path = "../embassy-sync"}
|
embassy-sync = { version = "0.3.0", path = "../embassy-sync"}
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
|
||||||
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"}
|
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"}
|
||||||
atomic-polyfill = "0.1.5"
|
atomic-polyfill = "0.1.5"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
* xref:getting_started.adoc[Getting started]
|
* xref:getting_started.adoc[Getting started]
|
||||||
** xref:basic_application.adoc[Basic application]
|
** xref:basic_application.adoc[Basic application]
|
||||||
** xref:layer_by_layer.adoc[Layer by Layer]
|
* xref:layer_by_layer.adoc[Bare metal to async]
|
||||||
* xref:runtime.adoc[Executor]
|
* xref:runtime.adoc[Executor]
|
||||||
* xref:hal.adoc[HAL]
|
* xref:hal.adoc[HAL]
|
||||||
** xref:nrf.adoc[nRF]
|
** xref:nrf.adoc[nRF]
|
||||||
@ -8,3 +8,5 @@
|
|||||||
* xref:bootloader.adoc[Bootloader]
|
* xref:bootloader.adoc[Bootloader]
|
||||||
|
|
||||||
* xref:examples.adoc[Examples]
|
* xref:examples.adoc[Examples]
|
||||||
|
* xref:developer.adoc[Developer]
|
||||||
|
** xref:developer_stm32.adoc[Developer: STM32]
|
||||||
|
1
docs/modules/ROOT/pages/developer.adoc
Normal file
1
docs/modules/ROOT/pages/developer.adoc
Normal file
@ -0,0 +1 @@
|
|||||||
|
= Developer Documentation
|
79
docs/modules/ROOT/pages/developer_stm32.adoc
Normal file
79
docs/modules/ROOT/pages/developer_stm32.adoc
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
= Developer Documentation: STM32
|
||||||
|
|
||||||
|
== Understanding metapac
|
||||||
|
|
||||||
|
When a project that imports `embassy-stm32` is compiled, that project selects the feature corresponding to the chip that project is using. Based on that feature, `embassy-stm32` selects supported link:https://anysilicon.com/ip-intellectual-property-core-semiconductors/[IP] for the chip, and enables the corresponding HAL implementations. But how does `embassy-stm32` know what IP the chip contains, out of the hundreds of chips that we support? It's a long story that starts with `stm32-data-sources`.
|
||||||
|
|
||||||
|
== `stm32-data-sources`
|
||||||
|
|
||||||
|
link:https://github.com/embassy-rs/stm32-data-sources[`stm32-data-sources`] is as mostly barren repository. It has no README, no documentation, and few watchers. But it's the core of what makes `embassy-stm32` possible. The data for every chip that we support is taken in part from a corresponding XML file like link:https://github.com/embassy-rs/stm32-data-sources/blob/b8b85202e22a954d6c59d4a43d9795d34cff05cf/cubedb/mcu/STM32F051K4Ux.xml[`STM32F051K4Ux.xml`]. In that file, you'll see lines like the following:
|
||||||
|
|
||||||
|
[source,xml]
|
||||||
|
----
|
||||||
|
<IP InstanceName="I2C1" Name="I2C" Version="i2c2_v1_1_Cube"/>
|
||||||
|
<!-- snip -->
|
||||||
|
<IP ConfigFile="TIM-STM32F0xx" InstanceName="TIM1" Name="TIM1_8F0" Version="gptimer2_v2_x_Cube"/>
|
||||||
|
----
|
||||||
|
|
||||||
|
These lines indicate that this chip has an i2c, and that it's version is "v1_1". It also indicates that it has a general purpose timer that with a version of "v2_x". From this data, it's possible to determine which implementations should be included in `embassy-stm32`. But actually doing that is another matter.
|
||||||
|
|
||||||
|
|
||||||
|
== `stm32-data`
|
||||||
|
|
||||||
|
While all users of this project are familiar with `embassy-stm32`, fewer are familiar with the project that powers it: `stm32-data`. This project doesn't just aim to generate data for `embassy-stm32`, but for machine consumption in general. To acheive this, information from multiple files from the `stm32-data-sources` project are combined and parsed to assign register block implementations for each supported IP. The core of this matching resides in `chips.rs`:
|
||||||
|
|
||||||
|
[source,rust]
|
||||||
|
----
|
||||||
|
(".*:I2C:i2c2_v1_1", ("i2c", "v2", "I2C")),
|
||||||
|
// snip
|
||||||
|
(r".*TIM\d.*:gptimer.*", ("timer", "v1", "TIM_GP16")),
|
||||||
|
----
|
||||||
|
|
||||||
|
In this case, the i2c version corresponds to our "v2" and the general purpose timer version corresponds to our "v1". Therefore, the `i2c_v2.yaml` and `timer_v1.yaml` register block implementations are assigned to those IP, respectively. The result is that these lines arr generated in `STM32F051K4.json`:
|
||||||
|
|
||||||
|
[source,json]
|
||||||
|
----
|
||||||
|
{
|
||||||
|
"name": "I2C1",
|
||||||
|
"address": 1073763328,
|
||||||
|
"registers": {
|
||||||
|
"kind": "i2c",
|
||||||
|
"version": "v2",
|
||||||
|
"block": "I2C"
|
||||||
|
},
|
||||||
|
// snip
|
||||||
|
}
|
||||||
|
// snip
|
||||||
|
{
|
||||||
|
"name": "TIM1",
|
||||||
|
"address": 1073818624,
|
||||||
|
"registers": {
|
||||||
|
"kind": "timer",
|
||||||
|
"version": "v1",
|
||||||
|
"block": "TIM_ADV"
|
||||||
|
},
|
||||||
|
// snip
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
In addition to register blocks, data for pin and RCC mapping is also generated and consumed by `embassy-stm32`. `stm32-metapac-gen` is used to package and publish the data as a crate.
|
||||||
|
|
||||||
|
|
||||||
|
== `embassy-stm32`
|
||||||
|
|
||||||
|
In the `lib.rs` file located in the root of `embassy-stm32`, you'll see this line:
|
||||||
|
|
||||||
|
[source,rust]
|
||||||
|
----
|
||||||
|
#[cfg(i2c)]
|
||||||
|
pub mod i2c;
|
||||||
|
----
|
||||||
|
|
||||||
|
And in the `mod.rs` of the i2c mod, you'll see this:
|
||||||
|
|
||||||
|
[source,rust]
|
||||||
|
----
|
||||||
|
#[cfg_attr(i2c_v2, path = "v2.rs")]
|
||||||
|
----
|
||||||
|
|
||||||
|
Because i2c is supported for STM32F051K4 and its version corresponds to our "v2", the `i2c` and `i2c_v2`, configuration directives will be present, and `embassy-stm32` will include these files, respectively. This and other configuration directives and tables are generated from the data for chip, allowing `embassy-stm32` to expressively and clearly adapt logic and implementations to what is required for each chip. Compared to other projects across the embedded ecosystem, `embassy-stm32` is the only project that can re-use code across the entire stm32 lineup and remove difficult-to-implement unsafe logic to the HAL.
|
@ -3,7 +3,7 @@
|
|||||||
So you want to try Embassy, great! To get started, there are a few tools you need to install:
|
So you want to try Embassy, great! To get started, there are a few tools you need to install:
|
||||||
|
|
||||||
* link:https://rustup.rs/[rustup] - the Rust toolchain is needed to compile Rust code.
|
* link:https://rustup.rs/[rustup] - the Rust toolchain is needed to compile Rust code.
|
||||||
* link:https://crates.io/crates/probe-run[probe-run] - to flash the firmware on your device. If you already have other tools like `OpenOCD` setup, you can use that as well.
|
* link:https://crates.io/crates/probe-rs[probe-rs] - to flash the firmware on your device. If you already have other tools like `OpenOCD` setup, you can use that as well.
|
||||||
|
|
||||||
If you don't have any supported board, don't worry: you can also run embassy on your PC using the `std` examples.
|
If you don't have any supported board, don't worry: you can also run embassy on your PC using the `std` examples.
|
||||||
|
|
||||||
@ -30,6 +30,10 @@ Embassy supports many microcontroller families, but the easiest ways to get star
|
|||||||
|
|
||||||
* link:https://www.raspberrypi.com/products/raspberry-pi-pico/[Raspberry Pi Pico]
|
* link:https://www.raspberrypi.com/products/raspberry-pi-pico/[Raspberry Pi Pico]
|
||||||
|
|
||||||
|
=== ESP32
|
||||||
|
|
||||||
|
* link:https://github.com/esp-rs/esp-rust-board[ESP32C3]
|
||||||
|
|
||||||
== Running an example
|
== Running an example
|
||||||
|
|
||||||
First you need to clone the [github repository];
|
First you need to clone the [github repository];
|
||||||
@ -38,7 +42,6 @@ First you need to clone the [github repository];
|
|||||||
----
|
----
|
||||||
git clone https://github.com/embassy-rs/embassy.git
|
git clone https://github.com/embassy-rs/embassy.git
|
||||||
cd embassy
|
cd embassy
|
||||||
git submodule update --init
|
|
||||||
----
|
----
|
||||||
|
|
||||||
You can run an example by opening a terminal and entering the following commands:
|
You can run an example by opening a terminal and entering the following commands:
|
||||||
|
@ -7,4 +7,6 @@ Embassy provides HALs for several microcontroller families:
|
|||||||
* `embassy-rp` for the Raspberry Pi RP2040 microcontrollers
|
* `embassy-rp` for the Raspberry Pi RP2040 microcontrollers
|
||||||
|
|
||||||
These HALs implement async/await functionality for most peripherals while also implementing the
|
These HALs implement async/await functionality for most peripherals while also implementing the
|
||||||
async traits in `embedded-hal-async`. You can also use these HALs with another executor.
|
async traits in `embedded-hal` and `embedded-hal-async`. You can also use these HALs with another executor.
|
||||||
|
|
||||||
|
For the ESP32 series, there is an link:https://github.com/esp-rs/esp-hal[esp-hal] which you can use.
|
||||||
|
@ -4,14 +4,9 @@ Embassy is a project to make async/await a first-class option for embedded devel
|
|||||||
|
|
||||||
== What is async?
|
== What is async?
|
||||||
|
|
||||||
Software written without async may block on I/O operations. In an std environment, such as a PC, software can handle this either by using threads or non-blocking operations.
|
When handling I/O, software must call functions that block program execution until the I/O operation completes. When running inside of an OS such as Linux, such functions generally transfer control to the kernel so that another task, known as a thread, can be executed if available, or the CPU can be put to sleep until another such task is ready to perform more work. Because an OS cannot presume that threads will behave cooperatively, threads are relatively resource-intensive, and may be forcibly interrupted they do not transfer control back to the kernel within an allotted time. But if tasks could be presumed to behave cooperatively, or at least not maliciously, it would be possible to create tasks that appear to be almost free when compared to a traditional OS thread. In Rust, these lightweight tasks, known as 'coroutines' or 'goroutines' in other languages, are implemented with async.
|
||||||
|
|
||||||
With threads, one thread blocks on an I/O operation, another is able to take its place. However, even on a PC, threads are relatively heavy, and therefore some programming languages, such as Go, have implemented a concept called coroutines or 'goroutines' that are much lighter and less-intensive than threads.
|
Async-await works by transforming each async function into an object called a future. When a future blocks on I/O the future yields, and the scheduler, called an executor, can select a different future to execute. Compared to alternatives such as an RTOS, async can yield better performance and lower power consumption because the executor doesn't have to guess when a future is ready to execute. However, program size may be higher than other alternatives, which may be a problem for certain space-constrained devices with very low memory. On the devices Embassy supports, such as stm32 and nrf, memory is generally large enough to accommodate the modestly-increased program size.
|
||||||
|
|
||||||
The other way to handle blocking I/O operations is to support polling the state of the underlying peripherals to check whether it is available to perform the requested operation. In programming languages without builtin async support,
|
|
||||||
this requires building a complex loop checking for events.
|
|
||||||
|
|
||||||
In Rust, non-blocking operations can be implemented using async-await. Async-await works by transforming each async function into an object called a future. When a future blocks on I/O the future yields, and the scheduler, called an executor, can select a different future to execute. Compared to alternatives such as an RTOS, async can yield better performance and lower power consumption because the executor doesn't have to guess when a future is ready to execute. However, program size may be higher than other alternatives, which may be a problem for certain space-constrained devices with very low memory. On the devices Embassy supports, such as stm32 and nrf, memory is generally large enough to accommodate the modestly-increased program size.
|
|
||||||
|
|
||||||
== What is Embassy?
|
== What is Embassy?
|
||||||
|
|
||||||
@ -22,13 +17,26 @@ The Embassy project consists of several crates that you can use together or inde
|
|||||||
* **Hardware Abstraction Layers** - HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. The Embassy project maintains HALs for select hardware, but you can still use HALs from other projects with Embassy.
|
* **Hardware Abstraction Layers** - HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. The Embassy project maintains HALs for select hardware, but you can still use HALs from other projects with Embassy.
|
||||||
** link:https://docs.embassy.dev/embassy-stm32/[embassy-stm32], for all STM32 microcontroller families.
|
** link:https://docs.embassy.dev/embassy-stm32/[embassy-stm32], for all STM32 microcontroller families.
|
||||||
** link:https://docs.embassy.dev/embassy-nrf/[embassy-nrf], for the Nordic Semiconductor nRF52, nRF53, nRF91 series.
|
** link:https://docs.embassy.dev/embassy-nrf/[embassy-nrf], for the Nordic Semiconductor nRF52, nRF53, nRF91 series.
|
||||||
|
** link:https://docs.embassy.dev/embassy-rp/[embassy-rp], for the Raspberry Pi RP2040 microcontroller.
|
||||||
|
** link:https://github.com/esp-rs[esp-rs], for the Espressif Systems ESP32 series of chips.
|
||||||
|
+
|
||||||
|
NOTE: A common question is if one can use the Embassy HALs standalone. Yes, it is possible! There are no dependency on the executor within the HALs. You can even use them without async,
|
||||||
|
as they implement both the link:https://github.com/rust-embedded/embedded-hal[Embedded HAL] blocking and async traits.
|
||||||
|
|
||||||
* **Networking** - The link:https://docs.embassy.dev/embassy-net/[embassy-net] network stack implements extensive networking functionality, including Ethernet, IP, TCP, UDP, ICMP and DHCP. Async drastically simplifies managing timeouts and serving multiple connections concurrently.
|
* **Networking** - The link:https://docs.embassy.dev/embassy-net/[embassy-net] network stack implements extensive networking functionality, including Ethernet, IP, TCP, UDP, ICMP and DHCP. Async drastically simplifies managing timeouts and serving multiple connections concurrently. Several drivers for WiFi and Ethernet chips can be found.
|
||||||
|
|
||||||
* **Bluetooth** - The link:https://github.com/embassy-rs/nrf-softdevice[nrf-softdevice] crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers.
|
* **Bluetooth** - The link:https://github.com/embassy-rs/nrf-softdevice[nrf-softdevice] crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers.
|
||||||
|
|
||||||
* **LoRa** - link:https://docs.embassy.dev/embassy-lora/[embassy-lora] supports LoRa networking on STM32WL wireless microcontrollers and Semtech SX127x transceivers.
|
* **LoRa** - link:https://github.com/embassy-rs/lora-phy[lora-phy] and link:https://docs.embassy.dev/embassy-lora/[embassy-lora] supports LoRa networking on a wide range of LoRa radios, fully integrated with a Rust link:https://github.com/ivajloip/rust-lorawan[LoRaWAN] implementation.
|
||||||
|
|
||||||
* **USB** - link:https://docs.embassy.dev/embassy-usb/[embassy-usb] implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own.
|
* **USB** - link:https://docs.embassy.dev/embassy-usb/[embassy-usb] implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own.
|
||||||
|
|
||||||
* **Bootloader and DFU** - link:https://github.com/embassy-rs/embassy/tree/master/embassy-boot[embassy-boot] is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks.
|
* **Bootloader and DFU** - link:https://github.com/embassy-rs/embassy/tree/master/embassy-boot[embassy-boot] is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks.
|
||||||
|
|
||||||
|
== Resources
|
||||||
|
|
||||||
|
For more reading material on async Rust and Embassy:
|
||||||
|
|
||||||
|
* link:https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown[Comparsion of FreeRTOS and Embassy]
|
||||||
|
* link:https://dev.to/apollolabsbin/series/20707[Tutorials]
|
||||||
|
* link:https://blog.drogue.io/firmware-updates-part-1/[Firmware Updates with Embassy]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
= Embassy layer by layer
|
= From bare metal to async Rust
|
||||||
|
|
||||||
If you're new to Embassy, it can be overwhelming to grasp all the terminology and concepts. This guide aims to clarify the different layers in Embassy, which problem each layer solves for the application writer.
|
If you're new to Embassy, it can be overwhelming to grasp all the terminology and concepts. This guide aims to clarify the different layers in Embassy, which problem each layer solves for the application writer.
|
||||||
|
|
||||||
@ -8,8 +8,7 @@ The application we'll write is a simple 'push button, blink led' application, wh
|
|||||||
|
|
||||||
== PAC version
|
== PAC version
|
||||||
|
|
||||||
The PAC is the lowest API for accessing peripherals and registers, if you don't count reading/writing directly to memory addresses. It provides distinct types
|
The PAC is the lowest API for accessing peripherals and registers, if you don't count reading/writing directly to memory addresses. It provides distinct types to make accessing peripheral registers easier, but it does not prevent you from writing unsafe code.
|
||||||
to make accessing peripheral registers easier, but it does not prevent you from writing unsafe code.
|
|
||||||
|
|
||||||
Writing an application using the PAC directly is therefore not recommended, but if the functionality you want to use is not exposed in the upper layers, that's what you need to use.
|
Writing an application using the PAC directly is therefore not recommended, but if the functionality you want to use is not exposed in the upper layers, that's what you need to use.
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ The nRF timer driver operates at 32768 Hz by default.
|
|||||||
|
|
||||||
== Peripherals
|
== Peripherals
|
||||||
|
|
||||||
The following peripherals have a HAL implementation at present:
|
The following peripherals have a HAL implementation at present
|
||||||
|
|
||||||
* PWM
|
* PWM
|
||||||
* SPIM
|
* SPIM
|
||||||
@ -23,3 +23,7 @@ The following peripherals have a HAL implementation at present:
|
|||||||
* UARTE
|
* UARTE
|
||||||
* TWIM
|
* TWIM
|
||||||
* SAADC
|
* SAADC
|
||||||
|
|
||||||
|
== Bluetooth
|
||||||
|
|
||||||
|
For bluetooth, you can use the link:https://github.com/embassy-rs/nrf-softdevice[nrf-softdevice] crate.
|
||||||
|
@ -10,7 +10,7 @@ The Embassy executor is an async/await executor designed for embedded usage alon
|
|||||||
* No busy-loop polling: CPU sleeps when there's no work to do, using interrupts or `WFE/SEV`.
|
* No busy-loop polling: CPU sleeps when there's no work to do, using interrupts or `WFE/SEV`.
|
||||||
* Efficient polling: a wake will only poll the woken task, not all of them.
|
* Efficient polling: a wake will only poll the woken task, not all of them.
|
||||||
* Fair: a task can't monopolize CPU time even if it's constantly being woken. All other tasks get a chance to run before a given task gets polled for the second time.
|
* Fair: a task can't monopolize CPU time even if it's constantly being woken. All other tasks get a chance to run before a given task gets polled for the second time.
|
||||||
* Creating multiple executor instances is supported, to run tasks with multiple priority levels. This allows higher-priority tasks to preempt lower-priority tasks.
|
* Creating multiple executor instances is supported, to run tasks at different priority levels. This allows higher-priority tasks to preempt lower-priority tasks.
|
||||||
|
|
||||||
== Executor
|
== Executor
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ digest = "0.10"
|
|||||||
log = { version = "0.4", optional = true }
|
log = { version = "0.4", optional = true }
|
||||||
ed25519-dalek = { version = "1.0.1", default_features = false, features = ["u32_backend"], optional = true }
|
ed25519-dalek = { version = "1.0.1", default_features = false, features = ["u32_backend"], optional = true }
|
||||||
embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
|
embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" }
|
||||||
embassy-sync = { version = "0.2.0", path = "../../embassy-sync" }
|
embassy-sync = { version = "0.3.0", path = "../../embassy-sync" }
|
||||||
embedded-storage = "0.3.0"
|
embedded-storage = "0.3.0"
|
||||||
embedded-storage-async = { version = "0.4.0", optional = true }
|
embedded-storage-async = { version = "0.4.0", optional = true }
|
||||||
salty = { git = "https://github.com/ycrypto/salty.git", rev = "a9f17911a5024698406b75c0fac56ab5ccf6a8c7", optional = true }
|
salty = { git = "https://github.com/ycrypto/salty.git", rev = "a9f17911a5024698406b75c0fac56ab5ccf6a8c7", optional = true }
|
||||||
|
@ -20,7 +20,7 @@ default = ["time"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures", optional = true }
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures", optional = true }
|
||||||
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
|
||||||
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
|
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
|
||||||
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [
|
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [
|
||||||
"unproven",
|
"unproven",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections, try_blocks))]
|
#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, try_blocks))]
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
//! Utilities to use `embedded-hal` traits with Embassy.
|
//! Utilities to use `embedded-hal` traits with Embassy.
|
||||||
@ -26,6 +26,18 @@ pub trait SetConfig {
|
|||||||
/// The configuration type used by this driver.
|
/// The configuration type used by this driver.
|
||||||
type Config;
|
type Config;
|
||||||
|
|
||||||
|
/// The error type that can occur if `set_config` fails.
|
||||||
|
type ConfigError;
|
||||||
|
|
||||||
/// Set the configuration of the driver.
|
/// Set the configuration of the driver.
|
||||||
fn set_config(&mut self, config: &Self::Config);
|
fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the configuration of a peripheral driver.
|
||||||
|
pub trait GetConfig {
|
||||||
|
/// The configuration type used by this driver.
|
||||||
|
type Config;
|
||||||
|
|
||||||
|
/// Get the configuration of the driver.
|
||||||
|
fn get_config(&self) -> Self::Config;
|
||||||
}
|
}
|
||||||
|
@ -125,14 +125,14 @@ where
|
|||||||
{
|
{
|
||||||
async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), I2cDeviceError<BUS::Error>> {
|
async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), I2cDeviceError<BUS::Error>> {
|
||||||
let mut bus = self.bus.lock().await;
|
let mut bus = self.bus.lock().await;
|
||||||
bus.set_config(&self.config);
|
bus.set_config(&self.config).map_err(|_| I2cDeviceError::Config)?;
|
||||||
bus.read(address, buffer).await.map_err(I2cDeviceError::I2c)?;
|
bus.read(address, buffer).await.map_err(I2cDeviceError::I2c)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), I2cDeviceError<BUS::Error>> {
|
async fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), I2cDeviceError<BUS::Error>> {
|
||||||
let mut bus = self.bus.lock().await;
|
let mut bus = self.bus.lock().await;
|
||||||
bus.set_config(&self.config);
|
bus.set_config(&self.config).map_err(|_| I2cDeviceError::Config)?;
|
||||||
bus.write(address, bytes).await.map_err(I2cDeviceError::I2c)?;
|
bus.write(address, bytes).await.map_err(I2cDeviceError::I2c)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -144,7 +144,7 @@ where
|
|||||||
rd_buffer: &mut [u8],
|
rd_buffer: &mut [u8],
|
||||||
) -> Result<(), I2cDeviceError<BUS::Error>> {
|
) -> Result<(), I2cDeviceError<BUS::Error>> {
|
||||||
let mut bus = self.bus.lock().await;
|
let mut bus = self.bus.lock().await;
|
||||||
bus.set_config(&self.config);
|
bus.set_config(&self.config).map_err(|_| I2cDeviceError::Config)?;
|
||||||
bus.write_read(address, wr_buffer, rd_buffer)
|
bus.write_read(address, wr_buffer, rd_buffer)
|
||||||
.await
|
.await
|
||||||
.map_err(I2cDeviceError::I2c)?;
|
.map_err(I2cDeviceError::I2c)?;
|
||||||
@ -153,7 +153,7 @@ where
|
|||||||
|
|
||||||
async fn transaction(&mut self, address: u8, operations: &mut [i2c::Operation<'_>]) -> Result<(), Self::Error> {
|
async fn transaction(&mut self, address: u8, operations: &mut [i2c::Operation<'_>]) -> Result<(), Self::Error> {
|
||||||
let mut bus = self.bus.lock().await;
|
let mut bus = self.bus.lock().await;
|
||||||
bus.set_config(&self.config);
|
bus.set_config(&self.config).map_err(|_| I2cDeviceError::Config)?;
|
||||||
bus.transaction(address, operations)
|
bus.transaction(address, operations)
|
||||||
.await
|
.await
|
||||||
.map_err(I2cDeviceError::I2c)?;
|
.map_err(I2cDeviceError::I2c)?;
|
||||||
|
@ -130,7 +130,7 @@ where
|
|||||||
{
|
{
|
||||||
async fn transaction(&mut self, operations: &mut [spi::Operation<'_, u8>]) -> Result<(), Self::Error> {
|
async fn transaction(&mut self, operations: &mut [spi::Operation<'_, u8>]) -> Result<(), Self::Error> {
|
||||||
let mut bus = self.bus.lock().await;
|
let mut bus = self.bus.lock().await;
|
||||||
bus.set_config(&self.config);
|
bus.set_config(&self.config).map_err(|_| SpiDeviceError::Config)?;
|
||||||
self.cs.set_low().map_err(SpiDeviceError::Cs)?;
|
self.cs.set_low().map_err(SpiDeviceError::Cs)?;
|
||||||
|
|
||||||
let op_res: Result<(), BUS::Error> = try {
|
let op_res: Result<(), BUS::Error> = try {
|
||||||
|
@ -148,7 +148,7 @@ where
|
|||||||
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
|
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
|
||||||
self.bus.lock(|bus| {
|
self.bus.lock(|bus| {
|
||||||
let mut bus = bus.borrow_mut();
|
let mut bus = bus.borrow_mut();
|
||||||
bus.set_config(&self.config);
|
bus.set_config(&self.config).map_err(|_| I2cDeviceError::Config)?;
|
||||||
bus.read(address, buffer).map_err(I2cDeviceError::I2c)
|
bus.read(address, buffer).map_err(I2cDeviceError::I2c)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -156,7 +156,7 @@ where
|
|||||||
fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> {
|
fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> {
|
||||||
self.bus.lock(|bus| {
|
self.bus.lock(|bus| {
|
||||||
let mut bus = bus.borrow_mut();
|
let mut bus = bus.borrow_mut();
|
||||||
bus.set_config(&self.config);
|
bus.set_config(&self.config).map_err(|_| I2cDeviceError::Config)?;
|
||||||
bus.write(address, bytes).map_err(I2cDeviceError::I2c)
|
bus.write(address, bytes).map_err(I2cDeviceError::I2c)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -164,7 +164,7 @@ where
|
|||||||
fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> {
|
fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> {
|
||||||
self.bus.lock(|bus| {
|
self.bus.lock(|bus| {
|
||||||
let mut bus = bus.borrow_mut();
|
let mut bus = bus.borrow_mut();
|
||||||
bus.set_config(&self.config);
|
bus.set_config(&self.config).map_err(|_| I2cDeviceError::Config)?;
|
||||||
bus.write_read(address, wr_buffer, rd_buffer)
|
bus.write_read(address, wr_buffer, rd_buffer)
|
||||||
.map_err(I2cDeviceError::I2c)
|
.map_err(I2cDeviceError::I2c)
|
||||||
})
|
})
|
||||||
|
@ -163,7 +163,7 @@ where
|
|||||||
fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), Self::Error> {
|
fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), Self::Error> {
|
||||||
self.bus.lock(|bus| {
|
self.bus.lock(|bus| {
|
||||||
let mut bus = bus.borrow_mut();
|
let mut bus = bus.borrow_mut();
|
||||||
bus.set_config(&self.config);
|
bus.set_config(&self.config).map_err(|_| SpiDeviceError::Config)?;
|
||||||
self.cs.set_low().map_err(SpiDeviceError::Cs)?;
|
self.cs.set_low().map_err(SpiDeviceError::Cs)?;
|
||||||
|
|
||||||
let op_res = operations.iter_mut().try_for_each(|op| match op {
|
let op_res = operations.iter_mut().try_for_each(|op| match op {
|
||||||
|
@ -14,6 +14,8 @@ pub mod blocking;
|
|||||||
pub enum I2cDeviceError<BUS> {
|
pub enum I2cDeviceError<BUS> {
|
||||||
/// An operation on the inner I2C bus failed.
|
/// An operation on the inner I2C bus failed.
|
||||||
I2c(BUS),
|
I2c(BUS),
|
||||||
|
/// Configuration of the inner I2C bus failed.
|
||||||
|
Config,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<BUS> i2c::Error for I2cDeviceError<BUS>
|
impl<BUS> i2c::Error for I2cDeviceError<BUS>
|
||||||
@ -23,6 +25,7 @@ where
|
|||||||
fn kind(&self) -> i2c::ErrorKind {
|
fn kind(&self) -> i2c::ErrorKind {
|
||||||
match self {
|
match self {
|
||||||
Self::I2c(e) => e.kind(),
|
Self::I2c(e) => e.kind(),
|
||||||
|
Self::Config => i2c::ErrorKind::Other,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -38,6 +41,8 @@ pub enum SpiDeviceError<BUS, CS> {
|
|||||||
Cs(CS),
|
Cs(CS),
|
||||||
/// DelayUs operations are not supported when the `time` Cargo feature is not enabled.
|
/// DelayUs operations are not supported when the `time` Cargo feature is not enabled.
|
||||||
DelayUsNotSupported,
|
DelayUsNotSupported,
|
||||||
|
/// The SPI bus could not be configured.
|
||||||
|
Config,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<BUS, CS> spi::Error for SpiDeviceError<BUS, CS>
|
impl<BUS, CS> spi::Error for SpiDeviceError<BUS, CS>
|
||||||
@ -50,6 +55,7 @@ where
|
|||||||
Self::Spi(e) => e.kind(),
|
Self::Spi(e) => e.kind(),
|
||||||
Self::Cs(_) => spi::ErrorKind::Other,
|
Self::Cs(_) => spi::ErrorKind::Other,
|
||||||
Self::DelayUsNotSupported => spi::ErrorKind::Other,
|
Self::DelayUsNotSupported => spi::ErrorKind::Other,
|
||||||
|
Self::Config => spi::ErrorKind::Other,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,9 +73,10 @@ mod thread {
|
|||||||
pub fn start(&'static mut self, init: impl FnOnce(Spawner)) {
|
pub fn start(&'static mut self, init: impl FnOnce(Spawner)) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let executor = &self.inner;
|
let executor = &self.inner;
|
||||||
self.ctx.closure.write(Closure::new(move |_| {
|
let future = Closure::new(move |_| {
|
||||||
executor.poll();
|
executor.poll();
|
||||||
}));
|
});
|
||||||
|
self.ctx.closure.write_in_place(|| future);
|
||||||
init(self.inner.spawner());
|
init(self.inner.spawner());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,7 +203,7 @@ impl<F: Future + 'static> AvailableTask<F> {
|
|||||||
fn initialize_impl<S>(self, future: impl FnOnce() -> F) -> SpawnToken<S> {
|
fn initialize_impl<S>(self, future: impl FnOnce() -> F) -> SpawnToken<S> {
|
||||||
unsafe {
|
unsafe {
|
||||||
self.task.raw.poll_fn.set(Some(TaskStorage::<F>::poll));
|
self.task.raw.poll_fn.set(Some(TaskStorage::<F>::poll));
|
||||||
self.task.future.write(future());
|
self.task.future.write_in_place(future);
|
||||||
|
|
||||||
let task = TaskRef::new(self.task);
|
let task = TaskRef::new(self.task);
|
||||||
|
|
||||||
|
@ -17,8 +17,9 @@ impl<T> UninitCell<T> {
|
|||||||
&mut *self.as_mut_ptr()
|
&mut *self.as_mut_ptr()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn write(&self, val: T) {
|
#[inline(never)]
|
||||||
ptr::write(self.as_mut_ptr(), val)
|
pub unsafe fn write_in_place(&self, func: impl FnOnce() -> T) {
|
||||||
|
ptr::write(self.as_mut_ptr(), func())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn drop_in_place(&self) {
|
pub unsafe fn drop_in_place(&self) {
|
||||||
|
@ -21,14 +21,11 @@ defmt = { version = "0.3", optional = true }
|
|||||||
log = { version = "0.4.14", optional = true }
|
log = { version = "0.4.14", optional = true }
|
||||||
|
|
||||||
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
|
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
|
||||||
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true }
|
embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true }
|
||||||
embedded-hal-async = { version = "=1.0.0-rc.1" }
|
embedded-hal-async = { version = "=1.0.0-rc.1" }
|
||||||
embedded-hal = { version = "0.2", features = ["unproven"] }
|
embedded-hal = { version = "0.2", features = ["unproven"] }
|
||||||
|
|
||||||
futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] }
|
futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] }
|
||||||
lora-phy = { version = "1" }
|
lora-phy = { version = "2" }
|
||||||
lorawan-device = { version = "0.10.0", default-features = false, features = ["async"], optional = true }
|
lorawan-device = { version = "0.11.0", default-features = false, features = ["async"], optional = true }
|
||||||
|
|
||||||
[patch.crates-io]
|
|
||||||
lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"}
|
|
||||||
|
@ -67,24 +67,20 @@ where
|
|||||||
self.board_type = board_type;
|
self.board_type = board_type;
|
||||||
}
|
}
|
||||||
async fn set_nss_low(&mut self) -> Result<(), RadioError> {
|
async fn set_nss_low(&mut self) -> Result<(), RadioError> {
|
||||||
let pwr = pac::PWR;
|
pac::PWR.subghzspicr().modify(|w| w.set_nss(false));
|
||||||
pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::LOW));
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
async fn set_nss_high(&mut self) -> Result<(), RadioError> {
|
async fn set_nss_high(&mut self) -> Result<(), RadioError> {
|
||||||
let pwr = pac::PWR;
|
pac::PWR.subghzspicr().modify(|w| w.set_nss(true));
|
||||||
pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::HIGH));
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
async fn reset(&mut self, _delay: &mut impl DelayUs) -> Result<(), RadioError> {
|
async fn reset(&mut self, _delay: &mut impl DelayUs) -> Result<(), RadioError> {
|
||||||
let rcc = pac::RCC;
|
pac::RCC.csr().modify(|w| w.set_rfrst(true));
|
||||||
rcc.csr().modify(|w| w.set_rfrst(true));
|
pac::RCC.csr().modify(|w| w.set_rfrst(false));
|
||||||
rcc.csr().modify(|w| w.set_rfrst(false));
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
async fn wait_on_busy(&mut self) -> Result<(), RadioError> {
|
async fn wait_on_busy(&mut self) -> Result<(), RadioError> {
|
||||||
let pwr = pac::PWR;
|
while pac::PWR.sr2().read().rfbusys() {}
|
||||||
while pwr.sr2().read().rfbusys() == pac::pwr::vals::Rfbusys::BUSY {}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,11 +280,7 @@ where
|
|||||||
self.busy.wait_for_low().await.map_err(|_| Busy)
|
self.busy.wait_for_low().await.map_err(|_| Busy)
|
||||||
}
|
}
|
||||||
async fn await_irq(&mut self) -> Result<(), RadioError> {
|
async fn await_irq(&mut self) -> Result<(), RadioError> {
|
||||||
if self.board_type != BoardType::RpPicoWaveshareSx1262 {
|
self.dio1.wait_for_high().await.map_err(|_| DIO1)?;
|
||||||
self.dio1.wait_for_high().await.map_err(|_| DIO1)?;
|
|
||||||
} else {
|
|
||||||
self.dio1.wait_for_rising_edge().await.map_err(|_| DIO1)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(async_fn_in_trait, impl_trait_projections)]
|
#![feature(async_fn_in_trait)]
|
||||||
//! embassy-lora holds LoRa-specific functionality.
|
//! embassy-lora holds LoRa-specific functionality.
|
||||||
|
|
||||||
pub(crate) mod fmt;
|
pub(crate) mod fmt;
|
||||||
|
@ -24,6 +24,6 @@ features = ["defmt"]
|
|||||||
defmt = { version = "0.3", optional = true }
|
defmt = { version = "0.3", optional = true }
|
||||||
log = { version = "0.4.14", optional = true }
|
log = { version = "0.4.14", optional = true }
|
||||||
|
|
||||||
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||||
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
|
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
|
||||||
|
@ -194,10 +194,15 @@ where
|
|||||||
self.bit_field_set(common::Register::ECON1, common::ECON1::mask().rxen());
|
self.bit_field_set(common::Register::ECON1, common::ECON1::mask().rxen());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the device's MAC address
|
||||||
|
pub fn address(&self) -> [u8; 6] {
|
||||||
|
self.mac_addr
|
||||||
|
}
|
||||||
|
|
||||||
/// Flushes the transmit buffer, ensuring all pending transmissions have completed
|
/// Flushes the transmit buffer, ensuring all pending transmissions have completed
|
||||||
/// NOTE: The returned packet *must* be `read` or `ignore`-d, otherwise this method will always
|
/// NOTE: The returned packet *must* be `read` or `ignore`-d, otherwise this method will always
|
||||||
/// return `None` on subsequent invocations
|
/// return `None` on subsequent invocations
|
||||||
pub fn receive<'a>(&mut self, buf: &'a mut [u8]) -> Option<&'a mut [u8]> {
|
pub fn receive(&mut self, buf: &mut [u8]) -> Option<usize> {
|
||||||
if self.pending_packets() == 0 {
|
if self.pending_packets() == 0 {
|
||||||
// Errata #6: we can't rely on PKTIF so we check PKTCNT
|
// Errata #6: we can't rely on PKTIF so we check PKTCNT
|
||||||
return None;
|
return None;
|
||||||
@ -241,7 +246,7 @@ where
|
|||||||
|
|
||||||
self.next_packet = next_packet;
|
self.next_packet = next_packet;
|
||||||
|
|
||||||
Some(&mut buf[..len as usize])
|
Some(len as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait_tx_ready(&mut self) {
|
fn wait_tx_ready(&mut self) {
|
||||||
@ -642,9 +647,8 @@ where
|
|||||||
fn receive(&mut self, cx: &mut core::task::Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
|
fn receive(&mut self, cx: &mut core::task::Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
|
||||||
let rx_buf = unsafe { &mut RX_BUF };
|
let rx_buf = unsafe { &mut RX_BUF };
|
||||||
let tx_buf = unsafe { &mut TX_BUF };
|
let tx_buf = unsafe { &mut TX_BUF };
|
||||||
if let Some(pkt) = self.receive(rx_buf) {
|
if let Some(n) = self.receive(rx_buf) {
|
||||||
let n = pkt.len();
|
Some((RxToken { buf: &mut rx_buf[..n] }, TxToken { buf: tx_buf, eth: self }))
|
||||||
Some((RxToken { buf: &mut pkt[..n] }, TxToken { buf: tx_buf, eth: self }))
|
|
||||||
} else {
|
} else {
|
||||||
cx.waker().wake_by_ref();
|
cx.waker().wake_by_ref();
|
||||||
None
|
None
|
||||||
|
@ -8,7 +8,7 @@ defmt = { version = "0.3", optional = true }
|
|||||||
log = { version = "0.4.14", optional = true }
|
log = { version = "0.4.14", optional = true }
|
||||||
|
|
||||||
embassy-time = { version = "0.1.3", path = "../embassy-time" }
|
embassy-time = { version = "0.1.3", path = "../embassy-time" }
|
||||||
embassy-sync = { version = "0.2.0", path = "../embassy-sync"}
|
embassy-sync = { version = "0.3.0", path = "../embassy-sync"}
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
|
||||||
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"}
|
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ embedded-io-async = { version = "0.5.0" }
|
|||||||
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
|
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||||
ppproto = { version = "0.1.2"}
|
ppproto = { version = "0.1.2"}
|
||||||
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
|
||||||
|
|
||||||
[package.metadata.embassy_docs]
|
[package.metadata.embassy_docs]
|
||||||
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-ppp-v$VERSION/embassy-net-ppp/src/"
|
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-ppp-v$VERSION/embassy-net-ppp/src/"
|
||||||
|
@ -52,7 +52,7 @@ smoltcp = { version = "0.10.0", default-features = false, features = [
|
|||||||
|
|
||||||
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
|
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
|
||||||
embassy-time = { version = "0.1.3", path = "../embassy-time" }
|
embassy-time = { version = "0.1.3", path = "../embassy-time" }
|
||||||
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
|
||||||
embedded-io-async = { version = "0.5.0", optional = true }
|
embedded-io-async = { version = "0.5.0", optional = true }
|
||||||
|
|
||||||
managed = { version = "0.8.0", default-features = false, features = [ "map" ] }
|
managed = { version = "0.8.0", default-features = false, features = [ "map" ] }
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections))]
|
#![cfg_attr(feature = "nightly", feature(async_fn_in_trait))]
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
#![doc = include_str!("../README.md")]
|
#![doc = include_str!("../README.md")]
|
||||||
|
|
||||||
@ -168,7 +168,7 @@ impl Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// IPv6 configuration with dynamic addressing.
|
/// IPv4 configuration with dynamic addressing.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```rust
|
/// ```rust
|
||||||
@ -258,7 +258,7 @@ fn to_smoltcp_hardware_address(addr: driver::HardwareAddress) -> HardwareAddress
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: Driver + 'static> Stack<D> {
|
impl<D: Driver> Stack<D> {
|
||||||
/// Create a new network stack.
|
/// Create a new network stack.
|
||||||
pub fn new<const SOCK: usize>(
|
pub fn new<const SOCK: usize>(
|
||||||
mut device: D,
|
mut device: D,
|
||||||
@ -555,7 +555,7 @@ impl<D: Driver + 'static> Stack<D> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "igmp")]
|
#[cfg(feature = "igmp")]
|
||||||
impl<D: Driver + 'static> Stack<D> {
|
impl<D: Driver> Stack<D> {
|
||||||
/// Join a multicast group.
|
/// Join a multicast group.
|
||||||
pub async fn join_multicast_group<T>(&self, addr: T) -> Result<bool, MulticastError>
|
pub async fn join_multicast_group<T>(&self, addr: T) -> Result<bool, MulticastError>
|
||||||
where
|
where
|
||||||
@ -645,7 +645,7 @@ impl SocketStack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: Driver + 'static> Inner<D> {
|
impl<D: Driver> Inner<D> {
|
||||||
#[cfg(feature = "proto-ipv4")]
|
#[cfg(feature = "proto-ipv4")]
|
||||||
pub fn set_config_v4(&mut self, _s: &mut SocketStack, config: ConfigV4) {
|
pub fn set_config_v4(&mut self, _s: &mut SocketStack, config: ConfigV4) {
|
||||||
// Handle static config.
|
// Handle static config.
|
||||||
|
@ -51,7 +51,7 @@ nrf52805 = ["nrf52805-pac", "_nrf52"]
|
|||||||
nrf52810 = ["nrf52810-pac", "_nrf52"]
|
nrf52810 = ["nrf52810-pac", "_nrf52"]
|
||||||
nrf52811 = ["nrf52811-pac", "_nrf52"]
|
nrf52811 = ["nrf52811-pac", "_nrf52"]
|
||||||
nrf52820 = ["nrf52820-pac", "_nrf52"]
|
nrf52820 = ["nrf52820-pac", "_nrf52"]
|
||||||
nrf52832 = ["nrf52832-pac", "_nrf52"]
|
nrf52832 = ["nrf52832-pac", "_nrf52", "_nrf52832_anomaly_109"]
|
||||||
nrf52833 = ["nrf52833-pac", "_nrf52", "_gpio-p1"]
|
nrf52833 = ["nrf52833-pac", "_nrf52", "_gpio-p1"]
|
||||||
nrf52840 = ["nrf52840-pac", "_nrf52", "_gpio-p1"]
|
nrf52840 = ["nrf52840-pac", "_nrf52", "_gpio-p1"]
|
||||||
nrf5340-app-s = ["_nrf5340-app", "_s"]
|
nrf5340-app-s = ["_nrf5340-app", "_s"]
|
||||||
@ -90,9 +90,12 @@ _ppi = []
|
|||||||
_dppi = []
|
_dppi = []
|
||||||
_gpio-p1 = []
|
_gpio-p1 = []
|
||||||
|
|
||||||
|
# Errata workarounds
|
||||||
|
_nrf52832_anomaly_109 = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
|
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
|
||||||
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
|
||||||
embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] }
|
embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] }
|
||||||
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||||
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true }
|
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional=true }
|
||||||
|
@ -86,7 +86,6 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) {
|
|||||||
unsafe { irq.enable() };
|
unsafe { irq.enable() };
|
||||||
|
|
||||||
let g = regs();
|
let g = regs();
|
||||||
g.events_port.write(|w| w);
|
|
||||||
g.intenset.write(|w| w.port().set());
|
g.intenset.write(|w| w.port().set());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections))]
|
#![cfg_attr(feature = "nightly", feature(async_fn_in_trait))]
|
||||||
#![doc = include_str!("../README.md")]
|
#![doc = include_str!("../README.md")]
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
@ -102,6 +102,7 @@ mod chip;
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! bind_interrupts {
|
macro_rules! bind_interrupts {
|
||||||
($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
|
($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
$vis struct $name;
|
$vis struct $name;
|
||||||
|
|
||||||
$(
|
$(
|
||||||
|
@ -68,30 +68,14 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
|||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
let s = T::state();
|
let s = T::state();
|
||||||
|
|
||||||
#[cfg(feature = "nrf52832")]
|
#[cfg(feature = "_nrf52832_anomaly_109")]
|
||||||
// NRF32 Anomaly 109 workaround... NRF52832
|
if r.events_started.read().bits() != 0 {
|
||||||
if r.intenset.read().started().is_enabled() && r.events_started.read().bits() != 0 {
|
s.waker.wake();
|
||||||
// Handle the first "fake" transmission
|
|
||||||
r.events_started.reset();
|
|
||||||
r.events_end.reset();
|
|
||||||
|
|
||||||
// Update DMA registers with correct rx/tx buffer sizes
|
|
||||||
r.rxd
|
|
||||||
.maxcnt
|
|
||||||
.write(|w| unsafe { w.maxcnt().bits(s.rx.load(Ordering::Relaxed)) });
|
|
||||||
r.txd
|
|
||||||
.maxcnt
|
|
||||||
.write(|w| unsafe { w.maxcnt().bits(s.tx.load(Ordering::Relaxed)) });
|
|
||||||
|
|
||||||
// Disable interrupt for STARTED event...
|
|
||||||
r.intenclr.write(|w| w.started().clear());
|
r.intenclr.write(|w| w.started().clear());
|
||||||
// ... and start actual, hopefully glitch-free transmission
|
|
||||||
r.tasks_start.write(|w| unsafe { w.bits(1) });
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.events_end.read().bits() != 0 {
|
if r.events_end.read().bits() != 0 {
|
||||||
s.end_waker.wake();
|
s.waker.wake();
|
||||||
r.intenclr.write(|w| w.end().clear());
|
r.intenclr.write(|w| w.end().clear());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -192,7 +176,7 @@ impl<'d, T: Instance> Spim<'d, T> {
|
|||||||
let mut spim = Self { _p: spim };
|
let mut spim = Self { _p: spim };
|
||||||
|
|
||||||
// Apply runtime peripheral configuration
|
// Apply runtime peripheral configuration
|
||||||
Self::set_config(&mut spim, &config);
|
Self::set_config(&mut spim, &config).unwrap();
|
||||||
|
|
||||||
// Disable all events interrupts
|
// Disable all events interrupts
|
||||||
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
||||||
@ -222,8 +206,7 @@ impl<'d, T: Instance> Spim<'d, T> {
|
|||||||
r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) });
|
r.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr as _) });
|
||||||
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(rx_len as _) });
|
r.rxd.maxcnt.write(|w| unsafe { w.maxcnt().bits(rx_len as _) });
|
||||||
|
|
||||||
// ANOMALY 109 workaround
|
#[cfg(feature = "_nrf52832_anomaly_109")]
|
||||||
#[cfg(feature = "nrf52832")]
|
|
||||||
{
|
{
|
||||||
let s = T::state();
|
let s = T::state();
|
||||||
|
|
||||||
@ -254,6 +237,9 @@ impl<'d, T: Instance> Spim<'d, T> {
|
|||||||
fn blocking_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
|
fn blocking_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
|
||||||
self.prepare(rx, tx)?;
|
self.prepare(rx, tx)?;
|
||||||
|
|
||||||
|
#[cfg(feature = "_nrf52832_anomaly_109")]
|
||||||
|
while let Poll::Pending = self.nrf52832_dma_workaround_status() {}
|
||||||
|
|
||||||
// Wait for 'end' event.
|
// Wait for 'end' event.
|
||||||
while T::regs().events_end.read().bits() == 0 {}
|
while T::regs().events_end.read().bits() == 0 {}
|
||||||
|
|
||||||
@ -278,9 +264,19 @@ impl<'d, T: Instance> Spim<'d, T> {
|
|||||||
async fn async_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
|
async fn async_inner_from_ram(&mut self, rx: *mut [u8], tx: *const [u8]) -> Result<(), Error> {
|
||||||
self.prepare(rx, tx)?;
|
self.prepare(rx, tx)?;
|
||||||
|
|
||||||
|
#[cfg(feature = "_nrf52832_anomaly_109")]
|
||||||
|
poll_fn(|cx| {
|
||||||
|
let s = T::state();
|
||||||
|
|
||||||
|
s.waker.register(cx.waker());
|
||||||
|
|
||||||
|
self.nrf52832_dma_workaround_status()
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
// Wait for 'end' event.
|
// Wait for 'end' event.
|
||||||
poll_fn(|cx| {
|
poll_fn(|cx| {
|
||||||
T::state().end_waker.register(cx.waker());
|
T::state().waker.register(cx.waker());
|
||||||
if T::regs().events_end.read().bits() != 0 {
|
if T::regs().events_end.read().bits() != 0 {
|
||||||
return Poll::Ready(());
|
return Poll::Ready(());
|
||||||
}
|
}
|
||||||
@ -371,6 +367,32 @@ impl<'d, T: Instance> Spim<'d, T> {
|
|||||||
pub async fn write_from_ram(&mut self, data: &[u8]) -> Result<(), Error> {
|
pub async fn write_from_ram(&mut self, data: &[u8]) -> Result<(), Error> {
|
||||||
self.async_inner_from_ram(&mut [], data).await
|
self.async_inner_from_ram(&mut [], data).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "_nrf52832_anomaly_109")]
|
||||||
|
fn nrf52832_dma_workaround_status(&mut self) -> Poll<()> {
|
||||||
|
let r = T::regs();
|
||||||
|
if r.events_started.read().bits() != 0 {
|
||||||
|
let s = T::state();
|
||||||
|
|
||||||
|
// Handle the first "fake" transmission
|
||||||
|
r.events_started.reset();
|
||||||
|
r.events_end.reset();
|
||||||
|
|
||||||
|
// Update DMA registers with correct rx/tx buffer sizes
|
||||||
|
r.rxd
|
||||||
|
.maxcnt
|
||||||
|
.write(|w| unsafe { w.maxcnt().bits(s.rx.load(Ordering::Relaxed)) });
|
||||||
|
r.txd
|
||||||
|
.maxcnt
|
||||||
|
.write(|w| unsafe { w.maxcnt().bits(s.tx.load(Ordering::Relaxed)) });
|
||||||
|
|
||||||
|
r.intenset.write(|w| w.end().set());
|
||||||
|
// ... and start actual, hopefully glitch-free transmission
|
||||||
|
r.tasks_start.write(|w| unsafe { w.bits(1) });
|
||||||
|
return Poll::Ready(());
|
||||||
|
}
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> Drop for Spim<'d, T> {
|
impl<'d, T: Instance> Drop for Spim<'d, T> {
|
||||||
@ -395,7 +417,7 @@ impl<'d, T: Instance> Drop for Spim<'d, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) mod sealed {
|
pub(crate) mod sealed {
|
||||||
#[cfg(feature = "nrf52832")]
|
#[cfg(feature = "_nrf52832_anomaly_109")]
|
||||||
use core::sync::atomic::AtomicU8;
|
use core::sync::atomic::AtomicU8;
|
||||||
|
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
@ -403,20 +425,20 @@ pub(crate) mod sealed {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub struct State {
|
pub struct State {
|
||||||
pub end_waker: AtomicWaker,
|
pub waker: AtomicWaker,
|
||||||
#[cfg(feature = "nrf52832")]
|
#[cfg(feature = "_nrf52832_anomaly_109")]
|
||||||
pub rx: AtomicU8,
|
pub rx: AtomicU8,
|
||||||
#[cfg(feature = "nrf52832")]
|
#[cfg(feature = "_nrf52832_anomaly_109")]
|
||||||
pub tx: AtomicU8,
|
pub tx: AtomicU8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
end_waker: AtomicWaker::new(),
|
waker: AtomicWaker::new(),
|
||||||
#[cfg(feature = "nrf52832")]
|
#[cfg(feature = "_nrf52832_anomaly_109")]
|
||||||
rx: AtomicU8::new(0),
|
rx: AtomicU8::new(0),
|
||||||
#[cfg(feature = "nrf52832")]
|
#[cfg(feature = "_nrf52832_anomaly_109")]
|
||||||
tx: AtomicU8::new(0),
|
tx: AtomicU8::new(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -544,7 +566,8 @@ mod eha {
|
|||||||
|
|
||||||
impl<'d, T: Instance> SetConfig for Spim<'d, T> {
|
impl<'d, T: Instance> SetConfig for Spim<'d, T> {
|
||||||
type Config = Config;
|
type Config = Config;
|
||||||
fn set_config(&mut self, config: &Self::Config) {
|
type ConfigError = ();
|
||||||
|
fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
// Configure mode.
|
// Configure mode.
|
||||||
let mode = config.mode;
|
let mode = config.mode;
|
||||||
@ -582,5 +605,7 @@ impl<'d, T: Instance> SetConfig for Spim<'d, T> {
|
|||||||
// Set over-read character
|
// Set over-read character
|
||||||
let orc = config.orc;
|
let orc = config.orc;
|
||||||
r.orc.write(|w| unsafe { w.orc().bits(orc) });
|
r.orc.write(|w| unsafe { w.orc().bits(orc) });
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,7 +172,7 @@ impl<'d, T: Instance> Spis<'d, T> {
|
|||||||
let mut spis = Self { _p: spis };
|
let mut spis = Self { _p: spis };
|
||||||
|
|
||||||
// Apply runtime peripheral configuration
|
// Apply runtime peripheral configuration
|
||||||
Self::set_config(&mut spis, &config);
|
Self::set_config(&mut spis, &config).unwrap();
|
||||||
|
|
||||||
// Disable all events interrupts.
|
// Disable all events interrupts.
|
||||||
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
||||||
@ -467,7 +467,8 @@ macro_rules! impl_spis {
|
|||||||
|
|
||||||
impl<'d, T: Instance> SetConfig for Spis<'d, T> {
|
impl<'d, T: Instance> SetConfig for Spis<'d, T> {
|
||||||
type Config = Config;
|
type Config = Config;
|
||||||
fn set_config(&mut self, config: &Self::Config) {
|
type ConfigError = ();
|
||||||
|
fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
// Configure mode.
|
// Configure mode.
|
||||||
let mode = config.mode;
|
let mode = config.mode;
|
||||||
@ -509,5 +510,7 @@ impl<'d, T: Instance> SetConfig for Spis<'d, T> {
|
|||||||
// Configure auto-acquire on 'transfer end' event.
|
// Configure auto-acquire on 'transfer end' event.
|
||||||
let auto_acquire = config.auto_acquire;
|
let auto_acquire = config.auto_acquire;
|
||||||
r.shorts.write(|w| w.end_acquire().bit(auto_acquire));
|
r.shorts.write(|w| w.end_acquire().bit(auto_acquire));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,7 +170,7 @@ impl<'d, T: Instance> Twim<'d, T> {
|
|||||||
let mut twim = Self { _p: twim };
|
let mut twim = Self { _p: twim };
|
||||||
|
|
||||||
// Apply runtime peripheral configuration
|
// Apply runtime peripheral configuration
|
||||||
Self::set_config(&mut twim, &config);
|
Self::set_config(&mut twim, &config).unwrap();
|
||||||
|
|
||||||
// Disable all events interrupts
|
// Disable all events interrupts
|
||||||
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
||||||
@ -890,9 +890,12 @@ mod eha {
|
|||||||
|
|
||||||
impl<'d, T: Instance> SetConfig for Twim<'d, T> {
|
impl<'d, T: Instance> SetConfig for Twim<'d, T> {
|
||||||
type Config = Config;
|
type Config = Config;
|
||||||
fn set_config(&mut self, config: &Self::Config) {
|
type ConfigError = ();
|
||||||
|
fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
|
||||||
let r = T::regs();
|
let r = T::regs();
|
||||||
r.frequency
|
r.frequency
|
||||||
.write(|w| unsafe { w.frequency().bits(config.frequency as u32) });
|
.write(|w| unsafe { w.frequency().bits(config.frequency as u32) });
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ nightly = ["embedded-hal-1", "embedded-hal-async", "embedded-storage-async", "em
|
|||||||
unstable-traits = ["embedded-hal-1", "embedded-hal-nb"]
|
unstable-traits = ["embedded-hal-1", "embedded-hal-nb"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
|
||||||
embassy-time = { version = "0.1.3", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] }
|
embassy-time = { version = "0.1.3", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] }
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||||
embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] }
|
embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] }
|
||||||
@ -89,7 +89,6 @@ embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1", optional =
|
|||||||
embedded-hal-async = { version = "=1.0.0-rc.1", optional = true}
|
embedded-hal-async = { version = "=1.0.0-rc.1", optional = true}
|
||||||
embedded-hal-nb = { version = "=1.0.0-rc.1", optional = true}
|
embedded-hal-nb = { version = "=1.0.0-rc.1", optional = true}
|
||||||
|
|
||||||
paste = "1.0"
|
|
||||||
pio-proc = {version= "0.2" }
|
pio-proc = {version= "0.2" }
|
||||||
pio = {version= "0.2.1" }
|
pio = {version= "0.2.1" }
|
||||||
rp2040-boot2 = "0.3"
|
rp2040-boot2 = "0.3"
|
||||||
|
@ -97,6 +97,12 @@ impl<'d, T: Pin> Input<'d, T> {
|
|||||||
Self { pin }
|
Self { pin }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the pin's Schmitt trigger.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_schmitt(&mut self, enable: bool) {
|
||||||
|
self.pin.set_schmitt(enable)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_high(&self) -> bool {
|
pub fn is_high(&self) -> bool {
|
||||||
self.pin.is_high()
|
self.pin.is_high()
|
||||||
@ -216,7 +222,6 @@ fn IO_IRQ_QSPI() {
|
|||||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||||
struct InputFuture<'a, T: Pin> {
|
struct InputFuture<'a, T: Pin> {
|
||||||
pin: PeripheralRef<'a, T>,
|
pin: PeripheralRef<'a, T>,
|
||||||
level: InterruptTrigger,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Pin> InputFuture<'d, T> {
|
impl<'d, T: Pin> InputFuture<'d, T> {
|
||||||
@ -243,7 +248,6 @@ impl<'d, T: Pin> InputFuture<'d, T> {
|
|||||||
.inte((pin.pin() / 8) as usize)
|
.inte((pin.pin() / 8) as usize)
|
||||||
.write_set(|w| match level {
|
.write_set(|w| match level {
|
||||||
InterruptTrigger::LevelHigh => {
|
InterruptTrigger::LevelHigh => {
|
||||||
trace!("InputFuture::new enable LevelHigh for pin {}", pin.pin());
|
|
||||||
w.set_level_high(pin_group, true);
|
w.set_level_high(pin_group, true);
|
||||||
}
|
}
|
||||||
InterruptTrigger::LevelLow => {
|
InterruptTrigger::LevelLow => {
|
||||||
@ -261,7 +265,7 @@ impl<'d, T: Pin> InputFuture<'d, T> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self { pin, level }
|
Self { pin }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,14 +301,8 @@ impl<'d, T: Pin> Future for InputFuture<'d, T> {
|
|||||||
&& !inte.level_high(pin_group)
|
&& !inte.level_high(pin_group)
|
||||||
&& !inte.level_low(pin_group)
|
&& !inte.level_low(pin_group)
|
||||||
{
|
{
|
||||||
trace!(
|
|
||||||
"{:?} for pin {} was cleared, return Poll::Ready",
|
|
||||||
self.level,
|
|
||||||
self.pin.pin()
|
|
||||||
);
|
|
||||||
return Poll::Ready(());
|
return Poll::Ready(());
|
||||||
}
|
}
|
||||||
trace!("InputFuture::poll return Poll::Pending");
|
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -326,6 +324,18 @@ impl<'d, T: Pin> Output<'d, T> {
|
|||||||
Self { pin }
|
Self { pin }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the pin's drive strength.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_drive_strength(&mut self, strength: Drive) {
|
||||||
|
self.pin.set_drive_strength(strength)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the pin's slew rate.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_slew_rate(&mut self, slew_rate: SlewRate) {
|
||||||
|
self.pin.set_slew_rate(slew_rate)
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the output as high.
|
/// Set the output as high.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_high(&mut self) {
|
pub fn set_high(&mut self) {
|
||||||
@ -386,6 +396,18 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
|
|||||||
Self { pin }
|
Self { pin }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the pin's drive strength.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_drive_strength(&mut self, strength: Drive) {
|
||||||
|
self.pin.set_drive_strength(strength)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the pin's slew rate.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_slew_rate(&mut self, slew_rate: SlewRate) {
|
||||||
|
self.pin.set_slew_rate(slew_rate)
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the output as high.
|
/// Set the output as high.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_high(&mut self) {
|
pub fn set_high(&mut self) {
|
||||||
@ -541,6 +563,14 @@ impl<'d, T: Pin> Flex<'d, T> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the pin's Schmitt trigger.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_schmitt(&mut self, enable: bool) {
|
||||||
|
self.pin.pad_ctrl().modify(|w| {
|
||||||
|
w.set_schmitt(enable);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// Put the pin into input mode.
|
/// Put the pin into input mode.
|
||||||
///
|
///
|
||||||
/// The pull setting is left unchanged.
|
/// The pull setting is left unchanged.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections))]
|
#![cfg_attr(feature = "nightly", feature(async_fn_in_trait))]
|
||||||
|
|
||||||
// This mod MUST go first, so that the others see its macros.
|
// This mod MUST go first, so that the others see its macros.
|
||||||
pub(crate) mod fmt;
|
pub(crate) mod fmt;
|
||||||
@ -90,7 +90,8 @@ embassy_hal_internal::interrupt_mod!(
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! bind_interrupts {
|
macro_rules! bind_interrupts {
|
||||||
($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
|
($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
|
||||||
$vis struct $name;
|
#[derive(Copy, Clone)]
|
||||||
|
$vis struct $name;
|
||||||
|
|
||||||
$(
|
$(
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
|
@ -1079,18 +1079,43 @@ impl_pio!(PIO1, 1, PIO1, PIO1_0, PIO1_IRQ_0);
|
|||||||
pub trait PioPin: sealed::PioPin + gpio::Pin {}
|
pub trait PioPin: sealed::PioPin + gpio::Pin {}
|
||||||
|
|
||||||
macro_rules! impl_pio_pin {
|
macro_rules! impl_pio_pin {
|
||||||
($( $num:tt )*) => {
|
($( $pin:ident, )*) => {
|
||||||
$(
|
$(
|
||||||
paste::paste!{
|
impl sealed::PioPin for peripherals::$pin {}
|
||||||
impl sealed::PioPin for peripherals::[< PIN_ $num >] {}
|
impl PioPin for peripherals::$pin {}
|
||||||
impl PioPin for peripherals::[< PIN_ $num >] {}
|
|
||||||
}
|
|
||||||
)*
|
)*
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_pio_pin! {
|
impl_pio_pin! {
|
||||||
0 1 2 3 4 5 6 7 8 9
|
PIN_0,
|
||||||
10 11 12 13 14 15 16 17 18 19
|
PIN_1,
|
||||||
20 21 22 23 24 25 26 27 28 29
|
PIN_2,
|
||||||
|
PIN_3,
|
||||||
|
PIN_4,
|
||||||
|
PIN_5,
|
||||||
|
PIN_6,
|
||||||
|
PIN_7,
|
||||||
|
PIN_8,
|
||||||
|
PIN_9,
|
||||||
|
PIN_10,
|
||||||
|
PIN_11,
|
||||||
|
PIN_12,
|
||||||
|
PIN_13,
|
||||||
|
PIN_14,
|
||||||
|
PIN_15,
|
||||||
|
PIN_16,
|
||||||
|
PIN_17,
|
||||||
|
PIN_18,
|
||||||
|
PIN_19,
|
||||||
|
PIN_20,
|
||||||
|
PIN_21,
|
||||||
|
PIN_22,
|
||||||
|
PIN_23,
|
||||||
|
PIN_24,
|
||||||
|
PIN_25,
|
||||||
|
PIN_26,
|
||||||
|
PIN_27,
|
||||||
|
PIN_28,
|
||||||
|
PIN_29,
|
||||||
}
|
}
|
||||||
|
@ -597,7 +597,8 @@ mod eha {
|
|||||||
|
|
||||||
impl<'d, T: Instance, M: Mode> SetConfig for Spi<'d, T, M> {
|
impl<'d, T: Instance, M: Mode> SetConfig for Spi<'d, T, M> {
|
||||||
type Config = Config;
|
type Config = Config;
|
||||||
fn set_config(&mut self, config: &Self::Config) {
|
type ConfigError = ();
|
||||||
|
fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
|
||||||
let p = self.inner.regs();
|
let p = self.inner.regs();
|
||||||
let (presc, postdiv) = calc_prescs(config.frequency);
|
let (presc, postdiv) = calc_prescs(config.frequency);
|
||||||
p.cpsr().write(|w| w.set_cpsdvsr(presc));
|
p.cpsr().write(|w| w.set_cpsdvsr(presc));
|
||||||
@ -607,5 +608,7 @@ impl<'d, T: Instance, M: Mode> SetConfig for Spi<'d, T, M> {
|
|||||||
w.set_sph(config.phase == Phase::CaptureOnSecondTransition);
|
w.set_sph(config.phase == Phase::CaptureOnSecondTransition);
|
||||||
w.set_scr(postdiv);
|
w.set_scr(postdiv);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -490,8 +490,6 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterr
|
|||||||
w.set_oeic(ris.oeris());
|
w.set_oeic(ris.oeris());
|
||||||
});
|
});
|
||||||
|
|
||||||
trace!("on_interrupt ris={:#X}", ris.0);
|
|
||||||
|
|
||||||
// Errors
|
// Errors
|
||||||
if ris.feris() {
|
if ris.feris() {
|
||||||
warn!("Framing error");
|
warn!("Framing error");
|
||||||
|
@ -12,7 +12,7 @@ features = ["stm32wb55rg"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" }
|
embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" }
|
||||||
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
|
||||||
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
|
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||||
embassy-hal-internal = { version = "0.1.0", path = "../embassy-hal-internal" }
|
embassy-hal-internal = { version = "0.1.0", path = "../embassy-hal-internal" }
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use core::marker::PhantomData;
|
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
|
|
||||||
use embassy_stm32::ipcc::Ipcc;
|
use embassy_stm32::ipcc::Ipcc;
|
||||||
@ -13,7 +12,7 @@ use crate::unsafe_linked_list::LinkedListNode;
|
|||||||
use crate::{channels, evt};
|
use crate::{channels, evt};
|
||||||
|
|
||||||
pub struct Ble {
|
pub struct Ble {
|
||||||
phantom: PhantomData<Ble>,
|
_private: (),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ble {
|
impl Ble {
|
||||||
@ -29,7 +28,7 @@ impl Ble {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Self { phantom: PhantomData }
|
Self { _private: () }
|
||||||
}
|
}
|
||||||
/// `HW_IPCC_BLE_EvtNot`
|
/// `HW_IPCC_BLE_EvtNot`
|
||||||
pub async fn tl_read(&self) -> EvtBox<Self> {
|
pub async fn tl_read(&self) -> EvtBox<Self> {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use core::future::poll_fn;
|
use core::future::poll_fn;
|
||||||
use core::marker::PhantomData;
|
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
@ -21,12 +20,12 @@ static MAC_WAKER: AtomicWaker = AtomicWaker::new();
|
|||||||
static MAC_EVT_OUT: AtomicBool = AtomicBool::new(false);
|
static MAC_EVT_OUT: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
pub struct Mac {
|
pub struct Mac {
|
||||||
phantom: PhantomData<Mac>,
|
_private: (),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mac {
|
impl Mac {
|
||||||
pub(crate) fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
Self { phantom: PhantomData }
|
Self { _private: () }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `HW_IPCC_MAC_802_15_4_EvtNot`
|
/// `HW_IPCC_MAC_802_15_4_EvtNot`
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
//! Memory manager routines
|
//! Memory manager routines
|
||||||
use core::future::poll_fn;
|
use core::future::poll_fn;
|
||||||
use core::marker::PhantomData;
|
|
||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
@ -21,7 +20,7 @@ static MM_WAKER: AtomicWaker = AtomicWaker::new();
|
|||||||
static mut LOCAL_FREE_BUF_QUEUE: Aligned<A4, MaybeUninit<LinkedListNode>> = Aligned(MaybeUninit::uninit());
|
static mut LOCAL_FREE_BUF_QUEUE: Aligned<A4, MaybeUninit<LinkedListNode>> = Aligned(MaybeUninit::uninit());
|
||||||
|
|
||||||
pub struct MemoryManager {
|
pub struct MemoryManager {
|
||||||
phantom: PhantomData<MemoryManager>,
|
_private: (),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MemoryManager {
|
impl MemoryManager {
|
||||||
@ -44,7 +43,7 @@ impl MemoryManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Self { phantom: PhantomData }
|
Self { _private: () }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run_queue(&self) {
|
pub async fn run_queue(&self) {
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use core::marker::PhantomData;
|
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
|
|
||||||
use crate::cmd::CmdPacket;
|
use crate::cmd::CmdPacket;
|
||||||
@ -12,7 +11,7 @@ use crate::unsafe_linked_list::LinkedListNode;
|
|||||||
use crate::{channels, Ipcc, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_DEVICE_INFO_TABLE, TL_SYS_TABLE};
|
use crate::{channels, Ipcc, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_DEVICE_INFO_TABLE, TL_SYS_TABLE};
|
||||||
|
|
||||||
pub struct Sys {
|
pub struct Sys {
|
||||||
phantom: PhantomData<Sys>,
|
_private: (),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sys {
|
impl Sys {
|
||||||
@ -27,7 +26,7 @@ impl Sys {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Self { phantom: PhantomData }
|
Self { _private: () }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns CPU2 wireless firmware information (if present).
|
/// Returns CPU2 wireless firmware information (if present).
|
||||||
|
@ -21,17 +21,18 @@ flavors = [
|
|||||||
{ regex_feature = "stm32g4.*", target = "thumbv7em-none-eabi" },
|
{ regex_feature = "stm32g4.*", target = "thumbv7em-none-eabi" },
|
||||||
{ regex_feature = "stm32h5.*", target = "thumbv8m.main-none-eabihf" },
|
{ regex_feature = "stm32h5.*", target = "thumbv8m.main-none-eabihf" },
|
||||||
{ regex_feature = "stm32h7.*", target = "thumbv7em-none-eabi" },
|
{ regex_feature = "stm32h7.*", target = "thumbv7em-none-eabi" },
|
||||||
{ regex_feature = "stm32l0.*", target = "thumbv6m-none-eabi" },
|
{ regex_feature = "stm32l0.*", target = "thumbv6m-none-eabi", features = ["low-power"] },
|
||||||
{ regex_feature = "stm32l1.*", target = "thumbv7m-none-eabi" },
|
{ regex_feature = "stm32l1.*", target = "thumbv7m-none-eabi" },
|
||||||
{ regex_feature = "stm32l4.*", target = "thumbv7em-none-eabi" },
|
{ regex_feature = "stm32l4.*", target = "thumbv7em-none-eabi" },
|
||||||
{ regex_feature = "stm32l5.*", target = "thumbv8m.main-none-eabihf" },
|
{ regex_feature = "stm32l5.*", target = "thumbv8m.main-none-eabihf" },
|
||||||
{ regex_feature = "stm32u5.*", target = "thumbv8m.main-none-eabihf" },
|
{ regex_feature = "stm32u5.*", target = "thumbv8m.main-none-eabihf" },
|
||||||
{ regex_feature = "stm32wb.*", target = "thumbv7em-none-eabi" },
|
{ regex_feature = "stm32wb.*", target = "thumbv7em-none-eabi" },
|
||||||
|
{ regex_feature = "stm32wba.*", target = "thumbv8m.main-none-eabihf" },
|
||||||
{ regex_feature = "stm32wl.*", target = "thumbv7em-none-eabi" },
|
{ regex_feature = "stm32wl.*", target = "thumbv7em-none-eabi" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
embassy-sync = { version = "0.2.0", path = "../embassy-sync" }
|
embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
|
||||||
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
|
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
|
||||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||||
embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] }
|
embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] }
|
||||||
@ -58,11 +59,11 @@ sdio-host = "0.5.0"
|
|||||||
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
|
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
|
||||||
critical-section = "1.1"
|
critical-section = "1.1"
|
||||||
atomic-polyfill = "1.0.1"
|
atomic-polyfill = "1.0.1"
|
||||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e667107cf81934383ec5744f49b2cda0599ec749" }
|
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-06d13dfd245cc9bf86fd88c35b401bdb84c079c4" }
|
||||||
vcell = "0.1.3"
|
vcell = "0.1.3"
|
||||||
bxcan = "0.7.0"
|
bxcan = "0.7.0"
|
||||||
nb = "1.0.0"
|
nb = "1.0.0"
|
||||||
stm32-fmc = "0.2.4"
|
stm32-fmc = "0.3.0"
|
||||||
seq-macro = "0.3.0"
|
seq-macro = "0.3.0"
|
||||||
cfg-if = "1.0.0"
|
cfg-if = "1.0.0"
|
||||||
embedded-io = { version = "0.5.0" }
|
embedded-io = { version = "0.5.0" }
|
||||||
@ -77,7 +78,8 @@ critical-section = { version = "1.1", features = ["std"] }
|
|||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
proc-macro2 = "1.0.36"
|
proc-macro2 = "1.0.36"
|
||||||
quote = "1.0.15"
|
quote = "1.0.15"
|
||||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e667107cf81934383ec5744f49b2cda0599ec749", default-features = false, features = ["metadata"]}
|
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-06d13dfd245cc9bf86fd88c35b401bdb84c079c4", default-features = false, features = ["metadata"]}
|
||||||
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["rt"]
|
default = ["rt"]
|
||||||
@ -133,6 +135,22 @@ time-driver-tim12 = ["_time-driver"]
|
|||||||
time-driver-tim15 = ["_time-driver"]
|
time-driver-tim15 = ["_time-driver"]
|
||||||
|
|
||||||
|
|
||||||
|
#! ## Analog Switch Pins (Pxy_C) on STM32H7 series
|
||||||
|
#! Get `PXY` and `PXY_C` singletons. Digital impls are on `PXY`, Analog impls are on `PXY_C`
|
||||||
|
#! If disabled, you get only the `PXY` singleton. It has both digital and analog impls.
|
||||||
|
|
||||||
|
## Split PA0
|
||||||
|
split-pa0 = ["_split-pins-enabled"]
|
||||||
|
## Split PA1
|
||||||
|
split-pa1 = ["_split-pins-enabled"]
|
||||||
|
## Split PC2
|
||||||
|
split-pc2 = ["_split-pins-enabled"]
|
||||||
|
## Split PC3
|
||||||
|
split-pc3 = ["_split-pins-enabled"]
|
||||||
|
|
||||||
|
## internal use only
|
||||||
|
_split-pins-enabled = []
|
||||||
|
|
||||||
#! ## Chip-selection features
|
#! ## Chip-selection features
|
||||||
#! Select your chip by specifying the model as a feature, e.g. `stm32c011d6`.
|
#! Select your chip by specifying the model as a feature, e.g. `stm32c011d6`.
|
||||||
#! Check the `Cargo.toml` for the latest list of supported chips.
|
#! Check the `Cargo.toml` for the latest list of supported chips.
|
||||||
@ -1454,6 +1472,10 @@ stm32wb55vc = [ "stm32-metapac/stm32wb55vc" ]
|
|||||||
stm32wb55ve = [ "stm32-metapac/stm32wb55ve" ]
|
stm32wb55ve = [ "stm32-metapac/stm32wb55ve" ]
|
||||||
stm32wb55vg = [ "stm32-metapac/stm32wb55vg" ]
|
stm32wb55vg = [ "stm32-metapac/stm32wb55vg" ]
|
||||||
stm32wb55vy = [ "stm32-metapac/stm32wb55vy" ]
|
stm32wb55vy = [ "stm32-metapac/stm32wb55vy" ]
|
||||||
|
stm32wba52ce = [ "stm32-metapac/stm32wba52ce" ]
|
||||||
|
stm32wba52cg = [ "stm32-metapac/stm32wba52cg" ]
|
||||||
|
stm32wba52ke = [ "stm32-metapac/stm32wba52ke" ]
|
||||||
|
stm32wba52kg = [ "stm32-metapac/stm32wba52kg" ]
|
||||||
stm32wl54cc-cm4 = [ "stm32-metapac/stm32wl54cc-cm4" ]
|
stm32wl54cc-cm4 = [ "stm32-metapac/stm32wl54cc-cm4" ]
|
||||||
stm32wl54cc-cm0p = [ "stm32-metapac/stm32wl54cc-cm0p" ]
|
stm32wl54cc-cm0p = [ "stm32-metapac/stm32wl54cc-cm0p" ]
|
||||||
stm32wl54jc-cm4 = [ "stm32-metapac/stm32wl54jc-cm4" ]
|
stm32wl54jc-cm4 = [ "stm32-metapac/stm32wl54jc-cm4" ]
|
||||||
|
@ -81,6 +81,60 @@ fn main() {
|
|||||||
singletons.push(c.name.to_string());
|
singletons.push(c.name.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut pin_set = std::collections::HashSet::new();
|
||||||
|
for p in METADATA.peripherals {
|
||||||
|
for pin in p.pins {
|
||||||
|
pin_set.insert(pin.pin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SplitFeature {
|
||||||
|
feature_name: String,
|
||||||
|
pin_name_with_c: String,
|
||||||
|
#[cfg(feature = "_split-pins-enabled")]
|
||||||
|
pin_name_without_c: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extra analog switch pins available on most H7 chips
|
||||||
|
let split_features: Vec<SplitFeature> = vec![
|
||||||
|
#[cfg(feature = "split-pa0")]
|
||||||
|
SplitFeature {
|
||||||
|
feature_name: "split-pa0".to_string(),
|
||||||
|
pin_name_with_c: "PA0_C".to_string(),
|
||||||
|
pin_name_without_c: "PA0".to_string(),
|
||||||
|
},
|
||||||
|
#[cfg(feature = "split-pa1")]
|
||||||
|
SplitFeature {
|
||||||
|
feature_name: "split-pa1".to_string(),
|
||||||
|
pin_name_with_c: "PA1_C".to_string(),
|
||||||
|
pin_name_without_c: "PA1".to_string(),
|
||||||
|
},
|
||||||
|
#[cfg(feature = "split-pc2")]
|
||||||
|
SplitFeature {
|
||||||
|
feature_name: "split-pc2".to_string(),
|
||||||
|
pin_name_with_c: "PC2_C".to_string(),
|
||||||
|
pin_name_without_c: "PC2".to_string(),
|
||||||
|
},
|
||||||
|
#[cfg(feature = "split-pc3")]
|
||||||
|
SplitFeature {
|
||||||
|
feature_name: "split-pc3".to_string(),
|
||||||
|
pin_name_with_c: "PC3_C".to_string(),
|
||||||
|
pin_name_without_c: "PC3".to_string(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
for split_feature in &split_features {
|
||||||
|
if pin_set.contains(split_feature.pin_name_with_c.as_str()) {
|
||||||
|
singletons.push(split_feature.pin_name_with_c.clone());
|
||||||
|
} else {
|
||||||
|
panic!(
|
||||||
|
"'{}' feature invalid for this chip! No pin '{}' found.\n
|
||||||
|
Found pins: {:#?}",
|
||||||
|
split_feature.feature_name, split_feature.pin_name_with_c, pin_set
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ========
|
// ========
|
||||||
// Handle time-driver-XXXX features.
|
// Handle time-driver-XXXX features.
|
||||||
|
|
||||||
@ -463,6 +517,15 @@ fn main() {
|
|||||||
(("lpuart", "RTS"), quote!(crate::usart::RtsPin)),
|
(("lpuart", "RTS"), quote!(crate::usart::RtsPin)),
|
||||||
(("lpuart", "CK"), quote!(crate::usart::CkPin)),
|
(("lpuart", "CK"), quote!(crate::usart::CkPin)),
|
||||||
(("lpuart", "DE"), quote!(crate::usart::DePin)),
|
(("lpuart", "DE"), quote!(crate::usart::DePin)),
|
||||||
|
(("sai", "SCK_A"), quote!(crate::sai::SckAPin)),
|
||||||
|
(("sai", "SCK_B"), quote!(crate::sai::SckBPin)),
|
||||||
|
(("sai", "FS_A"), quote!(crate::sai::FsAPin)),
|
||||||
|
(("sai", "FS_B"), quote!(crate::sai::FsBPin)),
|
||||||
|
(("sai", "SD_A"), quote!(crate::sai::SdAPin)),
|
||||||
|
(("sai", "SD_B"), quote!(crate::sai::SdBPin)),
|
||||||
|
(("sai", "MCLK_A"), quote!(crate::sai::MclkAPin)),
|
||||||
|
(("sai", "MCLK_B"), quote!(crate::sai::MclkBPin)),
|
||||||
|
(("sai", "WS"), quote!(crate::sai::WsPin)),
|
||||||
(("spi", "SCK"), quote!(crate::spi::SckPin)),
|
(("spi", "SCK"), quote!(crate::spi::SckPin)),
|
||||||
(("spi", "MOSI"), quote!(crate::spi::MosiPin)),
|
(("spi", "MOSI"), quote!(crate::spi::MosiPin)),
|
||||||
(("spi", "MISO"), quote!(crate::spi::MisoPin)),
|
(("spi", "MISO"), quote!(crate::spi::MisoPin)),
|
||||||
@ -656,12 +719,17 @@ fn main() {
|
|||||||
(("sdmmc", "D6"), quote!(crate::sdmmc::D6Pin)),
|
(("sdmmc", "D6"), quote!(crate::sdmmc::D6Pin)),
|
||||||
(("sdmmc", "D6"), quote!(crate::sdmmc::D7Pin)),
|
(("sdmmc", "D6"), quote!(crate::sdmmc::D7Pin)),
|
||||||
(("sdmmc", "D8"), quote!(crate::sdmmc::D8Pin)),
|
(("sdmmc", "D8"), quote!(crate::sdmmc::D8Pin)),
|
||||||
(("quadspi", "BK1_IO0"), quote!(crate::qspi::D0Pin)),
|
(("quadspi", "BK1_IO0"), quote!(crate::qspi::BK1D0Pin)),
|
||||||
(("quadspi", "BK1_IO1"), quote!(crate::qspi::D1Pin)),
|
(("quadspi", "BK1_IO1"), quote!(crate::qspi::BK1D1Pin)),
|
||||||
(("quadspi", "BK1_IO2"), quote!(crate::qspi::D2Pin)),
|
(("quadspi", "BK1_IO2"), quote!(crate::qspi::BK1D2Pin)),
|
||||||
(("quadspi", "BK1_IO3"), quote!(crate::qspi::D3Pin)),
|
(("quadspi", "BK1_IO3"), quote!(crate::qspi::BK1D3Pin)),
|
||||||
|
(("quadspi", "BK1_NCS"), quote!(crate::qspi::BK1NSSPin)),
|
||||||
|
(("quadspi", "BK2_IO0"), quote!(crate::qspi::BK2D0Pin)),
|
||||||
|
(("quadspi", "BK2_IO1"), quote!(crate::qspi::BK2D1Pin)),
|
||||||
|
(("quadspi", "BK2_IO2"), quote!(crate::qspi::BK2D2Pin)),
|
||||||
|
(("quadspi", "BK2_IO3"), quote!(crate::qspi::BK2D3Pin)),
|
||||||
|
(("quadspi", "BK2_NCS"), quote!(crate::qspi::BK2NSSPin)),
|
||||||
(("quadspi", "CLK"), quote!(crate::qspi::SckPin)),
|
(("quadspi", "CLK"), quote!(crate::qspi::SckPin)),
|
||||||
(("quadspi", "BK1_NCS"), quote!(crate::qspi::NSSPin)),
|
|
||||||
].into();
|
].into();
|
||||||
|
|
||||||
for p in METADATA.peripherals {
|
for p in METADATA.peripherals {
|
||||||
@ -670,7 +738,16 @@ fn main() {
|
|||||||
let key = (regs.kind, pin.signal);
|
let key = (regs.kind, pin.signal);
|
||||||
if let Some(tr) = signals.get(&key) {
|
if let Some(tr) = signals.get(&key) {
|
||||||
let mut peri = format_ident!("{}", p.name);
|
let mut peri = format_ident!("{}", p.name);
|
||||||
let pin_name = format_ident!("{}", pin.pin);
|
|
||||||
|
let pin_name = {
|
||||||
|
// If we encounter a _C pin but the split_feature for this pin is not enabled, skip it
|
||||||
|
if pin.pin.ends_with("_C") && !split_features.iter().any(|x| x.pin_name_with_c == pin.pin) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
format_ident!("{}", pin.pin)
|
||||||
|
};
|
||||||
|
|
||||||
let af = pin.af.unwrap_or(0);
|
let af = pin.af.unwrap_or(0);
|
||||||
|
|
||||||
// MCO is special
|
// MCO is special
|
||||||
@ -707,7 +784,13 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let peri = format_ident!("{}", p.name);
|
let peri = format_ident!("{}", p.name);
|
||||||
let pin_name = format_ident!("{}", pin.pin);
|
let pin_name = {
|
||||||
|
// If we encounter a _C pin but the split_feature for this pin is not enabled, skip it
|
||||||
|
if pin.pin.ends_with("_C") && !split_features.iter().any(|x| x.pin_name_with_c == pin.pin) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
format_ident!("{}", pin.pin)
|
||||||
|
};
|
||||||
|
|
||||||
// H7 has differential voltage measurements
|
// H7 has differential voltage measurements
|
||||||
let ch: Option<u8> = if pin.signal.starts_with("INP") {
|
let ch: Option<u8> = if pin.signal.starts_with("INP") {
|
||||||
@ -727,6 +810,20 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if regs.kind == "opamp" {
|
||||||
|
if !pin.signal.starts_with("VP") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let peri = format_ident!("{}", p.name);
|
||||||
|
let pin_name = format_ident!("{}", pin.pin);
|
||||||
|
let ch: u8 = pin.signal.strip_prefix("VP").unwrap().parse().unwrap();
|
||||||
|
|
||||||
|
g.extend(quote! {
|
||||||
|
impl_opamp_pin!( #peri, #pin_name, #ch);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// DAC is special
|
// DAC is special
|
||||||
if regs.kind == "dac" {
|
if regs.kind == "dac" {
|
||||||
let peri = format_ident!("{}", p.name);
|
let peri = format_ident!("{}", p.name);
|
||||||
@ -750,6 +847,8 @@ fn main() {
|
|||||||
(("usart", "TX"), quote!(crate::usart::TxDma)),
|
(("usart", "TX"), quote!(crate::usart::TxDma)),
|
||||||
(("lpuart", "RX"), quote!(crate::usart::RxDma)),
|
(("lpuart", "RX"), quote!(crate::usart::RxDma)),
|
||||||
(("lpuart", "TX"), quote!(crate::usart::TxDma)),
|
(("lpuart", "TX"), quote!(crate::usart::TxDma)),
|
||||||
|
(("sai", "A"), quote!(crate::sai::DmaA)),
|
||||||
|
(("sai", "B"), quote!(crate::sai::DmaB)),
|
||||||
(("spi", "RX"), quote!(crate::spi::RxDma)),
|
(("spi", "RX"), quote!(crate::spi::RxDma)),
|
||||||
(("spi", "TX"), quote!(crate::spi::TxDma)),
|
(("spi", "TX"), quote!(crate::spi::TxDma)),
|
||||||
(("i2c", "RX"), quote!(crate::i2c::RxDma)),
|
(("i2c", "RX"), quote!(crate::i2c::RxDma)),
|
||||||
@ -817,6 +916,17 @@ fn main() {
|
|||||||
let mut peripherals_table: Vec<Vec<String>> = Vec::new();
|
let mut peripherals_table: Vec<Vec<String>> = Vec::new();
|
||||||
let mut pins_table: Vec<Vec<String>> = Vec::new();
|
let mut pins_table: Vec<Vec<String>> = Vec::new();
|
||||||
let mut dma_channels_table: Vec<Vec<String>> = Vec::new();
|
let mut dma_channels_table: Vec<Vec<String>> = Vec::new();
|
||||||
|
let mut adc_common_table: Vec<Vec<String>> = Vec::new();
|
||||||
|
|
||||||
|
/*
|
||||||
|
If ADC3_COMMON exists, ADC3 and higher are assigned to it
|
||||||
|
All other ADCs are assigned to ADC_COMMON
|
||||||
|
|
||||||
|
ADC3 and higher are assigned to the adc34 clock in the table
|
||||||
|
The adc3_common cfg directive is added if ADC3_COMMON exists
|
||||||
|
*/
|
||||||
|
let has_adc3 = METADATA.peripherals.iter().find(|p| p.name == "ADC3_COMMON").is_some();
|
||||||
|
let set_adc345 = HashSet::from(["ADC3", "ADC4", "ADC5"]);
|
||||||
|
|
||||||
for m in METADATA
|
for m in METADATA
|
||||||
.memory
|
.memory
|
||||||
@ -844,16 +954,45 @@ fn main() {
|
|||||||
|
|
||||||
for pin_num in 0u32..16 {
|
for pin_num in 0u32..16 {
|
||||||
let pin_name = format!("P{}{}", port_letter, pin_num);
|
let pin_name = format!("P{}{}", port_letter, pin_num);
|
||||||
|
|
||||||
pins_table.push(vec![
|
pins_table.push(vec![
|
||||||
pin_name,
|
pin_name.clone(),
|
||||||
p.name.to_string(),
|
p.name.to_string(),
|
||||||
port_num.to_string(),
|
port_num.to_string(),
|
||||||
pin_num.to_string(),
|
pin_num.to_string(),
|
||||||
format!("EXTI{}", pin_num),
|
format!("EXTI{}", pin_num),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// If we have the split pins, we need to do a little extra work:
|
||||||
|
// Add the "_C" variant to the table. The solution is not optimal, though.
|
||||||
|
// Adding them only when the corresponding GPIOx also appears.
|
||||||
|
// This should avoid unintended side-effects as much as possible.
|
||||||
|
#[cfg(feature = "_split-pins-enabled")]
|
||||||
|
for split_feature in &split_features {
|
||||||
|
if split_feature.pin_name_without_c == pin_name {
|
||||||
|
pins_table.push(vec![
|
||||||
|
split_feature.pin_name_with_c.to_string(),
|
||||||
|
p.name.to_string(),
|
||||||
|
port_num.to_string(),
|
||||||
|
pin_num.to_string(),
|
||||||
|
format!("EXTI{}", pin_num),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if regs.kind == "adc" {
|
||||||
|
let (adc_common, adc_clock) = if set_adc345.contains(p.name) && has_adc3 {
|
||||||
|
("ADC3_COMMON", "adc34")
|
||||||
|
} else {
|
||||||
|
("ADC_COMMON", "adc")
|
||||||
|
};
|
||||||
|
|
||||||
|
let row = vec![p.name.to_string(), adc_common.to_string(), adc_clock.to_string()];
|
||||||
|
adc_common_table.push(row);
|
||||||
|
}
|
||||||
|
|
||||||
for irq in p.interrupts {
|
for irq in p.interrupts {
|
||||||
let row = vec![
|
let row = vec![
|
||||||
p.name.to_string(),
|
p.name.to_string(),
|
||||||
@ -932,6 +1071,7 @@ fn main() {
|
|||||||
make_table(&mut m, "foreach_peripheral", &peripherals_table);
|
make_table(&mut m, "foreach_peripheral", &peripherals_table);
|
||||||
make_table(&mut m, "foreach_pin", &pins_table);
|
make_table(&mut m, "foreach_pin", &pins_table);
|
||||||
make_table(&mut m, "foreach_dma_channel", &dma_channels_table);
|
make_table(&mut m, "foreach_dma_channel", &dma_channels_table);
|
||||||
|
make_table(&mut m, "foreach_adc", &adc_common_table);
|
||||||
|
|
||||||
let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||||
let out_file = out_dir.join("_macros.rs").to_string_lossy().to_string();
|
let out_file = out_dir.join("_macros.rs").to_string_lossy().to_string();
|
||||||
@ -973,13 +1113,24 @@ fn main() {
|
|||||||
println!("cargo:rustc-cfg={}x{}", &chip_name[..9], &chip_name[10..11]);
|
println!("cargo:rustc-cfg={}x{}", &chip_name[..9], &chip_name[10..11]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =======
|
||||||
|
// ADC3_COMMON is present
|
||||||
|
if has_adc3 {
|
||||||
|
println!("cargo:rustc-cfg={}", "adc3_common");
|
||||||
|
}
|
||||||
|
|
||||||
// =======
|
// =======
|
||||||
// Features for targeting groups of chips
|
// Features for targeting groups of chips
|
||||||
|
|
||||||
println!("cargo:rustc-cfg={}", &chip_name[..7]); // stm32f4
|
if &chip_name[..8] == "stm32wba" {
|
||||||
println!("cargo:rustc-cfg={}", &chip_name[..9]); // stm32f429
|
println!("cargo:rustc-cfg={}", &chip_name[..8]); // stm32wba
|
||||||
println!("cargo:rustc-cfg={}x", &chip_name[..8]); // stm32f42x
|
println!("cargo:rustc-cfg={}", &chip_name[..10]); // stm32wba52
|
||||||
println!("cargo:rustc-cfg={}x{}", &chip_name[..7], &chip_name[8..9]); // stm32f4x9
|
} else {
|
||||||
|
println!("cargo:rustc-cfg={}", &chip_name[..7]); // stm32f4
|
||||||
|
println!("cargo:rustc-cfg={}", &chip_name[..9]); // stm32f429
|
||||||
|
println!("cargo:rustc-cfg={}x", &chip_name[..8]); // stm32f42x
|
||||||
|
println!("cargo:rustc-cfg={}x{}", &chip_name[..7], &chip_name[8..9]); // stm32f4x9
|
||||||
|
}
|
||||||
|
|
||||||
// Handle time-driver-XXXX features.
|
// Handle time-driver-XXXX features.
|
||||||
if env::var("CARGO_FEATURE_TIME_DRIVER_ANY").is_ok() {}
|
if env::var("CARGO_FEATURE_TIME_DRIVER_ANY").is_ok() {}
|
||||||
|
@ -1,16 +1,37 @@
|
|||||||
|
use core::future::poll_fn;
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
use core::task::Poll;
|
||||||
|
|
||||||
use embassy_hal_internal::into_ref;
|
use embassy_hal_internal::into_ref;
|
||||||
use embedded_hal_02::blocking::delay::DelayUs;
|
use embedded_hal_02::blocking::delay::DelayUs;
|
||||||
|
|
||||||
use crate::adc::{Adc, AdcPin, Instance, SampleTime};
|
use crate::adc::{Adc, AdcPin, Instance, SampleTime};
|
||||||
use crate::rcc::get_freqs;
|
use crate::rcc::get_freqs;
|
||||||
use crate::time::Hertz;
|
use crate::time::Hertz;
|
||||||
use crate::Peripheral;
|
use crate::{interrupt, Peripheral};
|
||||||
|
|
||||||
pub const VDDA_CALIB_MV: u32 = 3300;
|
pub const VDDA_CALIB_MV: u32 = 3300;
|
||||||
pub const ADC_MAX: u32 = (1 << 12) - 1;
|
pub const ADC_MAX: u32 = (1 << 12) - 1;
|
||||||
// No calibration data for F103, voltage should be 1.2v
|
// No calibration data for F103, voltage should be 1.2v
|
||||||
pub const VREF_INT: u32 = 1200;
|
pub const VREF_INT: u32 = 1200;
|
||||||
|
|
||||||
|
/// Interrupt handler.
|
||||||
|
pub struct InterruptHandler<T: Instance> {
|
||||||
|
_phantom: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
|
unsafe fn on_interrupt() {
|
||||||
|
if T::regs().sr().read().eoc() {
|
||||||
|
T::regs().cr1().modify(|w| w.set_eocie(false));
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
T::state().waker.wake();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Vref;
|
pub struct Vref;
|
||||||
impl<T: Instance> AdcPin<T> for Vref {}
|
impl<T: Instance> AdcPin<T> for Vref {}
|
||||||
impl<T: Instance> super::sealed::AdcPin<T> for Vref {
|
impl<T: Instance> super::sealed::AdcPin<T> for Vref {
|
||||||
@ -95,18 +116,28 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Perform a single conversion.
|
/// Perform a single conversion.
|
||||||
fn convert(&mut self) -> u16 {
|
async fn convert(&mut self) -> u16 {
|
||||||
T::regs().cr2().modify(|reg| {
|
T::regs().cr2().modify(|reg| {
|
||||||
reg.set_adon(true);
|
reg.set_adon(true);
|
||||||
reg.set_swstart(true);
|
reg.set_swstart(true);
|
||||||
});
|
});
|
||||||
while T::regs().cr2().read().swstart() {}
|
T::regs().cr1().modify(|w| w.set_eocie(true));
|
||||||
while !T::regs().sr().read().eoc() {}
|
|
||||||
|
poll_fn(|cx| {
|
||||||
|
T::state().waker.register(cx.waker());
|
||||||
|
|
||||||
|
if !T::regs().cr2().read().swstart() && T::regs().sr().read().eoc() {
|
||||||
|
Poll::Ready(())
|
||||||
|
} else {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
T::regs().dr().read().0 as u16
|
T::regs().dr().read().0 as u16
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
|
pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
|
||||||
Self::set_channel_sample_time(pin.channel(), self.sample_time);
|
Self::set_channel_sample_time(pin.channel(), self.sample_time);
|
||||||
T::regs().cr1().modify(|reg| {
|
T::regs().cr1().modify(|reg| {
|
||||||
reg.set_scan(false);
|
reg.set_scan(false);
|
||||||
@ -123,7 +154,7 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
|
|
||||||
// Configure the channel to sample
|
// Configure the channel to sample
|
||||||
T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel()));
|
T::regs().sqr3().write(|reg| reg.set_sq(0, pin.channel()));
|
||||||
self.convert()
|
self.convert().await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
|
fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
|
||||||
@ -135,3 +166,11 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> Drop for Adc<'d, T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
T::regs().cr2().modify(|reg| reg.set_adon(false));
|
||||||
|
|
||||||
|
T::disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,14 +1,36 @@
|
|||||||
|
use core::future::poll_fn;
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
use core::task::Poll;
|
||||||
|
|
||||||
use embassy_hal_internal::into_ref;
|
use embassy_hal_internal::into_ref;
|
||||||
use embedded_hal_02::blocking::delay::DelayUs;
|
use embedded_hal_02::blocking::delay::DelayUs;
|
||||||
|
|
||||||
use crate::adc::{Adc, AdcPin, Instance, SampleTime};
|
use crate::adc::{Adc, AdcPin, Instance, SampleTime};
|
||||||
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
use crate::time::Hertz;
|
use crate::time::Hertz;
|
||||||
use crate::Peripheral;
|
use crate::{interrupt, Peripheral};
|
||||||
|
|
||||||
pub const VDDA_CALIB_MV: u32 = 3300;
|
pub const VDDA_CALIB_MV: u32 = 3300;
|
||||||
pub const ADC_MAX: u32 = (1 << 12) - 1;
|
pub const ADC_MAX: u32 = (1 << 12) - 1;
|
||||||
pub const VREF_INT: u32 = 1230;
|
pub const VREF_INT: u32 = 1230;
|
||||||
|
|
||||||
|
/// Interrupt handler.
|
||||||
|
pub struct InterruptHandler<T: Instance> {
|
||||||
|
_phantom: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
|
unsafe fn on_interrupt() {
|
||||||
|
if T::regs().isr().read().eoc() {
|
||||||
|
T::regs().ier().modify(|w| w.set_eocie(false));
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
T::state().waker.wake();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Vref;
|
pub struct Vref;
|
||||||
impl<T: Instance> AdcPin<T> for Vref {}
|
impl<T: Instance> AdcPin<T> for Vref {}
|
||||||
impl<T: Instance> super::sealed::AdcPin<T> for Vref {
|
impl<T: Instance> super::sealed::AdcPin<T> for Vref {
|
||||||
@ -17,6 +39,13 @@ impl<T: Instance> super::sealed::AdcPin<T> for Vref {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Vref {
|
||||||
|
/// The value that vref would be if vdda was at 3300mv
|
||||||
|
pub fn value(&self) -> u16 {
|
||||||
|
crate::pac::VREFINTCAL.data().read().value()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Temperature;
|
pub struct Temperature;
|
||||||
impl<T: Instance> AdcPin<T> for Temperature {}
|
impl<T: Instance> AdcPin<T> for Temperature {}
|
||||||
impl<T: Instance> super::sealed::AdcPin<T> for Temperature {
|
impl<T: Instance> super::sealed::AdcPin<T> for Temperature {
|
||||||
@ -26,7 +55,11 @@ impl<T: Instance> super::sealed::AdcPin<T> for Temperature {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> Adc<'d, T> {
|
impl<'d, T: Instance> Adc<'d, T> {
|
||||||
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
|
pub fn new(
|
||||||
|
adc: impl Peripheral<P = T> + 'd,
|
||||||
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
|
delay: &mut impl DelayUs<u32>,
|
||||||
|
) -> Self {
|
||||||
use crate::pac::adc::vals;
|
use crate::pac::adc::vals;
|
||||||
|
|
||||||
into_ref!(adc);
|
into_ref!(adc);
|
||||||
@ -49,12 +82,20 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
|
|
||||||
while T::regs().cr().read().adcal() {}
|
while T::regs().cr().read().adcal() {}
|
||||||
|
|
||||||
|
// Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223)
|
||||||
|
delay.delay_us(1 + (6 * 1_000_000 / Self::freq().0));
|
||||||
|
|
||||||
// Enable the adc
|
// Enable the adc
|
||||||
T::regs().cr().modify(|w| w.set_aden(true));
|
T::regs().cr().modify(|w| w.set_aden(true));
|
||||||
|
|
||||||
// Wait until the adc is ready
|
// Wait until the adc is ready
|
||||||
while !T::regs().isr().read().adrdy() {}
|
while !T::regs().isr().read().adrdy() {}
|
||||||
|
|
||||||
|
T::Interrupt::unpend();
|
||||||
|
unsafe {
|
||||||
|
T::Interrupt::enable();
|
||||||
|
}
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
adc,
|
adc,
|
||||||
sample_time: Default::default(),
|
sample_time: Default::default(),
|
||||||
@ -94,30 +135,61 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Perform a single conversion.
|
/// Perform a single conversion.
|
||||||
fn convert(&mut self) -> u16 {
|
async fn convert(&mut self) -> u16 {
|
||||||
T::regs().isr().write(|_| {});
|
T::regs().isr().write(|_| {});
|
||||||
|
T::regs().ier().modify(|w| w.set_eocie(true));
|
||||||
T::regs().cr().modify(|w| w.set_adstart(true));
|
T::regs().cr().modify(|w| w.set_adstart(true));
|
||||||
|
|
||||||
while !T::regs().isr().read().eoc() && !T::regs().isr().read().eos() {}
|
poll_fn(|cx| {
|
||||||
|
T::state().waker.register(cx.waker());
|
||||||
|
|
||||||
|
if T::regs().isr().read().eoc() {
|
||||||
|
Poll::Ready(())
|
||||||
|
} else {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
T::regs().isr().write(|_| {});
|
T::regs().isr().write(|_| {});
|
||||||
|
|
||||||
T::regs().dr().read().rdata()
|
T::regs().dr().read().rdata()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
|
pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
|
||||||
Self::set_channel_sample_time(pin.channel(), self.sample_time);
|
Self::set_channel_sample_time(pin.channel(), self.sample_time);
|
||||||
|
|
||||||
// Configure the channel to sample
|
// Configure the channel to sample
|
||||||
T::regs().sqr1().write(|w| w.set_sq(0, pin.channel()));
|
T::regs().sqr1().write(|w| w.set_sq(0, pin.channel()));
|
||||||
self.convert()
|
self.convert().await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
|
fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
|
||||||
let sample_time = sample_time.into();
|
let sample_time = sample_time.into();
|
||||||
if ch <= 9 {
|
if ch <= 9 {
|
||||||
T::regs().smpr2().modify(|reg| reg.set_smp(ch as _, sample_time));
|
T::regs().smpr1().modify(|reg| reg.set_smp(ch as _, sample_time));
|
||||||
} else {
|
} else {
|
||||||
T::regs().smpr1().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
|
T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> Drop for Adc<'d, T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
use crate::pac::adc::vals;
|
||||||
|
|
||||||
|
T::regs().cr().modify(|w| w.set_adstp(true));
|
||||||
|
|
||||||
|
while T::regs().cr().read().adstp() {}
|
||||||
|
|
||||||
|
T::regs().cr().modify(|w| w.set_addis(true));
|
||||||
|
|
||||||
|
while T::regs().cr().read().aden() {}
|
||||||
|
|
||||||
|
// Disable the adc regulator
|
||||||
|
T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE));
|
||||||
|
T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::DISABLED));
|
||||||
|
|
||||||
|
T::disable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -31,15 +31,41 @@ pub struct Adc<'d, T: Instance> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) mod sealed {
|
pub(crate) mod sealed {
|
||||||
pub trait Instance {
|
#[cfg(any(adc_f1, adc_f3, adc_v1))]
|
||||||
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
|
|
||||||
|
#[cfg(any(adc_f1, adc_f3, adc_v1))]
|
||||||
|
pub struct State {
|
||||||
|
pub waker: AtomicWaker,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(adc_f1, adc_f3, adc_v1))]
|
||||||
|
impl State {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
waker: AtomicWaker::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait InterruptableInstance {
|
||||||
|
type Interrupt: crate::interrupt::typelevel::Interrupt;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Instance: InterruptableInstance {
|
||||||
fn regs() -> crate::pac::adc::Adc;
|
fn regs() -> crate::pac::adc::Adc;
|
||||||
#[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))]
|
#[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))]
|
||||||
fn common_regs() -> crate::pac::adccommon::AdcCommon;
|
fn common_regs() -> crate::pac::adccommon::AdcCommon;
|
||||||
#[cfg(adc_f3)]
|
#[cfg(adc_f3)]
|
||||||
fn frequency() -> crate::time::Hertz;
|
fn frequency() -> crate::time::Hertz;
|
||||||
|
#[cfg(any(adc_f1, adc_f3, adc_v1))]
|
||||||
|
fn state() -> &'static State;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait AdcPin<T: Instance> {
|
pub trait AdcPin<T: Instance> {
|
||||||
|
#[cfg(any(adc_v1, adc_v2))]
|
||||||
|
fn set_as_analog(&mut self) {}
|
||||||
|
|
||||||
fn channel(&self) -> u8;
|
fn channel(&self) -> u8;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,99 +82,37 @@ pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc:
|
|||||||
pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {}
|
pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {}
|
||||||
pub trait InternalChannel<T>: sealed::InternalChannel<T> {}
|
pub trait InternalChannel<T>: sealed::InternalChannel<T> {}
|
||||||
|
|
||||||
#[cfg(not(any(stm32h7, adc_f3, adc_v4)))]
|
foreach_adc!(
|
||||||
foreach_peripheral!(
|
($inst:ident, $common_inst:ident, $clock:ident) => {
|
||||||
(adc, $inst:ident) => {
|
|
||||||
impl crate::adc::sealed::Instance for peripherals::$inst {
|
impl crate::adc::sealed::Instance for peripherals::$inst {
|
||||||
fn regs() -> crate::pac::adc::Adc {
|
fn regs() -> crate::pac::adc::Adc {
|
||||||
crate::pac::$inst
|
crate::pac::$inst
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))]
|
#[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))]
|
||||||
fn common_regs() -> crate::pac::adccommon::AdcCommon {
|
fn common_regs() -> crate::pac::adccommon::AdcCommon {
|
||||||
foreach_peripheral!{
|
return crate::pac::$common_inst
|
||||||
(adccommon, $common_inst:ident) => {
|
|
||||||
return crate::pac::$common_inst
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl crate::adc::Instance for peripherals::$inst {}
|
|
||||||
};
|
|
||||||
);
|
|
||||||
|
|
||||||
#[cfg(any(stm32h7, adc_f3, adc_v4))]
|
|
||||||
foreach_peripheral!(
|
|
||||||
(adc, ADC3) => {
|
|
||||||
#[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))]
|
|
||||||
impl crate::adc::sealed::Instance for peripherals::ADC3 {
|
|
||||||
fn regs() -> crate::pac::adc::Adc {
|
|
||||||
crate::pac::ADC3
|
|
||||||
}
|
|
||||||
#[cfg(all(not(adc_f1), not(adc_v1)))]
|
|
||||||
fn common_regs() -> crate::pac::adccommon::AdcCommon {
|
|
||||||
foreach_peripheral!{
|
|
||||||
(adccommon, ADC3_COMMON) => {
|
|
||||||
return crate::pac::ADC3_COMMON
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(adc_f3)]
|
#[cfg(adc_f3)]
|
||||||
fn frequency() -> crate::time::Hertz {
|
fn frequency() -> crate::time::Hertz {
|
||||||
unsafe { crate::rcc::get_freqs() }.adc34.unwrap()
|
unsafe { crate::rcc::get_freqs() }.$clock.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(adc_f1, adc_f3, adc_v1))]
|
||||||
|
fn state() -> &'static sealed::State {
|
||||||
|
static STATE: sealed::State = sealed::State::new();
|
||||||
|
&STATE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))]
|
foreach_interrupt!(
|
||||||
impl crate::adc::Instance for peripherals::ADC3 {}
|
($inst,adc,ADC,GLOBAL,$irq:ident) => {
|
||||||
};
|
impl sealed::InterruptableInstance for peripherals::$inst {
|
||||||
(adc, ADC4) => {
|
type Interrupt = crate::interrupt::typelevel::$irq;
|
||||||
#[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))]
|
|
||||||
impl crate::adc::sealed::Instance for peripherals::ADC4 {
|
|
||||||
fn regs() -> crate::pac::adc::Adc {
|
|
||||||
crate::pac::ADC4
|
|
||||||
}
|
|
||||||
#[cfg(not(any(adc_f1, adc_v1)))]
|
|
||||||
fn common_regs() -> crate::pac::adccommon::AdcCommon {
|
|
||||||
foreach_peripheral!{
|
|
||||||
(adccommon, ADC3_COMMON) => {
|
|
||||||
return crate::pac::ADC3_COMMON
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
);
|
||||||
#[cfg(adc_f3)]
|
|
||||||
fn frequency() -> crate::time::Hertz {
|
|
||||||
unsafe { crate::rcc::get_freqs() }.adc34.unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(any(stm32g4x1, stm32g4x2, stm32g4x3, stm32g4x4)))]
|
|
||||||
impl crate::adc::Instance for peripherals::ADC4 {}
|
|
||||||
};
|
|
||||||
(adc, ADC5) => {
|
|
||||||
|
|
||||||
};
|
|
||||||
(adc, $inst:ident) => {
|
|
||||||
impl crate::adc::sealed::Instance for peripherals::$inst {
|
|
||||||
fn regs() -> crate::pac::adc::Adc {
|
|
||||||
crate::pac::$inst
|
|
||||||
}
|
|
||||||
#[cfg(not(any(adc_f1, adc_v1)))]
|
|
||||||
fn common_regs() -> crate::pac::adccommon::AdcCommon {
|
|
||||||
foreach_peripheral!{
|
|
||||||
(adccommon, ADC_COMMON) => {
|
|
||||||
return crate::pac::ADC_COMMON
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(adc_f3)]
|
|
||||||
fn frequency() -> crate::time::Hertz {
|
|
||||||
unsafe { crate::rcc::get_freqs() }.adc.unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl crate::adc::Instance for peripherals::$inst {}
|
impl crate::adc::Instance for peripherals::$inst {}
|
||||||
};
|
};
|
||||||
@ -159,6 +123,11 @@ macro_rules! impl_adc_pin {
|
|||||||
impl crate::adc::AdcPin<peripherals::$inst> for crate::peripherals::$pin {}
|
impl crate::adc::AdcPin<peripherals::$inst> for crate::peripherals::$pin {}
|
||||||
|
|
||||||
impl crate::adc::sealed::AdcPin<peripherals::$inst> for crate::peripherals::$pin {
|
impl crate::adc::sealed::AdcPin<peripherals::$inst> for crate::peripherals::$pin {
|
||||||
|
#[cfg(any(adc_v1, adc_v2))]
|
||||||
|
fn set_as_analog(&mut self) {
|
||||||
|
<Self as crate::gpio::sealed::Pin>::set_as_analog(self);
|
||||||
|
}
|
||||||
|
|
||||||
fn channel(&self) -> u8 {
|
fn channel(&self) -> u8 {
|
||||||
$ch
|
$ch
|
||||||
}
|
}
|
||||||
|
@ -1,39 +1,65 @@
|
|||||||
|
use core::future::poll_fn;
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
use core::task::Poll;
|
||||||
|
|
||||||
use embassy_hal_internal::into_ref;
|
use embassy_hal_internal::into_ref;
|
||||||
use embedded_hal_02::blocking::delay::DelayUs;
|
use embedded_hal_02::blocking::delay::DelayUs;
|
||||||
|
|
||||||
use crate::adc::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime};
|
use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
|
||||||
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
use crate::peripherals::ADC;
|
use crate::peripherals::ADC;
|
||||||
use crate::Peripheral;
|
use crate::{interrupt, Peripheral};
|
||||||
|
|
||||||
pub const VDDA_CALIB_MV: u32 = 3300;
|
pub const VDDA_CALIB_MV: u32 = 3300;
|
||||||
pub const VREF_INT: u32 = 1230;
|
pub const VREF_INT: u32 = 1230;
|
||||||
|
|
||||||
|
/// Interrupt handler.
|
||||||
|
pub struct InterruptHandler<T: Instance> {
|
||||||
|
_phantom: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||||
|
unsafe fn on_interrupt() {
|
||||||
|
if T::regs().isr().read().eoc() {
|
||||||
|
T::regs().ier().modify(|w| w.set_eocie(false));
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
T::state().waker.wake();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Vbat;
|
pub struct Vbat;
|
||||||
impl InternalChannel<ADC> for Vbat {}
|
impl AdcPin<ADC> for Vbat {}
|
||||||
impl super::sealed::InternalChannel<ADC> for Vbat {
|
impl super::sealed::AdcPin<ADC> for Vbat {
|
||||||
fn channel(&self) -> u8 {
|
fn channel(&self) -> u8 {
|
||||||
18
|
18
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Vref;
|
pub struct Vref;
|
||||||
impl InternalChannel<ADC> for Vref {}
|
impl AdcPin<ADC> for Vref {}
|
||||||
impl super::sealed::InternalChannel<ADC> for Vref {
|
impl super::sealed::AdcPin<ADC> for Vref {
|
||||||
fn channel(&self) -> u8 {
|
fn channel(&self) -> u8 {
|
||||||
17
|
17
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Temperature;
|
pub struct Temperature;
|
||||||
impl InternalChannel<ADC> for Temperature {}
|
impl AdcPin<ADC> for Temperature {}
|
||||||
impl super::sealed::InternalChannel<ADC> for Temperature {
|
impl super::sealed::AdcPin<ADC> for Temperature {
|
||||||
fn channel(&self) -> u8 {
|
fn channel(&self) -> u8 {
|
||||||
16
|
16
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> Adc<'d, T> {
|
impl<'d, T: Instance> Adc<'d, T> {
|
||||||
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
|
pub fn new(
|
||||||
|
adc: impl Peripheral<P = T> + 'd,
|
||||||
|
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||||
|
delay: &mut impl DelayUs<u32>,
|
||||||
|
) -> Self {
|
||||||
into_ref!(adc);
|
into_ref!(adc);
|
||||||
T::enable();
|
T::enable();
|
||||||
T::reset();
|
T::reset();
|
||||||
@ -44,12 +70,32 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
// tstab = 14 * 1/fadc
|
// tstab = 14 * 1/fadc
|
||||||
delay.delay_us(1);
|
delay.delay_us(1);
|
||||||
|
|
||||||
let s = Self {
|
// A.7.1 ADC calibration code example
|
||||||
|
T::regs().cfgr1().modify(|reg| reg.set_dmaen(false));
|
||||||
|
T::regs().cr().modify(|reg| reg.set_adcal(true));
|
||||||
|
while T::regs().cr().read().adcal() {}
|
||||||
|
|
||||||
|
// A.7.2 ADC enable sequence code example
|
||||||
|
if T::regs().isr().read().adrdy() {
|
||||||
|
T::regs().isr().modify(|reg| reg.set_adrdy(true));
|
||||||
|
}
|
||||||
|
T::regs().cr().modify(|reg| reg.set_aden(true));
|
||||||
|
while !T::regs().isr().read().adrdy() {
|
||||||
|
// ES0233, 2.4.3 ADEN bit cannot be set immediately after the ADC calibration
|
||||||
|
// Workaround: When the ADC calibration is complete (ADCAL = 0), keep setting the
|
||||||
|
// ADEN bit until the ADRDY flag goes high.
|
||||||
|
T::regs().cr().modify(|reg| reg.set_aden(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
T::Interrupt::unpend();
|
||||||
|
unsafe {
|
||||||
|
T::Interrupt::enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
adc,
|
adc,
|
||||||
sample_time: Default::default(),
|
sample_time: Default::default(),
|
||||||
};
|
}
|
||||||
s.calibrate();
|
|
||||||
s
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable_vbat(&self, _delay: &mut impl DelayUs<u32>) -> Vbat {
|
pub fn enable_vbat(&self, _delay: &mut impl DelayUs<u32>) -> Vbat {
|
||||||
@ -80,21 +126,6 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
Temperature
|
Temperature
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calibrate(&self) {
|
|
||||||
// A.7.1 ADC calibration code example
|
|
||||||
if T::regs().cr().read().aden() {
|
|
||||||
T::regs().cr().modify(|reg| reg.set_addis(true));
|
|
||||||
}
|
|
||||||
while T::regs().cr().read().aden() {
|
|
||||||
// spin
|
|
||||||
}
|
|
||||||
T::regs().cfgr1().modify(|reg| reg.set_dmaen(false));
|
|
||||||
T::regs().cr().modify(|reg| reg.set_adcal(true));
|
|
||||||
while T::regs().cr().read().adcal() {
|
|
||||||
// spin
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_sample_time(&mut self, sample_time: SampleTime) {
|
pub fn set_sample_time(&mut self, sample_time: SampleTime) {
|
||||||
self.sample_time = sample_time;
|
self.sample_time = sample_time;
|
||||||
}
|
}
|
||||||
@ -103,57 +134,50 @@ impl<'d, T: Instance> Adc<'d, T> {
|
|||||||
T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
|
T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read<P>(&mut self, pin: &mut P) -> u16
|
pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
|
||||||
where
|
|
||||||
P: AdcPin<T> + crate::gpio::sealed::Pin,
|
|
||||||
{
|
|
||||||
let channel = pin.channel();
|
let channel = pin.channel();
|
||||||
pin.set_as_analog();
|
pin.set_as_analog();
|
||||||
self.read_channel(channel)
|
|
||||||
|
// A.7.5 Single conversion sequence code example - Software trigger
|
||||||
|
T::regs().chselr().write(|reg| reg.set_chselx(channel as usize, true));
|
||||||
|
|
||||||
|
self.convert().await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
|
async fn convert(&mut self) -> u16 {
|
||||||
let channel = channel.channel();
|
|
||||||
self.read_channel(channel)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_channel(&mut self, channel: u8) -> u16 {
|
|
||||||
// A.7.2 ADC enable sequence code example
|
|
||||||
if T::regs().isr().read().adrdy() {
|
|
||||||
T::regs().isr().modify(|reg| reg.set_adrdy(true));
|
|
||||||
}
|
|
||||||
T::regs().cr().modify(|reg| reg.set_aden(true));
|
|
||||||
while !T::regs().isr().read().adrdy() {
|
|
||||||
// ES0233, 2.4.3 ADEN bit cannot be set immediately after the ADC calibration
|
|
||||||
// Workaround: When the ADC calibration is complete (ADCAL = 0), keep setting the
|
|
||||||
// ADEN bit until the ADRDY flag goes high.
|
|
||||||
T::regs().cr().modify(|reg| reg.set_aden(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
T::regs().isr().modify(|reg| {
|
T::regs().isr().modify(|reg| {
|
||||||
reg.set_eoc(true);
|
reg.set_eoc(true);
|
||||||
reg.set_eosmp(true);
|
reg.set_eosmp(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
// A.7.5 Single conversion sequence code example - Software trigger
|
|
||||||
T::regs().chselr().write(|reg| reg.set_chselx(channel as usize, true));
|
|
||||||
T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.into()));
|
T::regs().smpr().modify(|reg| reg.set_smp(self.sample_time.into()));
|
||||||
|
T::regs().ier().modify(|w| w.set_eocie(true));
|
||||||
T::regs().cr().modify(|reg| reg.set_adstart(true));
|
T::regs().cr().modify(|reg| reg.set_adstart(true));
|
||||||
while !T::regs().isr().read().eoc() {
|
|
||||||
// spin
|
|
||||||
}
|
|
||||||
let value = T::regs().dr().read().0 as u16;
|
|
||||||
|
|
||||||
// A.7.3 ADC disable code example
|
poll_fn(|cx| {
|
||||||
T::regs().cr().modify(|reg| reg.set_adstp(true));
|
T::state().waker.register(cx.waker());
|
||||||
while T::regs().cr().read().adstp() {
|
|
||||||
// spin
|
|
||||||
}
|
|
||||||
T::regs().cr().modify(|reg| reg.set_addis(true));
|
|
||||||
while T::regs().cr().read().aden() {
|
|
||||||
// spin
|
|
||||||
}
|
|
||||||
|
|
||||||
value
|
if T::regs().isr().read().eoc() {
|
||||||
|
Poll::Ready(())
|
||||||
|
} else {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
T::regs().dr().read().data()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> Drop for Adc<'d, T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
// A.7.3 ADC disable code example
|
||||||
|
T::regs().cr().modify(|reg| reg.set_adstp(true));
|
||||||
|
while T::regs().cr().read().adstp() {}
|
||||||
|
|
||||||
|
T::regs().cr().modify(|reg| reg.set_addis(true));
|
||||||
|
while T::regs().cr().read().aden() {}
|
||||||
|
|
||||||
|
T::disable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use embassy_hal_internal::into_ref;
|
use embassy_hal_internal::into_ref;
|
||||||
use embedded_hal_02::blocking::delay::DelayUs;
|
use embedded_hal_02::blocking::delay::DelayUs;
|
||||||
|
|
||||||
use super::InternalChannel;
|
|
||||||
use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
|
use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
|
||||||
use crate::peripherals::ADC1;
|
use crate::peripherals::ADC1;
|
||||||
use crate::time::Hertz;
|
use crate::time::Hertz;
|
||||||
@ -16,8 +15,8 @@ pub const VREF_CALIB_MV: u32 = 3300;
|
|||||||
pub const ADC_POWERUP_TIME_US: u32 = 3;
|
pub const ADC_POWERUP_TIME_US: u32 = 3;
|
||||||
|
|
||||||
pub struct VrefInt;
|
pub struct VrefInt;
|
||||||
impl InternalChannel<ADC1> for VrefInt {}
|
impl AdcPin<ADC1> for VrefInt {}
|
||||||
impl super::sealed::InternalChannel<ADC1> for VrefInt {
|
impl super::sealed::AdcPin<ADC1> for VrefInt {
|
||||||
fn channel(&self) -> u8 {
|
fn channel(&self) -> u8 {
|
||||||
17
|
17
|
||||||
}
|
}
|
||||||
@ -31,8 +30,8 @@ impl VrefInt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Temperature;
|
pub struct Temperature;
|
||||||
impl InternalChannel<ADC1> for Temperature {}
|
impl AdcPin<ADC1> for Temperature {}
|
||||||
impl super::sealed::InternalChannel<ADC1> for Temperature {
|
impl super::sealed::AdcPin<ADC1> for Temperature {
|
||||||
fn channel(&self) -> u8 {
|
fn channel(&self) -> u8 {
|
||||||
cfg_if::cfg_if! {
|
cfg_if::cfg_if! {
|
||||||
if #[cfg(any(stm32f40, stm32f41))] {
|
if #[cfg(any(stm32f40, stm32f41))] {
|
||||||
@ -52,8 +51,8 @@ impl Temperature {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Vbat;
|
pub struct Vbat;
|
||||||
impl InternalChannel<ADC1> for Vbat {}
|
impl AdcPin<ADC1> for Vbat {}
|
||||||
impl super::sealed::InternalChannel<ADC1> for Vbat {
|
impl super::sealed::AdcPin<ADC1> for Vbat {
|
||||||
fn channel(&self) -> u8 {
|
fn channel(&self) -> u8 {
|
||||||
18
|
18
|
||||||
}
|
}
|
||||||
@ -102,7 +101,7 @@ where
|
|||||||
let presc = Prescaler::from_pclk2(T::frequency());
|
let presc = Prescaler::from_pclk2(T::frequency());
|
||||||
T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre()));
|
T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre()));
|
||||||
T::regs().cr2().modify(|reg| {
|
T::regs().cr2().modify(|reg| {
|
||||||
reg.set_adon(crate::pac::adc::vals::Adon::ENABLED);
|
reg.set_adon(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
delay.delay_us(ADC_POWERUP_TIME_US);
|
delay.delay_us(ADC_POWERUP_TIME_US);
|
||||||
@ -125,7 +124,7 @@ where
|
|||||||
/// [Adc::read_internal()] to perform conversion.
|
/// [Adc::read_internal()] to perform conversion.
|
||||||
pub fn enable_vrefint(&self) -> VrefInt {
|
pub fn enable_vrefint(&self) -> VrefInt {
|
||||||
T::common_regs().ccr().modify(|reg| {
|
T::common_regs().ccr().modify(|reg| {
|
||||||
reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED);
|
reg.set_tsvrefe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
VrefInt {}
|
VrefInt {}
|
||||||
@ -138,7 +137,7 @@ where
|
|||||||
/// temperature sensor will return vbat value.
|
/// temperature sensor will return vbat value.
|
||||||
pub fn enable_temperature(&self) -> Temperature {
|
pub fn enable_temperature(&self) -> Temperature {
|
||||||
T::common_regs().ccr().modify(|reg| {
|
T::common_regs().ccr().modify(|reg| {
|
||||||
reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED);
|
reg.set_tsvrefe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
Temperature {}
|
Temperature {}
|
||||||
@ -148,7 +147,7 @@ where
|
|||||||
/// [Adc::read_internal()] to perform conversion.
|
/// [Adc::read_internal()] to perform conversion.
|
||||||
pub fn enable_vbat(&self) -> Vbat {
|
pub fn enable_vbat(&self) -> Vbat {
|
||||||
T::common_regs().ccr().modify(|reg| {
|
T::common_regs().ccr().modify(|reg| {
|
||||||
reg.set_vbate(crate::pac::adccommon::vals::Vbate::ENABLED);
|
reg.set_vbate(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
Vbat {}
|
Vbat {}
|
||||||
@ -176,22 +175,11 @@ where
|
|||||||
T::regs().dr().read().0 as u16
|
T::regs().dr().read().0 as u16
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read<P>(&mut self, pin: &mut P) -> u16
|
pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
|
||||||
where
|
|
||||||
P: AdcPin<T>,
|
|
||||||
P: crate::gpio::sealed::Pin,
|
|
||||||
{
|
|
||||||
pin.set_as_analog();
|
pin.set_as_analog();
|
||||||
|
|
||||||
self.read_channel(pin.channel())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_internal(&mut self, channel: &mut impl InternalChannel<T>) -> u16 {
|
|
||||||
self.read_channel(channel.channel())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_channel(&mut self, channel: u8) -> u16 {
|
|
||||||
// Configure ADC
|
// Configure ADC
|
||||||
|
let channel = pin.channel();
|
||||||
|
|
||||||
// Select channel
|
// Select channel
|
||||||
T::regs().sqr3().write(|reg| reg.set_sq(0, channel));
|
T::regs().sqr3().write(|reg| reg.set_sq(0, channel));
|
||||||
@ -199,9 +187,7 @@ where
|
|||||||
// Configure channel
|
// Configure channel
|
||||||
Self::set_channel_sample_time(channel, self.sample_time);
|
Self::set_channel_sample_time(channel, self.sample_time);
|
||||||
|
|
||||||
let val = self.convert();
|
self.convert()
|
||||||
|
|
||||||
val
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
|
fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
|
||||||
@ -216,6 +202,10 @@ where
|
|||||||
|
|
||||||
impl<'d, T: Instance> Drop for Adc<'d, T> {
|
impl<'d, T: Instance> Drop for Adc<'d, T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
T::regs().cr2().modify(|reg| {
|
||||||
|
reg.set_adon(false);
|
||||||
|
});
|
||||||
|
|
||||||
T::disable();
|
T::disable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
|||||||
|
|
||||||
#[cfg(any(eth_v1b, eth_v1c))]
|
#[cfg(any(eth_v1b, eth_v1c))]
|
||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
RCC.apb2enr().modify(|w| w.set_syscfgen(true));
|
|
||||||
RCC.ahb1enr().modify(|w| {
|
RCC.ahb1enr().modify(|w| {
|
||||||
w.set_ethen(true);
|
w.set_ethen(true);
|
||||||
w.set_ethtxen(true);
|
w.set_ethtxen(true);
|
||||||
|
@ -34,8 +34,6 @@ impl interrupt::typelevel::Handler<interrupt::typelevel::ETH> for InterruptHandl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const MTU: usize = 1514; // 14 Ethernet header + 1500 IP packet
|
|
||||||
|
|
||||||
pub struct Ethernet<'d, T: Instance, P: PHY> {
|
pub struct Ethernet<'d, T: Instance, P: PHY> {
|
||||||
_peri: PeripheralRef<'d, T>,
|
_peri: PeripheralRef<'d, T>,
|
||||||
pub(crate) tx: TDesRing<'d>,
|
pub(crate) tx: TDesRing<'d>,
|
||||||
@ -80,7 +78,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
|||||||
// Enable the necessary Clocks
|
// Enable the necessary Clocks
|
||||||
#[cfg(not(rcc_h5))]
|
#[cfg(not(rcc_h5))]
|
||||||
critical_section::with(|_| {
|
critical_section::with(|_| {
|
||||||
crate::pac::RCC.apb4enr().modify(|w| w.set_syscfgen(true));
|
|
||||||
crate::pac::RCC.ahb1enr().modify(|w| {
|
crate::pac::RCC.ahb1enr().modify(|w| {
|
||||||
w.set_eth1macen(true);
|
w.set_eth1macen(true);
|
||||||
w.set_eth1txen(true);
|
w.set_eth1txen(true);
|
||||||
@ -102,9 +99,9 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// RMII
|
// RMII
|
||||||
crate::pac::SBS
|
crate::pac::SYSCFG
|
||||||
.pmcr()
|
.pmcr()
|
||||||
.modify(|w| w.set_eth_sel_phy(crate::pac::sbs::vals::EthSelPhy::B_0X4));
|
.modify(|w| w.set_eth_sel_phy(crate::pac::syscfg::vals::EthSelPhy::B_0X4));
|
||||||
});
|
});
|
||||||
|
|
||||||
config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
|
config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
|
||||||
@ -164,7 +161,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
|||||||
dma.dmactx_cr().modify(|w| w.set_txpbl(1)); // 32 ?
|
dma.dmactx_cr().modify(|w| w.set_txpbl(1)); // 32 ?
|
||||||
dma.dmacrx_cr().modify(|w| {
|
dma.dmacrx_cr().modify(|w| {
|
||||||
w.set_rxpbl(1); // 32 ?
|
w.set_rxpbl(1); // 32 ?
|
||||||
w.set_rbsz(MTU as u16);
|
w.set_rbsz(RX_BUFFER_SIZE as u16);
|
||||||
});
|
});
|
||||||
|
|
||||||
// NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called
|
// NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called
|
||||||
|
@ -6,7 +6,7 @@ use core::task::{Context, Poll};
|
|||||||
use embassy_hal_internal::impl_peripheral;
|
use embassy_hal_internal::impl_peripheral;
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
|
|
||||||
use crate::gpio::{AnyPin, Input, Pin as GpioPin};
|
use crate::gpio::{AnyPin, Input, Level, Pin as GpioPin};
|
||||||
use crate::pac::exti::regs::Lines;
|
use crate::pac::exti::regs::Lines;
|
||||||
use crate::pac::EXTI;
|
use crate::pac::EXTI;
|
||||||
use crate::{interrupt, pac, peripherals, Peripheral};
|
use crate::{interrupt, pac, peripherals, Peripheral};
|
||||||
@ -39,6 +39,9 @@ fn exticr_regs() -> pac::afio::Afio {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn on_irq() {
|
pub unsafe fn on_irq() {
|
||||||
|
#[cfg(feature = "low-power")]
|
||||||
|
crate::low_power::on_wakeup_irq();
|
||||||
|
|
||||||
#[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))]
|
#[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))]
|
||||||
let bits = EXTI.pr(0).read().0;
|
let bits = EXTI.pr(0).read().0;
|
||||||
#[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))]
|
#[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))]
|
||||||
@ -98,6 +101,10 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> {
|
|||||||
self.pin.is_low()
|
self.pin.is_low()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_level(&self) -> Level {
|
||||||
|
self.pin.get_level()
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn wait_for_high<'a>(&'a mut self) {
|
pub async fn wait_for_high<'a>(&'a mut self) {
|
||||||
let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false);
|
let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false);
|
||||||
if self.is_high() {
|
if self.is_high() {
|
||||||
@ -364,9 +371,4 @@ pub(crate) unsafe fn init() {
|
|||||||
use crate::interrupt::typelevel::Interrupt;
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
|
|
||||||
foreach_exti_irq!(enable_irq);
|
foreach_exti_irq!(enable_irq);
|
||||||
|
|
||||||
#[cfg(not(any(rcc_wb, rcc_wl5, rcc_wle, stm32f1, exti_h5, exti_h50)))]
|
|
||||||
<crate::peripherals::SYSCFG as crate::rcc::sealed::RccPeripheral>::enable();
|
|
||||||
#[cfg(stm32f1)]
|
|
||||||
<crate::peripherals::AFIO as crate::rcc::sealed::RccPeripheral>::enable();
|
|
||||||
}
|
}
|
||||||
|
@ -758,6 +758,9 @@ foreach_pin!(
|
|||||||
);
|
);
|
||||||
|
|
||||||
pub(crate) unsafe fn init() {
|
pub(crate) unsafe fn init() {
|
||||||
|
#[cfg(afio)]
|
||||||
|
<crate::peripherals::AFIO as crate::rcc::sealed::RccPeripheral>::enable();
|
||||||
|
|
||||||
crate::_generated::init_gpio();
|
crate::_generated::init_gpio();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,12 +78,76 @@ pub(crate) mod sealed {
|
|||||||
pub trait Instance: RccPeripheral {
|
pub trait Instance: RccPeripheral {
|
||||||
fn regs() -> crate::pac::hrtim::Hrtim;
|
fn regs() -> crate::pac::hrtim::Hrtim;
|
||||||
|
|
||||||
fn set_master_frequency(frequency: Hertz);
|
fn set_master_frequency(frequency: Hertz) {
|
||||||
|
let f = frequency.0;
|
||||||
|
#[cfg(not(stm32f334))]
|
||||||
|
let timer_f = Self::frequency().0;
|
||||||
|
#[cfg(stm32f334)]
|
||||||
|
let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0;
|
||||||
|
|
||||||
fn set_channel_frequency(channnel: usize, frequency: Hertz);
|
let psc_min = (timer_f / f) / (u16::MAX as u32 / 32);
|
||||||
|
let psc = if Self::regs().isr().read().dllrdy() {
|
||||||
|
Prescaler::compute_min_high_res(psc_min)
|
||||||
|
} else {
|
||||||
|
Prescaler::compute_min_low_res(psc_min)
|
||||||
|
};
|
||||||
|
|
||||||
|
let timer_f = 32 * (timer_f / psc as u32);
|
||||||
|
let per: u16 = (timer_f / f) as u16;
|
||||||
|
|
||||||
|
let regs = Self::regs();
|
||||||
|
|
||||||
|
regs.mcr().modify(|w| w.set_ckpsc(psc.into()));
|
||||||
|
regs.mper().modify(|w| w.set_mper(per));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_channel_frequency(channel: usize, frequency: Hertz) {
|
||||||
|
let f = frequency.0;
|
||||||
|
#[cfg(not(stm32f334))]
|
||||||
|
let timer_f = Self::frequency().0;
|
||||||
|
#[cfg(stm32f334)]
|
||||||
|
let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0;
|
||||||
|
|
||||||
|
let psc_min = (timer_f / f) / (u16::MAX as u32 / 32);
|
||||||
|
let psc = if Self::regs().isr().read().dllrdy() {
|
||||||
|
Prescaler::compute_min_high_res(psc_min)
|
||||||
|
} else {
|
||||||
|
Prescaler::compute_min_low_res(psc_min)
|
||||||
|
};
|
||||||
|
|
||||||
|
let timer_f = 32 * (timer_f / psc as u32);
|
||||||
|
let per: u16 = (timer_f / f) as u16;
|
||||||
|
|
||||||
|
let regs = Self::regs();
|
||||||
|
|
||||||
|
regs.tim(channel).cr().modify(|w| w.set_ckpsc(psc.into()));
|
||||||
|
regs.tim(channel).per().modify(|w| w.set_per(per));
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the dead time as a proportion of max_duty
|
/// Set the dead time as a proportion of max_duty
|
||||||
fn set_channel_dead_time(channnel: usize, dead_time: u16);
|
|
||||||
|
fn set_channel_dead_time(channel: usize, dead_time: u16) {
|
||||||
|
let regs = Self::regs();
|
||||||
|
|
||||||
|
let channel_psc: Prescaler = regs.tim(channel).cr().read().ckpsc().into();
|
||||||
|
|
||||||
|
// The dead-time base clock runs 4 times slower than the hrtim base clock
|
||||||
|
// u9::MAX = 511
|
||||||
|
let psc_min = (channel_psc as u32 * dead_time as u32) / (4 * 511);
|
||||||
|
let psc = if Self::regs().isr().read().dllrdy() {
|
||||||
|
Prescaler::compute_min_high_res(psc_min)
|
||||||
|
} else {
|
||||||
|
Prescaler::compute_min_low_res(psc_min)
|
||||||
|
};
|
||||||
|
|
||||||
|
let dt_val = (psc as u32 * dead_time as u32) / (4 * channel_psc as u32);
|
||||||
|
|
||||||
|
regs.tim(channel).dt().modify(|w| {
|
||||||
|
w.set_dtprsc(psc.into());
|
||||||
|
w.set_dtf(dt_val as u16);
|
||||||
|
w.set_dtr(dt_val as u16);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// fn enable_outputs(enable: bool);
|
// fn enable_outputs(enable: bool);
|
||||||
//
|
//
|
||||||
@ -99,84 +163,6 @@ foreach_interrupt! {
|
|||||||
fn regs() -> crate::pac::hrtim::Hrtim {
|
fn regs() -> crate::pac::hrtim::Hrtim {
|
||||||
crate::pac::$inst
|
crate::pac::$inst
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_master_frequency(frequency: Hertz) {
|
|
||||||
use crate::rcc::sealed::RccPeripheral;
|
|
||||||
|
|
||||||
let f = frequency.0;
|
|
||||||
#[cfg(not(stm32f334))]
|
|
||||||
let timer_f = Self::frequency().0;
|
|
||||||
#[cfg(stm32f334)]
|
|
||||||
let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(
|
|
||||||
Self::frequency()
|
|
||||||
).0;
|
|
||||||
|
|
||||||
let psc_min = (timer_f / f) / (u16::MAX as u32 / 32);
|
|
||||||
let psc = if Self::regs().isr().read().dllrdy() {
|
|
||||||
Prescaler::compute_min_high_res(psc_min)
|
|
||||||
} else {
|
|
||||||
Prescaler::compute_min_low_res(psc_min)
|
|
||||||
};
|
|
||||||
|
|
||||||
let timer_f = 32 * (timer_f / psc as u32);
|
|
||||||
let per: u16 = (timer_f / f) as u16;
|
|
||||||
|
|
||||||
let regs = Self::regs();
|
|
||||||
|
|
||||||
regs.mcr().modify(|w| w.set_ckpsc(psc.into()));
|
|
||||||
regs.mper().modify(|w| w.set_mper(per));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_channel_frequency(channel: usize, frequency: Hertz) {
|
|
||||||
use crate::rcc::sealed::RccPeripheral;
|
|
||||||
|
|
||||||
let f = frequency.0;
|
|
||||||
#[cfg(not(stm32f334))]
|
|
||||||
let timer_f = Self::frequency().0;
|
|
||||||
#[cfg(stm32f334)]
|
|
||||||
let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(
|
|
||||||
Self::frequency()
|
|
||||||
).0;
|
|
||||||
|
|
||||||
let psc_min = (timer_f / f) / (u16::MAX as u32 / 32);
|
|
||||||
let psc = if Self::regs().isr().read().dllrdy() {
|
|
||||||
Prescaler::compute_min_high_res(psc_min)
|
|
||||||
} else {
|
|
||||||
Prescaler::compute_min_low_res(psc_min)
|
|
||||||
};
|
|
||||||
|
|
||||||
let timer_f = 32 * (timer_f / psc as u32);
|
|
||||||
let per: u16 = (timer_f / f) as u16;
|
|
||||||
|
|
||||||
let regs = Self::regs();
|
|
||||||
|
|
||||||
regs.tim(channel).cr().modify(|w| w.set_ckpsc(psc.into()));
|
|
||||||
regs.tim(channel).per().modify(|w| w.set_per(per));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_channel_dead_time(channel: usize, dead_time: u16) {
|
|
||||||
|
|
||||||
let regs = Self::regs();
|
|
||||||
|
|
||||||
let channel_psc: Prescaler = regs.tim(channel).cr().read().ckpsc().into();
|
|
||||||
|
|
||||||
// The dead-time base clock runs 4 times slower than the hrtim base clock
|
|
||||||
// u9::MAX = 511
|
|
||||||
let psc_min = (channel_psc as u32 * dead_time as u32) / (4 * 511);
|
|
||||||
let psc = if Self::regs().isr().read().dllrdy() {
|
|
||||||
Prescaler::compute_min_high_res(psc_min)
|
|
||||||
} else {
|
|
||||||
Prescaler::compute_min_low_res(psc_min)
|
|
||||||
};
|
|
||||||
|
|
||||||
let dt_val = (psc as u32 * dead_time as u32) / (4 * channel_psc as u32);
|
|
||||||
|
|
||||||
regs.tim(channel).dt().modify(|w| {
|
|
||||||
w.set_dtprsc(psc.into());
|
|
||||||
w.set_dtf(dt_val as u16);
|
|
||||||
w.set_dtr(dt_val as u16);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Instance for crate::peripherals::$inst {
|
impl Instance for crate::peripherals::$inst {
|
||||||
|
@ -518,7 +518,8 @@ impl Timings {
|
|||||||
|
|
||||||
impl<'d, T: Instance> SetConfig for I2c<'d, T> {
|
impl<'d, T: Instance> SetConfig for I2c<'d, T> {
|
||||||
type Config = Hertz;
|
type Config = Hertz;
|
||||||
fn set_config(&mut self, config: &Self::Config) {
|
type ConfigError = ();
|
||||||
|
fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
|
||||||
let timings = Timings::new(T::frequency(), *config);
|
let timings = Timings::new(T::frequency(), *config);
|
||||||
T::regs().cr2().modify(|reg| {
|
T::regs().cr2().modify(|reg| {
|
||||||
reg.set_freq(timings.freq);
|
reg.set_freq(timings.freq);
|
||||||
@ -531,5 +532,7 @@ impl<'d, T: Instance> SetConfig for I2c<'d, T> {
|
|||||||
T::regs().trise().modify(|reg| {
|
T::regs().trise().modify(|reg| {
|
||||||
reg.set_trise(timings.trise);
|
reg.set_trise(timings.trise);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1075,7 +1075,8 @@ mod eha {
|
|||||||
|
|
||||||
impl<'d, T: Instance> SetConfig for I2c<'d, T> {
|
impl<'d, T: Instance> SetConfig for I2c<'d, T> {
|
||||||
type Config = Hertz;
|
type Config = Hertz;
|
||||||
fn set_config(&mut self, config: &Self::Config) {
|
type ConfigError = ();
|
||||||
|
fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> {
|
||||||
let timings = Timings::new(T::frequency(), *config);
|
let timings = Timings::new(T::frequency(), *config);
|
||||||
T::regs().timingr().write(|reg| {
|
T::regs().timingr().write(|reg| {
|
||||||
reg.set_presc(timings.prescale);
|
reg.set_presc(timings.prescale);
|
||||||
@ -1084,5 +1085,7 @@ impl<'d, T: Instance> SetConfig for I2c<'d, T> {
|
|||||||
reg.set_sdadel(timings.sdadel);
|
reg.set_sdadel(timings.sdadel);
|
||||||
reg.set_scldel(timings.scldel);
|
reg.set_scldel(timings.scldel);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,15 +93,30 @@ pub struct Ipcc;
|
|||||||
|
|
||||||
impl Ipcc {
|
impl Ipcc {
|
||||||
pub fn enable(_config: Config) {
|
pub fn enable(_config: Config) {
|
||||||
|
// TODO: move these lines to the rcc mod
|
||||||
|
|
||||||
|
// set LPTIM1 & LPTIM2 clock source
|
||||||
|
crate::pac::RCC.ccipr().modify(|w| {
|
||||||
|
w.set_lptim1sel(0b00); // PCLK
|
||||||
|
w.set_lptim2sel(0b00); // PCLK
|
||||||
|
});
|
||||||
|
|
||||||
|
// set RF wake-up clock = LSE
|
||||||
|
crate::pac::RCC.csr().modify(|w| w.set_rfwkpsel(0b01));
|
||||||
|
|
||||||
IPCC::enable();
|
IPCC::enable();
|
||||||
IPCC::reset();
|
IPCC::reset();
|
||||||
|
// insert bus access and fence for delay
|
||||||
|
IPCC::enable();
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
IPCC::set_cpu2(true);
|
IPCC::set_cpu2(true);
|
||||||
|
|
||||||
_configure_pwr();
|
// insert bus access and fence for delay
|
||||||
|
IPCC::set_cpu2(true);
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
let regs = IPCC::regs();
|
IPCC::regs().cpu(0).cr().modify(|w| {
|
||||||
|
|
||||||
regs.cpu(0).cr().modify(|w| {
|
|
||||||
w.set_rxoie(true);
|
w.set_rxoie(true);
|
||||||
w.set_txfie(true);
|
w.set_txfie(true);
|
||||||
});
|
});
|
||||||
@ -263,18 +278,3 @@ pub(crate) mod sealed {
|
|||||||
fn state() -> &'static State;
|
fn state() -> &'static State;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _configure_pwr() {
|
|
||||||
// TODO: move the rest of this to rcc
|
|
||||||
let rcc = crate::pac::RCC;
|
|
||||||
|
|
||||||
// TODO: required
|
|
||||||
// set RF wake-up clock = LSE
|
|
||||||
rcc.csr().modify(|w| w.set_rfwkpsel(0b01));
|
|
||||||
|
|
||||||
// set LPTIM1 & LPTIM2 clock source
|
|
||||||
rcc.ccipr().modify(|w| {
|
|
||||||
w.set_lptim1sel(0b00); // PCLK
|
|
||||||
w.set_lptim2sel(0b00); // PCLK
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#![cfg_attr(not(test), no_std)]
|
#![cfg_attr(not(test), no_std)]
|
||||||
#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections))]
|
#![cfg_attr(feature = "nightly", feature(async_fn_in_trait))]
|
||||||
|
|
||||||
//! ## Feature flags
|
//! ## Feature flags
|
||||||
#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
|
#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
|
||||||
@ -49,12 +49,16 @@ pub mod i2s;
|
|||||||
pub mod ipcc;
|
pub mod ipcc;
|
||||||
#[cfg(feature = "low-power")]
|
#[cfg(feature = "low-power")]
|
||||||
pub mod low_power;
|
pub mod low_power;
|
||||||
|
#[cfg(opamp)]
|
||||||
|
pub mod opamp;
|
||||||
#[cfg(quadspi)]
|
#[cfg(quadspi)]
|
||||||
pub mod qspi;
|
pub mod qspi;
|
||||||
#[cfg(rng)]
|
#[cfg(rng)]
|
||||||
pub mod rng;
|
pub mod rng;
|
||||||
#[cfg(all(rtc, not(rtc_v1)))]
|
#[cfg(all(rtc, not(rtc_v1)))]
|
||||||
pub mod rtc;
|
pub mod rtc;
|
||||||
|
#[cfg(sai)]
|
||||||
|
pub mod sai;
|
||||||
#[cfg(sdmmc)]
|
#[cfg(sdmmc)]
|
||||||
pub mod sdmmc;
|
pub mod sdmmc;
|
||||||
#[cfg(spi)]
|
#[cfg(spi)]
|
||||||
@ -88,6 +92,7 @@ pub use crate::_generated::interrupt;
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! bind_interrupts {
|
macro_rules! bind_interrupts {
|
||||||
($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
|
($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
$vis struct $name;
|
$vis struct $name;
|
||||||
|
|
||||||
$(
|
$(
|
||||||
@ -117,6 +122,7 @@ pub(crate) use stm32_metapac as pac;
|
|||||||
use crate::interrupt::Priority;
|
use crate::interrupt::Priority;
|
||||||
#[cfg(feature = "rt")]
|
#[cfg(feature = "rt")]
|
||||||
pub use crate::pac::NVIC_PRIO_BITS;
|
pub use crate::pac::NVIC_PRIO_BITS;
|
||||||
|
use crate::rcc::sealed::RccPeripheral;
|
||||||
|
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
@ -154,7 +160,7 @@ pub fn init(config: Config) -> Peripherals {
|
|||||||
#[cfg(dbgmcu)]
|
#[cfg(dbgmcu)]
|
||||||
if config.enable_debug_during_sleep {
|
if config.enable_debug_during_sleep {
|
||||||
crate::pac::DBGMCU.cr().modify(|cr| {
|
crate::pac::DBGMCU.cr().modify(|cr| {
|
||||||
#[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5))]
|
#[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba))]
|
||||||
{
|
{
|
||||||
cr.set_dbg_stop(true);
|
cr.set_dbg_stop(true);
|
||||||
cr.set_dbg_standby(true);
|
cr.set_dbg_standby(true);
|
||||||
@ -179,7 +185,26 @@ pub fn init(config: Config) -> Peripherals {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(stm32f1, stm32wb, stm32wl)))]
|
||||||
|
peripherals::SYSCFG::enable();
|
||||||
|
#[cfg(not(any(stm32h5, stm32h7, stm32wb, stm32wl)))]
|
||||||
|
peripherals::PWR::enable();
|
||||||
|
#[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7)))]
|
||||||
|
peripherals::FLASH::enable();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
#[cfg(feature = "_split-pins-enabled")]
|
||||||
|
crate::pac::SYSCFG.pmcr().modify(|pmcr| {
|
||||||
|
#[cfg(feature = "split-pa0")]
|
||||||
|
pmcr.set_pa0so(true);
|
||||||
|
#[cfg(feature = "split-pa1")]
|
||||||
|
pmcr.set_pa1so(true);
|
||||||
|
#[cfg(feature = "split-pc2")]
|
||||||
|
pmcr.set_pc2so(true);
|
||||||
|
#[cfg(feature = "split-pc3")]
|
||||||
|
pmcr.set_pc3so(true);
|
||||||
|
});
|
||||||
|
|
||||||
gpio::init();
|
gpio::init();
|
||||||
dma::init(
|
dma::init(
|
||||||
#[cfg(bdma)]
|
#[cfg(bdma)]
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
use core::arch::asm;
|
use core::arch::asm;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use atomic_polyfill::{compiler_fence, Ordering};
|
||||||
use cortex_m::peripheral::SCB;
|
use cortex_m::peripheral::SCB;
|
||||||
use embassy_executor::*;
|
use embassy_executor::*;
|
||||||
|
|
||||||
use crate::interrupt;
|
use crate::interrupt;
|
||||||
use crate::interrupt::typelevel::Interrupt;
|
|
||||||
use crate::rcc::low_power_ready;
|
use crate::rcc::low_power_ready;
|
||||||
use crate::time_driver::{get_driver, RtcDriver};
|
use crate::time_driver::{get_driver, RtcDriver};
|
||||||
|
|
||||||
@ -19,36 +19,20 @@ foreach_interrupt! {
|
|||||||
(RTC, rtc, $block:ident, WKUP, $irq:ident) => {
|
(RTC, rtc, $block:ident, WKUP, $irq:ident) => {
|
||||||
#[interrupt]
|
#[interrupt]
|
||||||
unsafe fn $irq() {
|
unsafe fn $irq() {
|
||||||
unsafe { EXECUTOR.as_mut().unwrap() }.on_wakeup_irq();
|
EXECUTOR.as_mut().unwrap().on_wakeup_irq();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn timer_driver_pause_time() {
|
#[allow(dead_code)]
|
||||||
// pause_time();
|
pub(crate) unsafe fn on_wakeup_irq() {
|
||||||
// }
|
EXECUTOR.as_mut().unwrap().on_wakeup_irq();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn stop_with_rtc(rtc: &'static Rtc) {
|
pub fn stop_with_rtc(rtc: &'static Rtc) {
|
||||||
unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc)
|
unsafe { EXECUTOR.as_mut().unwrap() }.stop_with_rtc(rtc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn start_wakeup_alarm(requested_duration: embassy_time::Duration) {
|
|
||||||
// let rtc_instant = unsafe { EXECUTOR.as_mut().unwrap() }
|
|
||||||
// .rtc
|
|
||||||
// .unwrap()
|
|
||||||
// .start_wakeup_alarm(requested_duration);
|
|
||||||
//
|
|
||||||
// unsafe { EXECUTOR.as_mut().unwrap() }.last_stop = Some(rtc_instant);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// pub fn set_sleepdeep() {
|
|
||||||
// unsafe { EXECUTOR.as_mut().unwrap() }.scb.set_sleepdeep();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// pub fn stop_wakeup_alarm() -> RtcInstant {
|
|
||||||
// unsafe { EXECUTOR.as_mut().unwrap() }.rtc.unwrap().stop_wakeup_alarm()
|
|
||||||
// }
|
|
||||||
|
|
||||||
/// Thread mode executor, using WFE/SEV.
|
/// Thread mode executor, using WFE/SEV.
|
||||||
///
|
///
|
||||||
/// This is the simplest and most common kind of executor. It runs on
|
/// This is the simplest and most common kind of executor. It runs on
|
||||||
@ -84,39 +68,31 @@ impl Executor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn on_wakeup_irq(&mut self) {
|
unsafe fn on_wakeup_irq(&mut self) {
|
||||||
trace!("low power: on wakeup irq");
|
|
||||||
|
|
||||||
self.time_driver.resume_time();
|
self.time_driver.resume_time();
|
||||||
trace!("low power: resume time");
|
trace!("low power: resume");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) {
|
pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) {
|
||||||
trace!("low power: stop with rtc configured");
|
|
||||||
|
|
||||||
self.time_driver.set_rtc(rtc);
|
self.time_driver.set_rtc(rtc);
|
||||||
|
|
||||||
crate::interrupt::typelevel::RTC_WKUP::unpend();
|
|
||||||
unsafe { crate::interrupt::typelevel::RTC_WKUP::enable() };
|
|
||||||
|
|
||||||
rtc.enable_wakeup_line();
|
rtc.enable_wakeup_line();
|
||||||
|
|
||||||
|
trace!("low power: stop with rtc configured");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn configure_pwr(&mut self) {
|
fn configure_pwr(&mut self) {
|
||||||
trace!("low power: configure_pwr");
|
|
||||||
|
|
||||||
self.scb.clear_sleepdeep();
|
self.scb.clear_sleepdeep();
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
|
||||||
if !low_power_ready() {
|
if !low_power_ready() {
|
||||||
trace!("low power: configure_pwr: low power not ready");
|
trace!("low power: not ready to stop");
|
||||||
return;
|
} else if self.time_driver.pause_time().is_err() {
|
||||||
|
trace!("low power: failed to pause time");
|
||||||
|
} else {
|
||||||
|
trace!("low power: stop");
|
||||||
|
self.scb.set_sleepdeep();
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.time_driver.pause_time().is_err() {
|
|
||||||
trace!("low power: configure_pwr: time driver failed to pause");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
trace!("low power: enter stop...");
|
|
||||||
self.scb.set_sleepdeep();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run the executor.
|
/// Run the executor.
|
||||||
|
133
embassy-stm32/src/opamp.rs
Normal file
133
embassy-stm32/src/opamp.rs
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
#![macro_use]
|
||||||
|
|
||||||
|
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||||
|
|
||||||
|
use crate::Peripheral;
|
||||||
|
|
||||||
|
#[cfg(opamp_f3)]
|
||||||
|
pub struct OpAmpOutput<'d, 'p, T: Instance, P: NonInvertingPin<T>> {
|
||||||
|
_inner: &'d OpAmp<'d, T>,
|
||||||
|
_input: &'p mut P,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct OpAmp<'d, T: Instance> {
|
||||||
|
_inner: PeripheralRef<'d, T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: Instance> OpAmp<'d, T> {
|
||||||
|
pub fn new(opamp: impl Peripheral<P = T> + 'd) -> Self {
|
||||||
|
Self::new_inner(opamp)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_inner(opamp: impl Peripheral<P = T> + 'd) -> Self {
|
||||||
|
into_ref!(opamp);
|
||||||
|
|
||||||
|
#[cfg(opamp_f3)]
|
||||||
|
T::regs().opampcsr().modify(|w| {
|
||||||
|
w.set_opampen(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
#[cfg(opamp_g4)]
|
||||||
|
T::regs().opamp_csr().modify(|w| {
|
||||||
|
w.set_opaen(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
Self { _inner: opamp }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(opamp_f3)]
|
||||||
|
pub fn buffer_for<'a, 'b, P>(&'a mut self, pin: &'b mut P) -> OpAmpOutput<'a, 'b, T, P>
|
||||||
|
where
|
||||||
|
P: NonInvertingPin<T>,
|
||||||
|
{
|
||||||
|
#[cfg(opamp_f3)]
|
||||||
|
T::regs().opampcsr().modify(|w| {
|
||||||
|
w.set_vp_sel(pin.channel());
|
||||||
|
});
|
||||||
|
|
||||||
|
OpAmpOutput {
|
||||||
|
_inner: self,
|
||||||
|
_input: pin,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Instance: sealed::Instance + 'static {}
|
||||||
|
|
||||||
|
pub(crate) mod sealed {
|
||||||
|
pub trait Instance {
|
||||||
|
fn regs() -> crate::pac::opamp::Opamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait NonInvertingPin<T: Instance> {
|
||||||
|
fn channel(&self) -> u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait InvertingPin<T: Instance> {
|
||||||
|
fn channel(&self) -> u8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait NonInvertingPin<T: Instance>: sealed::NonInvertingPin<T> {}
|
||||||
|
|
||||||
|
pub trait InvertingPin<T: Instance>: sealed::InvertingPin<T> {}
|
||||||
|
|
||||||
|
#[cfg(opamp_f3)]
|
||||||
|
macro_rules! impl_opamp_output {
|
||||||
|
($inst:ident, $adc:ident, $ch:expr) => {
|
||||||
|
impl<'d, 'p, P: NonInvertingPin<crate::peripherals::$inst>> crate::adc::sealed::AdcPin<crate::peripherals::$adc>
|
||||||
|
for OpAmpOutput<'d, 'p, crate::peripherals::$inst, P>
|
||||||
|
{
|
||||||
|
fn channel(&self) -> u8 {
|
||||||
|
$ch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, 'p, P: NonInvertingPin<crate::peripherals::$inst>> crate::adc::AdcPin<crate::peripherals::$adc>
|
||||||
|
for OpAmpOutput<'d, 'p, crate::peripherals::$inst, P>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(opamp_f3)]
|
||||||
|
foreach_peripheral!(
|
||||||
|
(opamp, OPAMP1) => {
|
||||||
|
impl_opamp_output!(OPAMP1, ADC1, 3);
|
||||||
|
};
|
||||||
|
(opamp, OPAMP2) => {
|
||||||
|
impl_opamp_output!(OPAMP2, ADC2, 3);
|
||||||
|
};
|
||||||
|
(opamp, OPAMP3) => {
|
||||||
|
impl_opamp_output!(OPAMP3, ADC3, 1);
|
||||||
|
};
|
||||||
|
(opamp, OPAMP4) => {
|
||||||
|
impl_opamp_output!(OPAMP4, ADC4, 3);
|
||||||
|
};
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach_peripheral! {
|
||||||
|
(opamp, $inst:ident) => {
|
||||||
|
impl sealed::Instance for crate::peripherals::$inst {
|
||||||
|
fn regs() -> crate::pac::opamp::Opamp {
|
||||||
|
crate::pac::$inst
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Instance for crate::peripherals::$inst {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_macros)]
|
||||||
|
macro_rules! impl_opamp_pin {
|
||||||
|
($inst:ident, $pin:ident, $ch:expr) => {
|
||||||
|
impl crate::opamp::NonInvertingPin<peripherals::$inst> for crate::peripherals::$pin {}
|
||||||
|
impl crate::opamp::sealed::NonInvertingPin<peripherals::$inst> for crate::peripherals::$pin {
|
||||||
|
fn channel(&self) -> u8 {
|
||||||
|
$ch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -38,6 +38,22 @@ impl Into<u8> for QspiWidth {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub enum FlashSelection {
|
||||||
|
Flash1,
|
||||||
|
Flash2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<bool> for FlashSelection {
|
||||||
|
fn into(self) -> bool {
|
||||||
|
match self {
|
||||||
|
FlashSelection::Flash1 => false,
|
||||||
|
FlashSelection::Flash2 => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub enum MemorySize {
|
pub enum MemorySize {
|
||||||
_1KiB,
|
_1KiB,
|
||||||
|
@ -7,7 +7,7 @@ use enums::*;
|
|||||||
|
|
||||||
use crate::dma::Transfer;
|
use crate::dma::Transfer;
|
||||||
use crate::gpio::sealed::AFType;
|
use crate::gpio::sealed::AFType;
|
||||||
use crate::gpio::AnyPin;
|
use crate::gpio::{AnyPin, Pull};
|
||||||
use crate::pac::quadspi::Quadspi as Regs;
|
use crate::pac::quadspi::Quadspi as Regs;
|
||||||
use crate::rcc::RccPeripheral;
|
use crate::rcc::RccPeripheral;
|
||||||
use crate::{peripherals, Peripheral};
|
use crate::{peripherals, Peripheral};
|
||||||
@ -83,30 +83,30 @@ pub struct Qspi<'d, T: Instance, Dma> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
|
impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
|
||||||
pub fn new(
|
pub fn new_bk1(
|
||||||
peri: impl Peripheral<P = T> + 'd,
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
|
d0: impl Peripheral<P = impl BK1D0Pin<T>> + 'd,
|
||||||
d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
|
d1: impl Peripheral<P = impl BK1D1Pin<T>> + 'd,
|
||||||
d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
|
d2: impl Peripheral<P = impl BK1D2Pin<T>> + 'd,
|
||||||
d3: impl Peripheral<P = impl D3Pin<T>> + 'd,
|
d3: impl Peripheral<P = impl BK1D3Pin<T>> + 'd,
|
||||||
sck: impl Peripheral<P = impl SckPin<T>> + 'd,
|
sck: impl Peripheral<P = impl SckPin<T>> + 'd,
|
||||||
nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
|
nss: impl Peripheral<P = impl BK1NSSPin<T>> + 'd,
|
||||||
dma: impl Peripheral<P = Dma> + 'd,
|
dma: impl Peripheral<P = Dma> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(peri, d0, d1, d2, d3, sck, nss);
|
into_ref!(peri, d0, d1, d2, d3, sck, nss);
|
||||||
|
|
||||||
sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
|
sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None);
|
||||||
sck.set_speed(crate::gpio::Speed::VeryHigh);
|
sck.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
nss.set_as_af(nss.af_num(), AFType::OutputPushPull);
|
nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up);
|
||||||
nss.set_speed(crate::gpio::Speed::VeryHigh);
|
nss.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
d0.set_as_af(d0.af_num(), AFType::OutputPushPull);
|
d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None);
|
||||||
d0.set_speed(crate::gpio::Speed::VeryHigh);
|
d0.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
d1.set_as_af(d1.af_num(), AFType::OutputPushPull);
|
d1.set_as_af_pull(d1.af_num(), AFType::OutputPushPull, Pull::None);
|
||||||
d1.set_speed(crate::gpio::Speed::VeryHigh);
|
d1.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
d2.set_as_af(d2.af_num(), AFType::OutputPushPull);
|
d2.set_as_af_pull(d2.af_num(), AFType::OutputPushPull, Pull::None);
|
||||||
d2.set_speed(crate::gpio::Speed::VeryHigh);
|
d2.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
d3.set_as_af(d3.af_num(), AFType::OutputPushPull);
|
d3.set_as_af_pull(d3.af_num(), AFType::OutputPushPull, Pull::None);
|
||||||
d3.set_speed(crate::gpio::Speed::VeryHigh);
|
d3.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
|
|
||||||
Self::new_inner(
|
Self::new_inner(
|
||||||
@ -119,6 +119,47 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
|
|||||||
Some(nss.map_into()),
|
Some(nss.map_into()),
|
||||||
dma,
|
dma,
|
||||||
config,
|
config,
|
||||||
|
FlashSelection::Flash2,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_bk2(
|
||||||
|
peri: impl Peripheral<P = T> + 'd,
|
||||||
|
d0: impl Peripheral<P = impl BK2D0Pin<T>> + 'd,
|
||||||
|
d1: impl Peripheral<P = impl BK2D1Pin<T>> + 'd,
|
||||||
|
d2: impl Peripheral<P = impl BK2D2Pin<T>> + 'd,
|
||||||
|
d3: impl Peripheral<P = impl BK2D3Pin<T>> + 'd,
|
||||||
|
sck: impl Peripheral<P = impl SckPin<T>> + 'd,
|
||||||
|
nss: impl Peripheral<P = impl BK2NSSPin<T>> + 'd,
|
||||||
|
dma: impl Peripheral<P = Dma> + 'd,
|
||||||
|
config: Config,
|
||||||
|
) -> Self {
|
||||||
|
into_ref!(peri, d0, d1, d2, d3, sck, nss);
|
||||||
|
|
||||||
|
sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None);
|
||||||
|
sck.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
|
nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up);
|
||||||
|
nss.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
|
d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None);
|
||||||
|
d0.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
|
d1.set_as_af_pull(d1.af_num(), AFType::OutputPushPull, Pull::None);
|
||||||
|
d1.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
|
d2.set_as_af_pull(d2.af_num(), AFType::OutputPushPull, Pull::None);
|
||||||
|
d2.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
|
d3.set_as_af_pull(d3.af_num(), AFType::OutputPushPull, Pull::None);
|
||||||
|
d3.set_speed(crate::gpio::Speed::VeryHigh);
|
||||||
|
|
||||||
|
Self::new_inner(
|
||||||
|
peri,
|
||||||
|
Some(d0.map_into()),
|
||||||
|
Some(d1.map_into()),
|
||||||
|
Some(d2.map_into()),
|
||||||
|
Some(d3.map_into()),
|
||||||
|
Some(sck.map_into()),
|
||||||
|
Some(nss.map_into()),
|
||||||
|
dma,
|
||||||
|
config,
|
||||||
|
FlashSelection::Flash2,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,22 +173,40 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
|
|||||||
nss: Option<PeripheralRef<'d, AnyPin>>,
|
nss: Option<PeripheralRef<'d, AnyPin>>,
|
||||||
dma: impl Peripheral<P = Dma> + 'd,
|
dma: impl Peripheral<P = Dma> + 'd,
|
||||||
config: Config,
|
config: Config,
|
||||||
|
fsel: FlashSelection,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
into_ref!(peri, dma);
|
into_ref!(peri, dma);
|
||||||
|
|
||||||
T::enable();
|
T::enable();
|
||||||
T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into()));
|
T::reset();
|
||||||
|
|
||||||
while T::REGS.sr().read().busy() {}
|
while T::REGS.sr().read().busy() {}
|
||||||
|
|
||||||
T::REGS.cr().write(|w| {
|
#[cfg(stm32h7)]
|
||||||
w.set_prescaler(config.prescaler);
|
{
|
||||||
|
use stm32_metapac::quadspi::regs::Cr;
|
||||||
|
// Apply precautionary steps according to the errata...
|
||||||
|
T::REGS.cr().write_value(Cr(0));
|
||||||
|
while T::REGS.sr().read().busy() {}
|
||||||
|
T::REGS.cr().write_value(Cr(0xFF000001));
|
||||||
|
T::REGS.ccr().write(|w| w.set_frcm(true));
|
||||||
|
T::REGS.ccr().write(|w| w.set_frcm(true));
|
||||||
|
T::REGS.cr().write_value(Cr(0));
|
||||||
|
while T::REGS.sr().read().busy() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
T::REGS.cr().modify(|w| {
|
||||||
w.set_en(true);
|
w.set_en(true);
|
||||||
|
//w.set_tcen(false);
|
||||||
|
w.set_sshift(false);
|
||||||
|
w.set_fthres(config.fifo_threshold.into());
|
||||||
|
w.set_prescaler(config.prescaler);
|
||||||
|
w.set_fsel(fsel.into());
|
||||||
});
|
});
|
||||||
T::REGS.dcr().write(|w| {
|
T::REGS.dcr().modify(|w| {
|
||||||
w.set_fsize(config.memory_size.into());
|
w.set_fsize(config.memory_size.into());
|
||||||
w.set_csht(config.cs_high_time.into());
|
w.set_csht(config.cs_high_time.into());
|
||||||
w.set_ckmode(false);
|
w.set_ckmode(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
@ -164,6 +223,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn command(&mut self, transaction: TransferConfig) {
|
pub fn command(&mut self, transaction: TransferConfig) {
|
||||||
|
#[cfg(not(stm32h7))]
|
||||||
T::REGS.cr().modify(|v| v.set_dmaen(false));
|
T::REGS.cr().modify(|v| v.set_dmaen(false));
|
||||||
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
|
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
|
||||||
|
|
||||||
@ -172,6 +232,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) {
|
pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) {
|
||||||
|
#[cfg(not(stm32h7))]
|
||||||
T::REGS.cr().modify(|v| v.set_dmaen(false));
|
T::REGS.cr().modify(|v| v.set_dmaen(false));
|
||||||
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
|
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
|
||||||
|
|
||||||
@ -195,7 +256,10 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) {
|
pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) {
|
||||||
|
// STM32H7 does not have dmaen
|
||||||
|
#[cfg(not(stm32h7))]
|
||||||
T::REGS.cr().modify(|v| v.set_dmaen(false));
|
T::REGS.cr().modify(|v| v.set_dmaen(false));
|
||||||
|
|
||||||
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
|
self.setup_transaction(QspiMode::IndirectWrite, &transaction);
|
||||||
|
|
||||||
if let Some(len) = transaction.data_len {
|
if let Some(len) = transaction.data_len {
|
||||||
@ -238,6 +302,8 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// STM32H7 does not have dmaen
|
||||||
|
#[cfg(not(stm32h7))]
|
||||||
T::REGS.cr().modify(|v| v.set_dmaen(true));
|
T::REGS.cr().modify(|v| v.set_dmaen(true));
|
||||||
|
|
||||||
transfer.blocking_wait();
|
transfer.blocking_wait();
|
||||||
@ -264,6 +330,8 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// STM32H7 does not have dmaen
|
||||||
|
#[cfg(not(stm32h7))]
|
||||||
T::REGS.cr().modify(|v| v.set_dmaen(true));
|
T::REGS.cr().modify(|v| v.set_dmaen(true));
|
||||||
|
|
||||||
transfer.blocking_wait();
|
transfer.blocking_wait();
|
||||||
@ -313,11 +381,17 @@ pub(crate) mod sealed {
|
|||||||
pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
|
pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
|
||||||
|
|
||||||
pin_trait!(SckPin, Instance);
|
pin_trait!(SckPin, Instance);
|
||||||
pin_trait!(D0Pin, Instance);
|
pin_trait!(BK1D0Pin, Instance);
|
||||||
pin_trait!(D1Pin, Instance);
|
pin_trait!(BK1D1Pin, Instance);
|
||||||
pin_trait!(D2Pin, Instance);
|
pin_trait!(BK1D2Pin, Instance);
|
||||||
pin_trait!(D3Pin, Instance);
|
pin_trait!(BK1D3Pin, Instance);
|
||||||
pin_trait!(NSSPin, Instance);
|
pin_trait!(BK1NSSPin, Instance);
|
||||||
|
|
||||||
|
pin_trait!(BK2D0Pin, Instance);
|
||||||
|
pin_trait!(BK2D1Pin, Instance);
|
||||||
|
pin_trait!(BK2D2Pin, Instance);
|
||||||
|
pin_trait!(BK2D3Pin, Instance);
|
||||||
|
pin_trait!(BK2NSSPin, Instance);
|
||||||
|
|
||||||
dma_trait!(QuadDma, Instance);
|
dma_trait!(QuadDma, Instance);
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Default)]
|
#[derive(Default, Clone, Copy)]
|
||||||
pub enum LseDrive {
|
pub enum LseDrive {
|
||||||
#[cfg(any(rtc_v2f7, rtc_v2l4))]
|
#[cfg(any(rtc_v2f7, rtc_v2l4))]
|
||||||
Low = 0,
|
Low = 0,
|
||||||
@ -26,19 +26,7 @@ impl From<LseDrive> for crate::pac::rcc::vals::Lsedrv {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource;
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
|
||||||
#[repr(u8)]
|
|
||||||
pub enum RtcClockSource {
|
|
||||||
/// 00: No clock
|
|
||||||
NoClock = 0b00,
|
|
||||||
/// 01: LSE oscillator clock used as RTC clock
|
|
||||||
LSE = 0b01,
|
|
||||||
/// 10: LSI oscillator clock used as RTC clock
|
|
||||||
LSI = 0b10,
|
|
||||||
/// 11: HSE oscillator clock divided by 32 used as RTC clock
|
|
||||||
HSE = 0b11,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(any(rtc_v2l0, rtc_v2l1, stm32c0)))]
|
#[cfg(not(any(rtc_v2l0, rtc_v2l1, stm32c0)))]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -58,13 +46,13 @@ impl BackupDomain {
|
|||||||
))]
|
))]
|
||||||
#[allow(dead_code, unused_variables)]
|
#[allow(dead_code, unused_variables)]
|
||||||
fn modify<R>(f: impl FnOnce(&mut Bdcr) -> R) -> R {
|
fn modify<R>(f: impl FnOnce(&mut Bdcr) -> R) -> R {
|
||||||
#[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1))]
|
#[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1, rtc_v2l0))]
|
||||||
let cr = crate::pac::PWR.cr();
|
let cr = crate::pac::PWR.cr();
|
||||||
#[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
|
#[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
|
||||||
let cr = crate::pac::PWR.cr1();
|
let cr = crate::pac::PWR.cr1();
|
||||||
|
|
||||||
// TODO: Missing from PAC for l0 and f0?
|
// TODO: Missing from PAC for l0 and f0?
|
||||||
#[cfg(not(any(rtc_v2f0, rtc_v2l0, rtc_v3u5)))]
|
#[cfg(not(any(rtc_v2f0, rtc_v3u5)))]
|
||||||
{
|
{
|
||||||
cr.modify(|w| w.set_dbp(true));
|
cr.modify(|w| w.set_dbp(true));
|
||||||
while !cr.read().dbp() {}
|
while !cr.read().dbp() {}
|
||||||
@ -99,101 +87,97 @@ impl BackupDomain {
|
|||||||
rtc_v3u5
|
rtc_v3u5
|
||||||
))]
|
))]
|
||||||
#[allow(dead_code, unused_variables)]
|
#[allow(dead_code, unused_variables)]
|
||||||
pub fn configure_ls(clock_source: RtcClockSource, lse_drive: Option<LseDrive>) {
|
pub fn configure_ls(clock_source: RtcClockSource, lsi: bool, lse: Option<LseDrive>) {
|
||||||
|
use atomic_polyfill::{compiler_fence, Ordering};
|
||||||
|
|
||||||
match clock_source {
|
match clock_source {
|
||||||
RtcClockSource::LSI => {
|
RtcClockSource::LSI => assert!(lsi),
|
||||||
#[cfg(rtc_v3u5)]
|
RtcClockSource::LSE => assert!(&lse.is_some()),
|
||||||
let csr = crate::pac::RCC.bdcr();
|
|
||||||
|
|
||||||
#[cfg(not(rtc_v3u5))]
|
|
||||||
let csr = crate::pac::RCC.csr();
|
|
||||||
|
|
||||||
Self::modify(|_| {
|
|
||||||
#[cfg(not(rtc_v2wb))]
|
|
||||||
csr.modify(|w| w.set_lsion(true));
|
|
||||||
|
|
||||||
#[cfg(rtc_v2wb)]
|
|
||||||
csr.modify(|w| w.set_lsi1on(true));
|
|
||||||
});
|
|
||||||
|
|
||||||
#[cfg(not(rtc_v2wb))]
|
|
||||||
while !csr.read().lsirdy() {}
|
|
||||||
|
|
||||||
#[cfg(rtc_v2wb)]
|
|
||||||
while !csr.read().lsi1rdy() {}
|
|
||||||
}
|
|
||||||
RtcClockSource::LSE => {
|
|
||||||
let lse_drive = lse_drive.unwrap_or_default();
|
|
||||||
|
|
||||||
Self::modify(|w| {
|
|
||||||
#[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))]
|
|
||||||
w.set_lsedrv(lse_drive.into());
|
|
||||||
w.set_lseon(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
while !Self::read().lserdy() {}
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
Self::configure_rtc(clock_source);
|
if lsi {
|
||||||
}
|
#[cfg(rtc_v3u5)]
|
||||||
|
let csr = crate::pac::RCC.bdcr();
|
||||||
|
|
||||||
#[cfg(any(
|
#[cfg(not(rtc_v3u5))]
|
||||||
rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3,
|
let csr = crate::pac::RCC.csr();
|
||||||
rtc_v3u5
|
|
||||||
))]
|
|
||||||
#[allow(dead_code, unused_variables)]
|
|
||||||
pub fn configure_rtc(clock_source: RtcClockSource) {
|
|
||||||
let clock_source = clock_source as u8;
|
|
||||||
#[cfg(any(
|
|
||||||
not(any(rtc_v3, rtc_v3u5, rtc_v2wb)),
|
|
||||||
all(any(rtc_v3, rtc_v3u5), not(any(rcc_wl5, rcc_wle)))
|
|
||||||
))]
|
|
||||||
let clock_source = crate::pac::rcc::vals::Rtcsel::from_bits(clock_source);
|
|
||||||
|
|
||||||
#[cfg(not(rtc_v2wb))]
|
// Disable backup domain write protection
|
||||||
Self::modify(|w| {
|
Self::modify(|_| {});
|
||||||
// Select RTC source
|
|
||||||
w.set_rtcsel(clock_source);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(
|
#[cfg(not(any(rcc_wb, rcc_wba)))]
|
||||||
rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3,
|
csr.modify(|w| w.set_lsion(true));
|
||||||
rtc_v3u5
|
|
||||||
))]
|
#[cfg(any(rcc_wb, rcc_wba))]
|
||||||
#[allow(dead_code)]
|
csr.modify(|w| w.set_lsi1on(true));
|
||||||
pub fn enable_rtc() {
|
|
||||||
|
#[cfg(not(any(rcc_wb, rcc_wba)))]
|
||||||
|
while !csr.read().lsirdy() {}
|
||||||
|
|
||||||
|
#[cfg(any(rcc_wb, rcc_wba))]
|
||||||
|
while !csr.read().lsi1rdy() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// backup domain configuration (LSEON, RTCEN, RTCSEL) is kept across resets.
|
||||||
|
// once set, changing it requires a backup domain reset.
|
||||||
|
// first check if the configuration matches what we want.
|
||||||
|
|
||||||
|
// check if it's already enabled and in the source we want.
|
||||||
let reg = Self::read();
|
let reg = Self::read();
|
||||||
|
let mut ok = true;
|
||||||
|
ok &= reg.rtcsel() == clock_source;
|
||||||
|
#[cfg(not(rcc_wba))]
|
||||||
|
{
|
||||||
|
ok &= reg.rtcen() == (clock_source != RtcClockSource::NOCLOCK);
|
||||||
|
}
|
||||||
|
ok &= reg.lseon() == lse.is_some();
|
||||||
|
#[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))]
|
||||||
|
if let Some(lse_drive) = lse {
|
||||||
|
ok &= reg.lsedrv() == lse_drive.into();
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
|
// if configuration is OK, we're done.
|
||||||
assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
|
if ok {
|
||||||
|
// RTC code assumes backup domain is unlocked
|
||||||
|
Self::modify(|w| {});
|
||||||
|
|
||||||
if !reg.rtcen() {
|
trace!("BDCR ok: {:08x}", Self::read().0);
|
||||||
#[cfg(not(any(rtc_v2l0, rtc_v2l1, rtc_v2f2)))]
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not OK, reset backup domain and configure it.
|
||||||
|
#[cfg(not(any(rcc_l0, rcc_l1)))]
|
||||||
|
{
|
||||||
Self::modify(|w| w.set_bdrst(true));
|
Self::modify(|w| w.set_bdrst(true));
|
||||||
|
Self::modify(|w| w.set_bdrst(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(lse_drive) = lse {
|
||||||
Self::modify(|w| {
|
Self::modify(|w| {
|
||||||
// Reset
|
#[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))]
|
||||||
#[cfg(not(any(rtc_v2l0, rtc_v2l1, rtc_v2f2)))]
|
w.set_lsedrv(lse_drive.into());
|
||||||
w.set_bdrst(false);
|
w.set_lseon(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
while !Self::read().lserdy() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if clock_source != RtcClockSource::NOCLOCK {
|
||||||
|
Self::modify(|w| {
|
||||||
|
#[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
|
||||||
|
assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
|
||||||
|
|
||||||
|
#[cfg(not(rcc_wba))]
|
||||||
w.set_rtcen(true);
|
w.set_rtcen(true);
|
||||||
w.set_rtcsel(reg.rtcsel());
|
w.set_rtcsel(clock_source);
|
||||||
|
|
||||||
// Restore bcdr
|
|
||||||
#[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
|
|
||||||
w.set_lscosel(reg.lscosel());
|
|
||||||
#[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
|
|
||||||
w.set_lscoen(reg.lscoen());
|
|
||||||
|
|
||||||
w.set_lseon(reg.lseon());
|
|
||||||
|
|
||||||
#[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
|
|
||||||
w.set_lsedrv(reg.lsedrv());
|
|
||||||
w.set_lsebyp(reg.lsebyp());
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trace!("BDCR configured: {:08x}", Self::read().0);
|
||||||
|
|
||||||
|
compiler_fence(Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,173 +2,55 @@ use core::ops::Div;
|
|||||||
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use crate::pac::rcc;
|
use crate::pac::rcc;
|
||||||
|
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler};
|
||||||
use crate::time::Hertz;
|
use crate::time::Hertz;
|
||||||
|
|
||||||
/// Voltage Scale
|
|
||||||
///
|
|
||||||
/// Represents the voltage range feeding the CPU core. The maximum core
|
|
||||||
/// clock frequency depends on this value.
|
|
||||||
///
|
|
||||||
/// Scale0 represents the highest voltage range
|
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
|
||||||
pub enum VoltageScale {
|
|
||||||
Scale0,
|
|
||||||
Scale1,
|
|
||||||
#[cfg(not(any(rcc_wl5, rcc_wle)))]
|
|
||||||
Scale2,
|
|
||||||
#[cfg(not(any(rcc_wl5, rcc_wle)))]
|
|
||||||
Scale3,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// AHB prescaler
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
|
||||||
pub enum AHBPrescaler {
|
|
||||||
NotDivided,
|
|
||||||
Div2,
|
|
||||||
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
|
||||||
Div3,
|
|
||||||
Div4,
|
|
||||||
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
|
||||||
Div5,
|
|
||||||
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
|
||||||
Div6,
|
|
||||||
Div8,
|
|
||||||
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
|
||||||
Div10,
|
|
||||||
Div16,
|
|
||||||
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
|
||||||
Div32,
|
|
||||||
Div64,
|
|
||||||
Div128,
|
|
||||||
Div256,
|
|
||||||
Div512,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Div<AHBPrescaler> for Hertz {
|
impl Div<AHBPrescaler> for Hertz {
|
||||||
type Output = Hertz;
|
type Output = Hertz;
|
||||||
|
|
||||||
fn div(self, rhs: AHBPrescaler) -> Self::Output {
|
fn div(self, rhs: AHBPrescaler) -> Self::Output {
|
||||||
let divisor = match rhs {
|
let divisor = match rhs {
|
||||||
AHBPrescaler::NotDivided => 1,
|
AHBPrescaler::DIV1 => 1,
|
||||||
AHBPrescaler::Div2 => 2,
|
AHBPrescaler::DIV2 => 2,
|
||||||
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
||||||
AHBPrescaler::Div3 => 3,
|
AHBPrescaler::DIV3 => 3,
|
||||||
AHBPrescaler::Div4 => 4,
|
AHBPrescaler::DIV4 => 4,
|
||||||
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
||||||
AHBPrescaler::Div5 => 5,
|
AHBPrescaler::DIV5 => 5,
|
||||||
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
||||||
AHBPrescaler::Div6 => 6,
|
AHBPrescaler::DIV6 => 6,
|
||||||
AHBPrescaler::Div8 => 8,
|
AHBPrescaler::DIV8 => 8,
|
||||||
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
||||||
AHBPrescaler::Div10 => 10,
|
AHBPrescaler::DIV10 => 10,
|
||||||
AHBPrescaler::Div16 => 16,
|
AHBPrescaler::DIV16 => 16,
|
||||||
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
||||||
AHBPrescaler::Div32 => 32,
|
AHBPrescaler::DIV32 => 32,
|
||||||
AHBPrescaler::Div64 => 64,
|
#[cfg(not(rcc_wba))]
|
||||||
AHBPrescaler::Div128 => 128,
|
AHBPrescaler::DIV64 => 64,
|
||||||
AHBPrescaler::Div256 => 256,
|
#[cfg(not(rcc_wba))]
|
||||||
AHBPrescaler::Div512 => 512,
|
AHBPrescaler::DIV128 => 128,
|
||||||
|
#[cfg(not(rcc_wba))]
|
||||||
|
AHBPrescaler::DIV256 => 256,
|
||||||
|
#[cfg(not(rcc_wba))]
|
||||||
|
AHBPrescaler::DIV512 => 512,
|
||||||
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
Hertz(self.0 / divisor)
|
Hertz(self.0 / divisor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(rcc_g4, rcc_wb, rcc_wl5, rcc_wle)))]
|
|
||||||
impl From<AHBPrescaler> for rcc::vals::Hpre {
|
|
||||||
fn from(val: AHBPrescaler) -> rcc::vals::Hpre {
|
|
||||||
use rcc::vals::Hpre;
|
|
||||||
|
|
||||||
match val {
|
|
||||||
#[cfg(not(rcc_u5))]
|
|
||||||
AHBPrescaler::NotDivided => Hpre::DIV1,
|
|
||||||
#[cfg(rcc_u5)]
|
|
||||||
AHBPrescaler::NotDivided => Hpre::NONE,
|
|
||||||
AHBPrescaler::Div2 => Hpre::DIV2,
|
|
||||||
AHBPrescaler::Div4 => Hpre::DIV4,
|
|
||||||
AHBPrescaler::Div8 => Hpre::DIV8,
|
|
||||||
AHBPrescaler::Div16 => Hpre::DIV16,
|
|
||||||
AHBPrescaler::Div64 => Hpre::DIV64,
|
|
||||||
AHBPrescaler::Div128 => Hpre::DIV128,
|
|
||||||
AHBPrescaler::Div256 => Hpre::DIV256,
|
|
||||||
AHBPrescaler::Div512 => Hpre::DIV512,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
|
||||||
impl From<AHBPrescaler> for u8 {
|
|
||||||
fn from(val: AHBPrescaler) -> u8 {
|
|
||||||
match val {
|
|
||||||
AHBPrescaler::NotDivided => 0x0,
|
|
||||||
AHBPrescaler::Div2 => 0x08,
|
|
||||||
AHBPrescaler::Div3 => 0x01,
|
|
||||||
AHBPrescaler::Div4 => 0x09,
|
|
||||||
AHBPrescaler::Div5 => 0x02,
|
|
||||||
AHBPrescaler::Div6 => 0x05,
|
|
||||||
AHBPrescaler::Div8 => 0x0a,
|
|
||||||
AHBPrescaler::Div10 => 0x06,
|
|
||||||
AHBPrescaler::Div16 => 0x0b,
|
|
||||||
AHBPrescaler::Div32 => 0x07,
|
|
||||||
AHBPrescaler::Div64 => 0x0c,
|
|
||||||
AHBPrescaler::Div128 => 0x0d,
|
|
||||||
AHBPrescaler::Div256 => 0x0e,
|
|
||||||
AHBPrescaler::Div512 => 0x0f,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// APB prescaler
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum APBPrescaler {
|
|
||||||
NotDivided,
|
|
||||||
Div2,
|
|
||||||
Div4,
|
|
||||||
Div8,
|
|
||||||
Div16,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Div<APBPrescaler> for Hertz {
|
impl Div<APBPrescaler> for Hertz {
|
||||||
type Output = Hertz;
|
type Output = Hertz;
|
||||||
|
|
||||||
fn div(self, rhs: APBPrescaler) -> Self::Output {
|
fn div(self, rhs: APBPrescaler) -> Self::Output {
|
||||||
let divisor = match rhs {
|
let divisor = match rhs {
|
||||||
APBPrescaler::NotDivided => 1,
|
APBPrescaler::DIV1 => 1,
|
||||||
APBPrescaler::Div2 => 2,
|
APBPrescaler::DIV2 => 2,
|
||||||
APBPrescaler::Div4 => 4,
|
APBPrescaler::DIV4 => 4,
|
||||||
APBPrescaler::Div8 => 8,
|
APBPrescaler::DIV8 => 8,
|
||||||
APBPrescaler::Div16 => 16,
|
APBPrescaler::DIV16 => 16,
|
||||||
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
Hertz(self.0 / divisor)
|
Hertz(self.0 / divisor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(rcc_f1, rcc_f100, rcc_f1cl, rcc_g4, rcc_h7, rcc_h7ab, rcc_wb, rcc_wl5, rcc_wle)))]
|
|
||||||
impl From<APBPrescaler> for rcc::vals::Ppre {
|
|
||||||
fn from(val: APBPrescaler) -> rcc::vals::Ppre {
|
|
||||||
use rcc::vals::Ppre;
|
|
||||||
|
|
||||||
match val {
|
|
||||||
#[cfg(not(rcc_u5))]
|
|
||||||
APBPrescaler::NotDivided => Ppre::DIV1,
|
|
||||||
#[cfg(rcc_u5)]
|
|
||||||
APBPrescaler::NotDivided => Ppre::NONE,
|
|
||||||
APBPrescaler::Div2 => Ppre::DIV2,
|
|
||||||
APBPrescaler::Div4 => Ppre::DIV4,
|
|
||||||
APBPrescaler::Div8 => Ppre::DIV8,
|
|
||||||
APBPrescaler::Div16 => Ppre::DIV16,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
|
|
||||||
impl From<APBPrescaler> for u8 {
|
|
||||||
fn from(val: APBPrescaler) -> u8 {
|
|
||||||
match val {
|
|
||||||
APBPrescaler::NotDivided => 1,
|
|
||||||
APBPrescaler::Div2 => 0x04,
|
|
||||||
APBPrescaler::Div4 => 0x05,
|
|
||||||
APBPrescaler::Div8 => 0x06,
|
|
||||||
APBPrescaler::Div16 => 0x07,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -58,8 +58,8 @@ impl Default for Config {
|
|||||||
fn default() -> Config {
|
fn default() -> Config {
|
||||||
Config {
|
Config {
|
||||||
mux: ClockSrc::HSI(HSIPrescaler::NotDivided),
|
mux: ClockSrc::HSI(HSIPrescaler::NotDivided),
|
||||||
ahb_pre: AHBPrescaler::NotDivided,
|
ahb_pre: AHBPrescaler::DIV1,
|
||||||
apb_pre: APBPrescaler::NotDivided,
|
apb_pre: APBPrescaler::DIV1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,20 +151,21 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let ahb_div = match config.ahb_pre {
|
let ahb_div = match config.ahb_pre {
|
||||||
AHBPrescaler::NotDivided => 1,
|
AHBPrescaler::DIV1 => 1,
|
||||||
AHBPrescaler::Div2 => 2,
|
AHBPrescaler::DIV2 => 2,
|
||||||
AHBPrescaler::Div4 => 4,
|
AHBPrescaler::DIV4 => 4,
|
||||||
AHBPrescaler::Div8 => 8,
|
AHBPrescaler::DIV8 => 8,
|
||||||
AHBPrescaler::Div16 => 16,
|
AHBPrescaler::DIV16 => 16,
|
||||||
AHBPrescaler::Div64 => 64,
|
AHBPrescaler::DIV64 => 64,
|
||||||
AHBPrescaler::Div128 => 128,
|
AHBPrescaler::DIV128 => 128,
|
||||||
AHBPrescaler::Div256 => 256,
|
AHBPrescaler::DIV256 => 256,
|
||||||
AHBPrescaler::Div512 => 512,
|
AHBPrescaler::DIV512 => 512,
|
||||||
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
let ahb_freq = sys_clk / ahb_div;
|
let ahb_freq = sys_clk / ahb_div;
|
||||||
|
|
||||||
let (apb_freq, apb_tim_freq) = match config.apb_pre {
|
let (apb_freq, apb_tim_freq) = match config.apb_pre {
|
||||||
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
|
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||||
pre => {
|
pre => {
|
||||||
let pre: Ppre = pre.into();
|
let pre: Ppre = pre.into();
|
||||||
let pre: u8 = 1 << (pre.to_bits() - 3);
|
let pre: u8 = 1 << (pre.to_bits() - 3);
|
||||||
|
@ -163,8 +163,8 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
// Only needed for stm32f103?
|
// Only needed for stm32f103?
|
||||||
RCC.cfgr().modify(|w| {
|
RCC.cfgr().modify(|w| {
|
||||||
w.set_adcpre(Adcpre::from_bits(apre_bits));
|
w.set_adcpre(Adcpre::from_bits(apre_bits));
|
||||||
w.set_ppre2(Ppre1::from_bits(ppre2_bits));
|
w.set_ppre2(Ppre::from_bits(ppre2_bits));
|
||||||
w.set_ppre1(Ppre1::from_bits(ppre1_bits));
|
w.set_ppre1(Ppre::from_bits(ppre1_bits));
|
||||||
w.set_hpre(Hpre::from_bits(hpre_bits));
|
w.set_hpre(Hpre::from_bits(hpre_bits));
|
||||||
#[cfg(not(rcc_f100))]
|
#[cfg(not(rcc_f100))]
|
||||||
w.set_usbpre(Usbpre::from_bits(usbpre as u8));
|
w.set_usbpre(Usbpre::from_bits(usbpre as u8));
|
||||||
|
@ -4,7 +4,7 @@ use core::ops::{Div, Mul};
|
|||||||
pub use super::bus::{AHBPrescaler, APBPrescaler};
|
pub use super::bus::{AHBPrescaler, APBPrescaler};
|
||||||
use crate::pac::flash::vals::Latency;
|
use crate::pac::flash::vals::Latency;
|
||||||
use crate::pac::rcc::vals::{Pllp, Pllsrc, Sw};
|
use crate::pac::rcc::vals::{Pllp, Pllsrc, Sw};
|
||||||
use crate::pac::{FLASH, PWR, RCC};
|
use crate::pac::{FLASH, RCC};
|
||||||
use crate::rcc::bd::BackupDomain;
|
use crate::rcc::bd::BackupDomain;
|
||||||
use crate::rcc::{set_freqs, Clocks};
|
use crate::rcc::{set_freqs, Clocks};
|
||||||
use crate::rtc::RtcClockSource;
|
use crate::rtc::RtcClockSource;
|
||||||
@ -203,7 +203,20 @@ pub struct PLLClocks {
|
|||||||
pub pll48_freq: Hertz,
|
pub pll48_freq: Hertz,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use super::bus::VoltageScale;
|
/// Voltage range of the power supply used.
|
||||||
|
///
|
||||||
|
/// Used to calculate flash waitstates. See
|
||||||
|
/// RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock frequency
|
||||||
|
pub enum VoltageScale {
|
||||||
|
/// 2.7 to 3.6 V
|
||||||
|
Range0,
|
||||||
|
/// 2.4 to 2.7 V
|
||||||
|
Range1,
|
||||||
|
/// 2.1 to 2.4 V
|
||||||
|
Range2,
|
||||||
|
/// 1.8 to 2.1 V
|
||||||
|
Range3,
|
||||||
|
}
|
||||||
|
|
||||||
impl VoltageScale {
|
impl VoltageScale {
|
||||||
const fn wait_states(&self, ahb_freq: Hertz) -> Option<Latency> {
|
const fn wait_states(&self, ahb_freq: Hertz) -> Option<Latency> {
|
||||||
@ -211,7 +224,7 @@ impl VoltageScale {
|
|||||||
// Reference: RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock
|
// Reference: RM0033 - Table 3. Number of wait states according to Cortex®-M3 clock
|
||||||
// frequency
|
// frequency
|
||||||
match self {
|
match self {
|
||||||
VoltageScale::Scale3 => {
|
VoltageScale::Range3 => {
|
||||||
if ahb_freq <= 16_000_000 {
|
if ahb_freq <= 16_000_000 {
|
||||||
Some(Latency::WS0)
|
Some(Latency::WS0)
|
||||||
} else if ahb_freq <= 32_000_000 {
|
} else if ahb_freq <= 32_000_000 {
|
||||||
@ -232,7 +245,7 @@ impl VoltageScale {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VoltageScale::Scale2 => {
|
VoltageScale::Range2 => {
|
||||||
if ahb_freq <= 18_000_000 {
|
if ahb_freq <= 18_000_000 {
|
||||||
Some(Latency::WS0)
|
Some(Latency::WS0)
|
||||||
} else if ahb_freq <= 36_000_000 {
|
} else if ahb_freq <= 36_000_000 {
|
||||||
@ -251,7 +264,7 @@ impl VoltageScale {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VoltageScale::Scale1 => {
|
VoltageScale::Range1 => {
|
||||||
if ahb_freq <= 24_000_000 {
|
if ahb_freq <= 24_000_000 {
|
||||||
Some(Latency::WS0)
|
Some(Latency::WS0)
|
||||||
} else if ahb_freq <= 48_000_000 {
|
} else if ahb_freq <= 48_000_000 {
|
||||||
@ -266,7 +279,7 @@ impl VoltageScale {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VoltageScale::Scale0 => {
|
VoltageScale::Range0 => {
|
||||||
if ahb_freq <= 30_000_000 {
|
if ahb_freq <= 30_000_000 {
|
||||||
Some(Latency::WS0)
|
Some(Latency::WS0)
|
||||||
} else if ahb_freq <= 60_000_000 {
|
} else if ahb_freq <= 60_000_000 {
|
||||||
@ -291,6 +304,8 @@ pub struct Config {
|
|||||||
pub pll: PLLConfig,
|
pub pll: PLLConfig,
|
||||||
pub mux: ClockSrc,
|
pub mux: ClockSrc,
|
||||||
pub rtc: Option<RtcClockSource>,
|
pub rtc: Option<RtcClockSource>,
|
||||||
|
pub lsi: bool,
|
||||||
|
pub lse: Option<Hertz>,
|
||||||
pub voltage: VoltageScale,
|
pub voltage: VoltageScale,
|
||||||
pub ahb_pre: AHBPrescaler,
|
pub ahb_pre: AHBPrescaler,
|
||||||
pub apb1_pre: APBPrescaler,
|
pub apb1_pre: APBPrescaler,
|
||||||
@ -305,12 +320,14 @@ impl Default for Config {
|
|||||||
hsi: true,
|
hsi: true,
|
||||||
pll_mux: PLLSrc::HSI,
|
pll_mux: PLLSrc::HSI,
|
||||||
pll: PLLConfig::default(),
|
pll: PLLConfig::default(),
|
||||||
voltage: VoltageScale::Scale3,
|
voltage: VoltageScale::Range3,
|
||||||
mux: ClockSrc::HSI,
|
mux: ClockSrc::HSI,
|
||||||
rtc: None,
|
rtc: None,
|
||||||
ahb_pre: AHBPrescaler::NotDivided,
|
lsi: false,
|
||||||
apb1_pre: APBPrescaler::NotDivided,
|
lse: None,
|
||||||
apb2_pre: APBPrescaler::NotDivided,
|
ahb_pre: AHBPrescaler::DIV1,
|
||||||
|
apb1_pre: APBPrescaler::DIV1,
|
||||||
|
apb2_pre: APBPrescaler::DIV1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -383,7 +400,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
assert!(ahb_freq <= Hertz(120_000_000));
|
assert!(ahb_freq <= Hertz(120_000_000));
|
||||||
|
|
||||||
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
|
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
|
||||||
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
|
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||||
pre => {
|
pre => {
|
||||||
let freq = ahb_freq / pre;
|
let freq = ahb_freq / pre;
|
||||||
(freq, Hertz(freq.0 * 2))
|
(freq, Hertz(freq.0 * 2))
|
||||||
@ -393,7 +410,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
assert!(apb1_freq <= Hertz(30_000_000));
|
assert!(apb1_freq <= Hertz(30_000_000));
|
||||||
|
|
||||||
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
|
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
|
||||||
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
|
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||||
pre => {
|
pre => {
|
||||||
let freq = ahb_freq / pre;
|
let freq = ahb_freq / pre;
|
||||||
(freq, Hertz(freq.0 * 2))
|
(freq, Hertz(freq.0 * 2))
|
||||||
@ -418,12 +435,11 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
RCC.cr().modify(|w| w.set_hsion(false));
|
RCC.cr().modify(|w| w.set_hsion(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
RCC.apb1enr().modify(|w| w.set_pwren(true));
|
BackupDomain::configure_ls(
|
||||||
PWR.cr().read();
|
config.rtc.unwrap_or(RtcClockSource::NOCLOCK),
|
||||||
|
config.lsi,
|
||||||
config
|
config.lse.map(|_| Default::default()),
|
||||||
.rtc
|
);
|
||||||
.map(|clock_source| BackupDomain::configure_ls(clock_source, None));
|
|
||||||
|
|
||||||
set_freqs(Clocks {
|
set_freqs(Clocks {
|
||||||
sys: sys_clk,
|
sys: sys_clk,
|
||||||
|
@ -280,7 +280,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
#[cfg(rcc_f3)]
|
#[cfg(all(rcc_f3, adc3_common))]
|
||||||
let adc34 = config.adc.map(|adc| {
|
let adc34 = config.adc.map(|adc| {
|
||||||
if !adc.is_bus() {
|
if !adc.is_bus() {
|
||||||
RCC.cfgr2().modify(|w| {
|
RCC.cfgr2().modify(|w| {
|
||||||
@ -291,9 +291,13 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
Hertz(sysclk / adc as u32)
|
Hertz(sysclk / adc as u32)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
// TODO: need to use only if adc32_common is present
|
crate::pac::ADC3_COMMON.ccr().modify(|w| {
|
||||||
|
assert!(!(adc.bus_div() == 1 && hpre_bits != Hpre::DIV1));
|
||||||
|
|
||||||
todo!()
|
w.set_ckmode(adc.into());
|
||||||
|
|
||||||
|
Hertz(sysclk / adc.bus_div() as u32)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -323,8 +327,10 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
ahb1: Hertz(hclk),
|
ahb1: Hertz(hclk),
|
||||||
#[cfg(rcc_f3)]
|
#[cfg(rcc_f3)]
|
||||||
adc: adc,
|
adc: adc,
|
||||||
#[cfg(rcc_f3)]
|
#[cfg(all(rcc_f3, adc3_common))]
|
||||||
adc34: adc34,
|
adc34: adc34,
|
||||||
|
#[cfg(all(rcc_f3, not(adc3_common)))]
|
||||||
|
adc34: None,
|
||||||
#[cfg(stm32f334)]
|
#[cfg(stm32f334)]
|
||||||
hrtim: hrtim,
|
hrtim: hrtim,
|
||||||
});
|
});
|
||||||
|
@ -3,7 +3,6 @@ use core::marker::PhantomData;
|
|||||||
use embassy_hal_internal::into_ref;
|
use embassy_hal_internal::into_ref;
|
||||||
use stm32_metapac::rcc::vals::{Mco1, Mco2, Mcopre};
|
use stm32_metapac::rcc::vals::{Mco1, Mco2, Mcopre};
|
||||||
|
|
||||||
use super::sealed::RccPeripheral;
|
|
||||||
use crate::gpio::sealed::AFType;
|
use crate::gpio::sealed::AFType;
|
||||||
use crate::gpio::Speed;
|
use crate::gpio::Speed;
|
||||||
use crate::pac::rcc::vals::{Hpre, Ppre, Sw};
|
use crate::pac::rcc::vals::{Hpre, Ppre, Sw};
|
||||||
@ -33,8 +32,13 @@ pub struct Config {
|
|||||||
#[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))]
|
#[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))]
|
||||||
pub plli2s: Option<Hertz>,
|
pub plli2s: Option<Hertz>,
|
||||||
|
|
||||||
|
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
|
||||||
|
pub pllsai: Option<Hertz>,
|
||||||
|
|
||||||
pub pll48: bool,
|
pub pll48: bool,
|
||||||
pub rtc: Option<RtcClockSource>,
|
pub rtc: Option<RtcClockSource>,
|
||||||
|
pub lsi: bool,
|
||||||
|
pub lse: Option<Hertz>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(stm32f410)]
|
#[cfg(stm32f410)]
|
||||||
@ -48,11 +52,10 @@ fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))]
|
#[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423)))]
|
||||||
fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> {
|
fn calculate_sai_i2s_pll_values(vco_in: u32, max_div: u32, target: Option<u32>) -> Option<(u32, u32, u32)> {
|
||||||
let min_div = 2;
|
let min_div = 2;
|
||||||
let max_div = 7;
|
let target = match target {
|
||||||
let target = match plli2s {
|
|
||||||
Some(target) => target,
|
Some(target) => target,
|
||||||
None => return None,
|
None => return None,
|
||||||
};
|
};
|
||||||
@ -76,15 +79,48 @@ fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> {
|
|||||||
})
|
})
|
||||||
.min_by_key(|(_, _, _, error)| *error)?;
|
.min_by_key(|(_, _, _, error)| *error)?;
|
||||||
|
|
||||||
|
Some((n, outdiv, output))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))]
|
||||||
|
fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> {
|
||||||
|
let (n, outdiv, output) = calculate_sai_i2s_pll_values(vco_in, 7, plli2s)?;
|
||||||
|
|
||||||
RCC.plli2scfgr().modify(|w| {
|
RCC.plli2scfgr().modify(|w| {
|
||||||
w.set_plli2sn(n as u16);
|
w.set_plli2sn(n as u16);
|
||||||
w.set_plli2sr(outdiv as u8);
|
w.set_plli2sr(outdiv as u8);
|
||||||
|
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
|
||||||
|
w.set_plli2sq(outdiv as u8); //set sai divider same as i2s
|
||||||
});
|
});
|
||||||
|
|
||||||
Some(output)
|
Some(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, plli2s: Option<u32>, pll48clk: bool) -> PllResults {
|
#[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479)))]
|
||||||
|
fn setup_sai_pll(_vco_in: u32, _pllsai: Option<u32>) -> Option<u32> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
|
||||||
|
fn setup_sai_pll(vco_in: u32, pllsai: Option<u32>) -> Option<u32> {
|
||||||
|
let (n, outdiv, output) = calculate_sai_i2s_pll_values(vco_in, 15, pllsai)?;
|
||||||
|
|
||||||
|
RCC.pllsaicfgr().modify(|w| {
|
||||||
|
w.set_pllsain(n as u16);
|
||||||
|
w.set_pllsaiq(outdiv as u8);
|
||||||
|
});
|
||||||
|
|
||||||
|
Some(output)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_pll(
|
||||||
|
pllsrcclk: u32,
|
||||||
|
use_hse: bool,
|
||||||
|
pllsysclk: Option<u32>,
|
||||||
|
plli2s: Option<u32>,
|
||||||
|
pllsai: Option<u32>,
|
||||||
|
pll48clk: bool,
|
||||||
|
) -> PllResults {
|
||||||
use crate::pac::rcc::vals::{Pllp, Pllsrc};
|
use crate::pac::rcc::vals::{Pllp, Pllsrc};
|
||||||
|
|
||||||
let sysclk = pllsysclk.unwrap_or(pllsrcclk);
|
let sysclk = pllsysclk.unwrap_or(pllsrcclk);
|
||||||
@ -96,6 +132,7 @@ fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, plli2s: Opti
|
|||||||
pllsysclk: None,
|
pllsysclk: None,
|
||||||
pll48clk: None,
|
pll48clk: None,
|
||||||
plli2sclk: None,
|
plli2sclk: None,
|
||||||
|
pllsaiclk: None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// Input divisor from PLL source clock, must result to frequency in
|
// Input divisor from PLL source clock, must result to frequency in
|
||||||
@ -146,6 +183,7 @@ fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, plli2s: Opti
|
|||||||
w.set_pllp(Pllp::from_bits(pllp as u8));
|
w.set_pllp(Pllp::from_bits(pllp as u8));
|
||||||
w.set_pllq(pllq as u8);
|
w.set_pllq(pllq as u8);
|
||||||
w.set_pllsrc(Pllsrc::from_bits(use_hse as u8));
|
w.set_pllsrc(Pllsrc::from_bits(use_hse as u8));
|
||||||
|
w.set_pllr(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
let real_pllsysclk = vco_in * plln / sysclk_div;
|
let real_pllsysclk = vco_in * plln / sysclk_div;
|
||||||
@ -155,6 +193,7 @@ fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, plli2s: Opti
|
|||||||
pllsysclk: Some(real_pllsysclk),
|
pllsysclk: Some(real_pllsysclk),
|
||||||
pll48clk: if pll48clk { Some(real_pll48clk) } else { None },
|
pll48clk: if pll48clk { Some(real_pll48clk) } else { None },
|
||||||
plli2sclk: setup_i2s_pll(vco_in, plli2s),
|
plli2sclk: setup_i2s_pll(vco_in, plli2s),
|
||||||
|
pllsaiclk: setup_sai_pll(vco_in, pllsai),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,8 +369,6 @@ fn flash_setup(sysclk: u32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn init(config: Config) {
|
pub(crate) unsafe fn init(config: Config) {
|
||||||
crate::peripherals::PWR::enable();
|
|
||||||
|
|
||||||
let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI_FREQ.0);
|
let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI_FREQ.0);
|
||||||
let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
|
let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
|
||||||
let sysclk_on_pll = sysclk != pllsrcclk;
|
let sysclk_on_pll = sysclk != pllsrcclk;
|
||||||
@ -344,6 +381,10 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
config.plli2s.map(|i2s| i2s.0),
|
config.plli2s.map(|i2s| i2s.0),
|
||||||
#[cfg(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446))]
|
#[cfg(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446))]
|
||||||
None,
|
None,
|
||||||
|
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
|
||||||
|
config.pllsai.map(|sai| sai.0),
|
||||||
|
#[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479)))]
|
||||||
|
None,
|
||||||
config.pll48,
|
config.pll48,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -441,6 +482,12 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
while !RCC.cr().read().plli2srdy() {}
|
while !RCC.cr().read().plli2srdy() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
|
||||||
|
if plls.pllsaiclk.is_some() {
|
||||||
|
RCC.cr().modify(|w| w.set_pllsaion(true));
|
||||||
|
while !RCC.cr().read().pllsairdy() {}
|
||||||
|
}
|
||||||
|
|
||||||
RCC.cfgr().modify(|w| {
|
RCC.cfgr().modify(|w| {
|
||||||
w.set_ppre2(Ppre::from_bits(ppre2_bits));
|
w.set_ppre2(Ppre::from_bits(ppre2_bits));
|
||||||
w.set_ppre1(Ppre::from_bits(ppre1_bits));
|
w.set_ppre1(Ppre::from_bits(ppre1_bits));
|
||||||
@ -461,12 +508,15 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
config
|
BackupDomain::configure_ls(
|
||||||
.rtc
|
config.rtc.unwrap_or(RtcClockSource::NOCLOCK),
|
||||||
.map(|clock_source| BackupDomain::configure_ls(clock_source, None));
|
config.lsi,
|
||||||
|
config.lse.map(|_| Default::default()),
|
||||||
|
);
|
||||||
|
|
||||||
let rtc = match config.rtc {
|
let rtc = match config.rtc {
|
||||||
Some(RtcClockSource::LSI) => Some(LSI_FREQ),
|
Some(RtcClockSource::LSI) => Some(LSI_FREQ),
|
||||||
|
Some(RtcClockSource::LSE) => Some(config.lse.unwrap()),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -488,7 +538,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
plli2s: plls.plli2sclk.map(Hertz),
|
plli2s: plls.plli2sclk.map(Hertz),
|
||||||
|
|
||||||
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
|
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
|
||||||
pllsai: None,
|
pllsai: plls.pllsaiclk.map(Hertz),
|
||||||
|
|
||||||
rtc: rtc,
|
rtc: rtc,
|
||||||
rtc_hse: None,
|
rtc_hse: None,
|
||||||
@ -501,6 +551,8 @@ struct PllResults {
|
|||||||
pll48clk: Option<u32>,
|
pll48clk: Option<u32>,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
plli2sclk: Option<u32>,
|
plli2sclk: Option<u32>,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pllsaiclk: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
mod max {
|
mod max {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::sealed::RccPeripheral;
|
|
||||||
use crate::pac::pwr::vals::Vos;
|
use crate::pac::pwr::vals::Vos;
|
||||||
use crate::pac::rcc::vals::{Hpre, Ppre, Sw};
|
use crate::pac::rcc::vals::{Hpre, Ppre, Sw};
|
||||||
use crate::pac::{FLASH, PWR, RCC};
|
use crate::pac::{FLASH, PWR, RCC};
|
||||||
|
use crate::rcc::bd::{BackupDomain, RtcClockSource};
|
||||||
use crate::rcc::{set_freqs, Clocks};
|
use crate::rcc::{set_freqs, Clocks};
|
||||||
use crate::time::Hertz;
|
use crate::time::Hertz;
|
||||||
|
|
||||||
@ -23,6 +23,9 @@ pub struct Config {
|
|||||||
pub pclk2: Option<Hertz>,
|
pub pclk2: Option<Hertz>,
|
||||||
|
|
||||||
pub pll48: bool,
|
pub pll48: bool,
|
||||||
|
pub rtc: Option<RtcClockSource>,
|
||||||
|
pub lsi: bool,
|
||||||
|
pub lse: Option<Hertz>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults {
|
fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults {
|
||||||
@ -111,8 +114,6 @@ fn flash_setup(sysclk: u32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn init(config: Config) {
|
pub(crate) unsafe fn init(config: Config) {
|
||||||
crate::peripherals::PWR::enable();
|
|
||||||
|
|
||||||
if let Some(hse) = config.hse {
|
if let Some(hse) = config.hse {
|
||||||
if config.bypass_hse {
|
if config.bypass_hse {
|
||||||
assert!((max::HSE_BYPASS_MIN..=max::HSE_BYPASS_MAX).contains(&hse.0));
|
assert!((max::HSE_BYPASS_MIN..=max::HSE_BYPASS_MAX).contains(&hse.0));
|
||||||
@ -212,10 +213,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
if plls.use_pll {
|
if plls.use_pll {
|
||||||
RCC.cr().modify(|w| w.set_pllon(false));
|
RCC.cr().modify(|w| w.set_pllon(false));
|
||||||
|
|
||||||
// enable PWR and setup VOSScale
|
// setup VOSScale
|
||||||
|
|
||||||
RCC.apb1enr().modify(|w| w.set_pwren(true));
|
|
||||||
|
|
||||||
let vos_scale = if sysclk <= 144_000_000 {
|
let vos_scale = if sysclk <= 144_000_000 {
|
||||||
3
|
3
|
||||||
} else if sysclk <= 168_000_000 {
|
} else if sysclk <= 168_000_000 {
|
||||||
@ -265,6 +263,18 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
BackupDomain::configure_ls(
|
||||||
|
config.rtc.unwrap_or(RtcClockSource::NOCLOCK),
|
||||||
|
config.lsi,
|
||||||
|
config.lse.map(|_| Default::default()),
|
||||||
|
);
|
||||||
|
|
||||||
|
let rtc = match config.rtc {
|
||||||
|
Some(RtcClockSource::LSI) => Some(LSI_FREQ),
|
||||||
|
Some(RtcClockSource::LSE) => Some(config.lse.unwrap()),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
set_freqs(Clocks {
|
set_freqs(Clocks {
|
||||||
sys: Hertz(sysclk),
|
sys: Hertz(sysclk),
|
||||||
apb1: Hertz(pclk1),
|
apb1: Hertz(pclk1),
|
||||||
@ -278,6 +288,8 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
ahb3: Hertz(hclk),
|
ahb3: Hertz(hclk),
|
||||||
|
|
||||||
pll48: plls.pll48clk.map(Hertz),
|
pll48: plls.pll48clk.map(Hertz),
|
||||||
|
|
||||||
|
rtc,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,8 +186,8 @@ impl Default for Config {
|
|||||||
fn default() -> Config {
|
fn default() -> Config {
|
||||||
Config {
|
Config {
|
||||||
mux: ClockSrc::HSI16(HSI16Prescaler::NotDivided),
|
mux: ClockSrc::HSI16(HSI16Prescaler::NotDivided),
|
||||||
ahb_pre: AHBPrescaler::NotDivided,
|
ahb_pre: AHBPrescaler::DIV1,
|
||||||
apb_pre: APBPrescaler::NotDivided,
|
apb_pre: APBPrescaler::DIV1,
|
||||||
low_power_run: false,
|
low_power_run: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -377,7 +377,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
let ahb_freq = Hertz(sys_clk) / config.ahb_pre;
|
let ahb_freq = Hertz(sys_clk) / config.ahb_pre;
|
||||||
|
|
||||||
let (apb_freq, apb_tim_freq) = match config.apb_pre {
|
let (apb_freq, apb_tim_freq) = match config.apb_pre {
|
||||||
APBPrescaler::NotDivided => (ahb_freq.0, ahb_freq.0),
|
APBPrescaler::DIV1 => (ahb_freq.0, ahb_freq.0),
|
||||||
pre => {
|
pre => {
|
||||||
let pre: Ppre = pre.into();
|
let pre: Ppre = pre.into();
|
||||||
let pre: u8 = 1 << (pre.to_bits() - 3);
|
let pre: u8 = 1 << (pre.to_bits() - 3);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use stm32_metapac::flash::vals::Latency;
|
use stm32_metapac::flash::vals::Latency;
|
||||||
use stm32_metapac::rcc::vals::{Adcsel, Hpre, Pllsrc, Ppre, Sw};
|
use stm32_metapac::rcc::vals::{Adcsel, Pllsrc, Sw};
|
||||||
use stm32_metapac::FLASH;
|
use stm32_metapac::FLASH;
|
||||||
|
|
||||||
pub use super::bus::{AHBPrescaler, APBPrescaler};
|
pub use super::bus::{AHBPrescaler, APBPrescaler};
|
||||||
@ -261,59 +261,29 @@ pub struct Pll {
|
|||||||
pub div_r: Option<PllR>,
|
pub div_r: Option<PllR>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AHBPrescaler {
|
fn ahb_div(ahb: AHBPrescaler) -> u32 {
|
||||||
const fn div(self) -> u32 {
|
match ahb {
|
||||||
match self {
|
AHBPrescaler::DIV1 => 1,
|
||||||
AHBPrescaler::NotDivided => 1,
|
AHBPrescaler::DIV2 => 2,
|
||||||
AHBPrescaler::Div2 => 2,
|
AHBPrescaler::DIV4 => 4,
|
||||||
AHBPrescaler::Div4 => 4,
|
AHBPrescaler::DIV8 => 8,
|
||||||
AHBPrescaler::Div8 => 8,
|
AHBPrescaler::DIV16 => 16,
|
||||||
AHBPrescaler::Div16 => 16,
|
AHBPrescaler::DIV64 => 64,
|
||||||
AHBPrescaler::Div64 => 64,
|
AHBPrescaler::DIV128 => 128,
|
||||||
AHBPrescaler::Div128 => 128,
|
AHBPrescaler::DIV256 => 256,
|
||||||
AHBPrescaler::Div256 => 256,
|
AHBPrescaler::DIV512 => 512,
|
||||||
AHBPrescaler::Div512 => 512,
|
_ => unreachable!(),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl APBPrescaler {
|
fn apb_div(apb: APBPrescaler) -> u32 {
|
||||||
const fn div(self) -> u32 {
|
match apb {
|
||||||
match self {
|
APBPrescaler::DIV1 => 1,
|
||||||
APBPrescaler::NotDivided => 1,
|
APBPrescaler::DIV2 => 2,
|
||||||
APBPrescaler::Div2 => 2,
|
APBPrescaler::DIV4 => 4,
|
||||||
APBPrescaler::Div4 => 4,
|
APBPrescaler::DIV8 => 8,
|
||||||
APBPrescaler::Div8 => 8,
|
APBPrescaler::DIV16 => 16,
|
||||||
APBPrescaler::Div16 => 16,
|
_ => unreachable!(),
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<Ppre> for APBPrescaler {
|
|
||||||
fn into(self) -> Ppre {
|
|
||||||
match self {
|
|
||||||
APBPrescaler::NotDivided => Ppre::DIV1,
|
|
||||||
APBPrescaler::Div2 => Ppre::DIV2,
|
|
||||||
APBPrescaler::Div4 => Ppre::DIV4,
|
|
||||||
APBPrescaler::Div8 => Ppre::DIV8,
|
|
||||||
APBPrescaler::Div16 => Ppre::DIV16,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<Hpre> for AHBPrescaler {
|
|
||||||
fn into(self) -> Hpre {
|
|
||||||
match self {
|
|
||||||
AHBPrescaler::NotDivided => Hpre::DIV1,
|
|
||||||
AHBPrescaler::Div2 => Hpre::DIV2,
|
|
||||||
AHBPrescaler::Div4 => Hpre::DIV4,
|
|
||||||
AHBPrescaler::Div8 => Hpre::DIV8,
|
|
||||||
AHBPrescaler::Div16 => Hpre::DIV16,
|
|
||||||
AHBPrescaler::Div64 => Hpre::DIV64,
|
|
||||||
AHBPrescaler::Div128 => Hpre::DIV128,
|
|
||||||
AHBPrescaler::Div256 => Hpre::DIV256,
|
|
||||||
AHBPrescaler::Div512 => Hpre::DIV512,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -365,9 +335,9 @@ impl Default for Config {
|
|||||||
fn default() -> Config {
|
fn default() -> Config {
|
||||||
Config {
|
Config {
|
||||||
mux: ClockSrc::HSI16,
|
mux: ClockSrc::HSI16,
|
||||||
ahb_pre: AHBPrescaler::NotDivided,
|
ahb_pre: AHBPrescaler::DIV1,
|
||||||
apb1_pre: APBPrescaler::NotDivided,
|
apb1_pre: APBPrescaler::DIV1,
|
||||||
apb2_pre: APBPrescaler::NotDivided,
|
apb2_pre: APBPrescaler::DIV1,
|
||||||
low_power_run: false,
|
low_power_run: false,
|
||||||
pll: None,
|
pll: None,
|
||||||
clock_48mhz_src: None,
|
clock_48mhz_src: None,
|
||||||
@ -512,22 +482,22 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let ahb_freq: u32 = match config.ahb_pre {
|
let ahb_freq: u32 = match config.ahb_pre {
|
||||||
AHBPrescaler::NotDivided => sys_clk,
|
AHBPrescaler::DIV1 => sys_clk,
|
||||||
pre => sys_clk / pre.div(),
|
pre => sys_clk / ahb_div(pre),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
|
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
|
||||||
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
|
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||||
pre => {
|
pre => {
|
||||||
let freq = ahb_freq / pre.div();
|
let freq = ahb_freq / apb_div(pre);
|
||||||
(freq, freq * 2)
|
(freq, freq * 2)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
|
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
|
||||||
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
|
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||||
pre => {
|
pre => {
|
||||||
let freq = ahb_freq / pre.div();
|
let freq = ahb_freq / apb_div(pre);
|
||||||
(freq, freq * 2)
|
(freq, freq * 2)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
772
embassy-stm32/src/rcc/h.rs
Normal file
772
embassy-stm32/src/rcc/h.rs
Normal file
@ -0,0 +1,772 @@
|
|||||||
|
use core::ops::RangeInclusive;
|
||||||
|
|
||||||
|
use crate::pac;
|
||||||
|
use crate::pac::pwr::vals::Vos;
|
||||||
|
#[cfg(stm32h5)]
|
||||||
|
pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource;
|
||||||
|
#[cfg(stm32h7)]
|
||||||
|
pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
|
||||||
|
pub use crate::pac::rcc::vals::Ckpersel as PerClockSource;
|
||||||
|
use crate::pac::rcc::vals::{Ckpersel, Hsidiv, Pllrge, Pllsrc, Pllvcosel, Sw, Timpre};
|
||||||
|
use crate::pac::{FLASH, PWR, RCC};
|
||||||
|
use crate::rcc::{set_freqs, Clocks};
|
||||||
|
use crate::time::Hertz;
|
||||||
|
|
||||||
|
/// HSI speed
|
||||||
|
pub const HSI_FREQ: Hertz = Hertz(64_000_000);
|
||||||
|
|
||||||
|
/// CSI speed
|
||||||
|
pub const CSI_FREQ: Hertz = Hertz(4_000_000);
|
||||||
|
|
||||||
|
/// HSI48 speed
|
||||||
|
pub const HSI48_FREQ: Hertz = Hertz(48_000_000);
|
||||||
|
|
||||||
|
/// LSI speed
|
||||||
|
pub const LSI_FREQ: Hertz = Hertz(32_000);
|
||||||
|
|
||||||
|
const VCO_RANGE: RangeInclusive<u32> = 150_000_000..=420_000_000;
|
||||||
|
#[cfg(any(stm32h5, pwr_h7rm0455))]
|
||||||
|
const VCO_WIDE_RANGE: RangeInclusive<u32> = 128_000_000..=560_000_000;
|
||||||
|
#[cfg(pwr_h7rm0468)]
|
||||||
|
const VCO_WIDE_RANGE: RangeInclusive<u32> = 192_000_000..=836_000_000;
|
||||||
|
#[cfg(any(pwr_h7rm0399, pwr_h7rm0433))]
|
||||||
|
const VCO_WIDE_RANGE: RangeInclusive<u32> = 192_000_000..=960_000_000;
|
||||||
|
|
||||||
|
pub use super::bus::{AHBPrescaler, APBPrescaler};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
|
pub enum VoltageScale {
|
||||||
|
Scale0,
|
||||||
|
Scale1,
|
||||||
|
Scale2,
|
||||||
|
Scale3,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
|
pub enum HseMode {
|
||||||
|
/// crystal/ceramic oscillator (HSEBYP=0)
|
||||||
|
Oscillator,
|
||||||
|
/// external analog clock (low swing) (HSEBYP=1, HSEEXT=0)
|
||||||
|
Bypass,
|
||||||
|
/// external digital clock (full swing) (HSEBYP=1, HSEEXT=1)
|
||||||
|
#[cfg(any(rcc_h5, rcc_h50))]
|
||||||
|
BypassDigital,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
|
pub struct Hse {
|
||||||
|
/// HSE frequency.
|
||||||
|
pub freq: Hertz,
|
||||||
|
/// HSE mode.
|
||||||
|
pub mode: HseMode,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
|
pub enum Hsi {
|
||||||
|
/// 64Mhz
|
||||||
|
Mhz64,
|
||||||
|
/// 32Mhz (divided by 2)
|
||||||
|
Mhz32,
|
||||||
|
/// 16Mhz (divided by 4)
|
||||||
|
Mhz16,
|
||||||
|
/// 8Mhz (divided by 8)
|
||||||
|
Mhz8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
|
pub enum Sysclk {
|
||||||
|
/// HSI selected as sysclk
|
||||||
|
HSI,
|
||||||
|
/// HSE selected as sysclk
|
||||||
|
HSE,
|
||||||
|
/// CSI selected as sysclk
|
||||||
|
CSI,
|
||||||
|
/// PLL1_P selected as sysclk
|
||||||
|
Pll1P,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
|
pub enum PllSource {
|
||||||
|
Hsi,
|
||||||
|
Csi,
|
||||||
|
Hse,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct Pll {
|
||||||
|
/// Source clock selection.
|
||||||
|
#[cfg(stm32h5)]
|
||||||
|
pub source: PllSource,
|
||||||
|
|
||||||
|
/// PLL pre-divider (DIVM). Must be between 1 and 63.
|
||||||
|
pub prediv: u8,
|
||||||
|
|
||||||
|
/// PLL multiplication factor. Must be between 4 and 512.
|
||||||
|
pub mul: u16,
|
||||||
|
|
||||||
|
/// PLL P division factor. If None, PLL P output is disabled. Must be between 1 and 128.
|
||||||
|
/// On PLL1, it must be even (in particular, it cannot be 1.)
|
||||||
|
pub divp: Option<u16>,
|
||||||
|
/// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128.
|
||||||
|
pub divq: Option<u16>,
|
||||||
|
/// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128.
|
||||||
|
pub divr: Option<u16>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apb_div_tim(apb: &APBPrescaler, clk: Hertz, tim: TimerPrescaler) -> Hertz {
|
||||||
|
match (tim, apb) {
|
||||||
|
(TimerPrescaler::DefaultX2, APBPrescaler::DIV1) => clk,
|
||||||
|
(TimerPrescaler::DefaultX2, APBPrescaler::DIV2) => clk,
|
||||||
|
(TimerPrescaler::DefaultX2, APBPrescaler::DIV4) => clk / 2u32,
|
||||||
|
(TimerPrescaler::DefaultX2, APBPrescaler::DIV8) => clk / 4u32,
|
||||||
|
(TimerPrescaler::DefaultX2, APBPrescaler::DIV16) => clk / 8u32,
|
||||||
|
|
||||||
|
(TimerPrescaler::DefaultX4, APBPrescaler::DIV1) => clk,
|
||||||
|
(TimerPrescaler::DefaultX4, APBPrescaler::DIV2) => clk,
|
||||||
|
(TimerPrescaler::DefaultX4, APBPrescaler::DIV4) => clk,
|
||||||
|
(TimerPrescaler::DefaultX4, APBPrescaler::DIV8) => clk / 2u32,
|
||||||
|
(TimerPrescaler::DefaultX4, APBPrescaler::DIV16) => clk / 4u32,
|
||||||
|
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Timer prescaler
|
||||||
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
|
pub enum TimerPrescaler {
|
||||||
|
/// The timers kernel clock is equal to hclk if PPREx corresponds to a
|
||||||
|
/// division by 1 or 2, else it is equal to 2*pclk
|
||||||
|
DefaultX2,
|
||||||
|
|
||||||
|
/// The timers kernel clock is equal to hclk if PPREx corresponds to a
|
||||||
|
/// division by 1, 2 or 4, else it is equal to 4*pclk
|
||||||
|
DefaultX4,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TimerPrescaler> for Timpre {
|
||||||
|
fn from(value: TimerPrescaler) -> Self {
|
||||||
|
match value {
|
||||||
|
TimerPrescaler::DefaultX2 => Timpre::DEFAULTX2,
|
||||||
|
TimerPrescaler::DefaultX4 => Timpre::DEFAULTX4,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configuration of the core clocks
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub struct Config {
|
||||||
|
pub hsi: Option<Hsi>,
|
||||||
|
pub hse: Option<Hse>,
|
||||||
|
pub csi: bool,
|
||||||
|
pub hsi48: bool,
|
||||||
|
pub sys: Sysclk,
|
||||||
|
|
||||||
|
#[cfg(stm32h7)]
|
||||||
|
pub pll_src: PllSource,
|
||||||
|
|
||||||
|
pub pll1: Option<Pll>,
|
||||||
|
pub pll2: Option<Pll>,
|
||||||
|
#[cfg(any(rcc_h5, stm32h7))]
|
||||||
|
pub pll3: Option<Pll>,
|
||||||
|
|
||||||
|
pub d1c_pre: AHBPrescaler,
|
||||||
|
pub ahb_pre: AHBPrescaler,
|
||||||
|
pub apb1_pre: APBPrescaler,
|
||||||
|
pub apb2_pre: APBPrescaler,
|
||||||
|
pub apb3_pre: APBPrescaler,
|
||||||
|
#[cfg(stm32h7)]
|
||||||
|
pub apb4_pre: APBPrescaler,
|
||||||
|
|
||||||
|
pub per_clock_source: PerClockSource,
|
||||||
|
pub adc_clock_source: AdcClockSource,
|
||||||
|
pub timer_prescaler: TimerPrescaler,
|
||||||
|
pub voltage_scale: VoltageScale,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Config {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
hsi: Some(Hsi::Mhz64),
|
||||||
|
hse: None,
|
||||||
|
csi: false,
|
||||||
|
hsi48: false,
|
||||||
|
sys: Sysclk::HSI,
|
||||||
|
#[cfg(stm32h7)]
|
||||||
|
pll_src: PllSource::Hsi,
|
||||||
|
pll1: None,
|
||||||
|
pll2: None,
|
||||||
|
#[cfg(any(rcc_h5, stm32h7))]
|
||||||
|
pll3: None,
|
||||||
|
|
||||||
|
d1c_pre: AHBPrescaler::DIV1,
|
||||||
|
ahb_pre: AHBPrescaler::DIV1,
|
||||||
|
apb1_pre: APBPrescaler::DIV1,
|
||||||
|
apb2_pre: APBPrescaler::DIV1,
|
||||||
|
apb3_pre: APBPrescaler::DIV1,
|
||||||
|
#[cfg(stm32h7)]
|
||||||
|
apb4_pre: APBPrescaler::DIV1,
|
||||||
|
|
||||||
|
per_clock_source: PerClockSource::HSI,
|
||||||
|
adc_clock_source: AdcClockSource::from_bits(0), // PLL2_P on H7, HCLK on H5
|
||||||
|
timer_prescaler: TimerPrescaler::DefaultX2,
|
||||||
|
voltage_scale: VoltageScale::Scale0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn init(config: Config) {
|
||||||
|
// NB. The lower bytes of CR3 can only be written once after
|
||||||
|
// POR, and must be written with a valid combination. Refer to
|
||||||
|
// RM0433 Rev 7 6.8.4. This is partially enforced by dropping
|
||||||
|
// `self` at the end of this method, but of course we cannot
|
||||||
|
// know what happened between the previous POR and here.
|
||||||
|
#[cfg(pwr_h7rm0433)]
|
||||||
|
PWR.cr3().modify(|w| {
|
||||||
|
w.set_scuen(true);
|
||||||
|
w.set_ldoen(true);
|
||||||
|
w.set_bypass(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
|
||||||
|
PWR.cr3().modify(|w| {
|
||||||
|
// hardcode "Direct SPMS" for now, this is what works on nucleos with the
|
||||||
|
// default solderbridge configuration.
|
||||||
|
w.set_sden(true);
|
||||||
|
w.set_ldoen(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Validate the supply configuration. If you are stuck here, it is
|
||||||
|
// because the voltages on your board do not match those specified
|
||||||
|
// in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset
|
||||||
|
// VOS = Scale 3, so check that the voltage on the VCAP pins =
|
||||||
|
// 1.0V.
|
||||||
|
#[cfg(any(pwr_h7rm0433, pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
|
||||||
|
while !PWR.csr1().read().actvosrdy() {}
|
||||||
|
|
||||||
|
// Configure voltage scale.
|
||||||
|
#[cfg(any(pwr_h5, pwr_h50))]
|
||||||
|
{
|
||||||
|
PWR.voscr().modify(|w| {
|
||||||
|
w.set_vos(match config.voltage_scale {
|
||||||
|
VoltageScale::Scale0 => Vos::SCALE0,
|
||||||
|
VoltageScale::Scale1 => Vos::SCALE1,
|
||||||
|
VoltageScale::Scale2 => Vos::SCALE2,
|
||||||
|
VoltageScale::Scale3 => Vos::SCALE3,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
while !PWR.vossr().read().vosrdy() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(syscfg_h7)]
|
||||||
|
{
|
||||||
|
// in chips without the overdrive bit, we can go from any scale to any scale directly.
|
||||||
|
PWR.d3cr().modify(|w| {
|
||||||
|
w.set_vos(match config.voltage_scale {
|
||||||
|
VoltageScale::Scale0 => Vos::SCALE0,
|
||||||
|
VoltageScale::Scale1 => Vos::SCALE1,
|
||||||
|
VoltageScale::Scale2 => Vos::SCALE2,
|
||||||
|
VoltageScale::Scale3 => Vos::SCALE3,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
while !PWR.d3cr().read().vosrdy() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(syscfg_h7od)]
|
||||||
|
{
|
||||||
|
match config.voltage_scale {
|
||||||
|
VoltageScale::Scale0 => {
|
||||||
|
// to go to scale0, we must go to Scale1 first...
|
||||||
|
PWR.d3cr().modify(|w| w.set_vos(Vos::SCALE1));
|
||||||
|
while !PWR.d3cr().read().vosrdy() {}
|
||||||
|
|
||||||
|
// Then enable overdrive.
|
||||||
|
critical_section::with(|_| pac::SYSCFG.pwrcr().modify(|w| w.set_oden(1)));
|
||||||
|
while !PWR.d3cr().read().vosrdy() {}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// for all other scales, we can go directly.
|
||||||
|
PWR.d3cr().modify(|w| {
|
||||||
|
w.set_vos(match config.voltage_scale {
|
||||||
|
VoltageScale::Scale0 => unreachable!(),
|
||||||
|
VoltageScale::Scale1 => Vos::SCALE1,
|
||||||
|
VoltageScale::Scale2 => Vos::SCALE2,
|
||||||
|
VoltageScale::Scale3 => Vos::SCALE3,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
while !PWR.d3cr().read().vosrdy() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure HSI
|
||||||
|
let hsi = match config.hsi {
|
||||||
|
None => {
|
||||||
|
RCC.cr().modify(|w| w.set_hsion(false));
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Some(hsi) => {
|
||||||
|
let (freq, hsidiv) = match hsi {
|
||||||
|
Hsi::Mhz64 => (HSI_FREQ / 1u32, Hsidiv::DIV1),
|
||||||
|
Hsi::Mhz32 => (HSI_FREQ / 2u32, Hsidiv::DIV2),
|
||||||
|
Hsi::Mhz16 => (HSI_FREQ / 4u32, Hsidiv::DIV4),
|
||||||
|
Hsi::Mhz8 => (HSI_FREQ / 8u32, Hsidiv::DIV8),
|
||||||
|
};
|
||||||
|
RCC.cr().modify(|w| {
|
||||||
|
w.set_hsidiv(hsidiv);
|
||||||
|
w.set_hsion(true);
|
||||||
|
});
|
||||||
|
while !RCC.cr().read().hsirdy() {}
|
||||||
|
Some(freq)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Configure HSE
|
||||||
|
let hse = match config.hse {
|
||||||
|
None => {
|
||||||
|
RCC.cr().modify(|w| w.set_hseon(false));
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Some(hse) => {
|
||||||
|
RCC.cr().modify(|w| {
|
||||||
|
w.set_hsebyp(hse.mode != HseMode::Oscillator);
|
||||||
|
#[cfg(any(rcc_h5, rcc_h50))]
|
||||||
|
w.set_hseext(match hse.mode {
|
||||||
|
HseMode::Oscillator | HseMode::Bypass => pac::rcc::vals::Hseext::ANALOG,
|
||||||
|
HseMode::BypassDigital => pac::rcc::vals::Hseext::DIGITAL,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
RCC.cr().modify(|w| w.set_hseon(true));
|
||||||
|
while !RCC.cr().read().hserdy() {}
|
||||||
|
Some(hse.freq)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Configure HSI48.
|
||||||
|
RCC.cr().modify(|w| w.set_hsi48on(config.hsi48));
|
||||||
|
let _hsi48 = match config.hsi48 {
|
||||||
|
false => None,
|
||||||
|
true => {
|
||||||
|
while !RCC.cr().read().hsi48rdy() {}
|
||||||
|
Some(CSI_FREQ)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Configure CSI.
|
||||||
|
RCC.cr().modify(|w| w.set_csion(config.csi));
|
||||||
|
let csi = match config.csi {
|
||||||
|
false => None,
|
||||||
|
true => {
|
||||||
|
while !RCC.cr().read().csirdy() {}
|
||||||
|
Some(CSI_FREQ)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Configure PLLs.
|
||||||
|
let pll_input = PllInput {
|
||||||
|
csi,
|
||||||
|
hse,
|
||||||
|
hsi,
|
||||||
|
#[cfg(stm32h7)]
|
||||||
|
source: config.pll_src,
|
||||||
|
};
|
||||||
|
let pll1 = init_pll(0, config.pll1, &pll_input);
|
||||||
|
let pll2 = init_pll(1, config.pll2, &pll_input);
|
||||||
|
#[cfg(any(rcc_h5, stm32h7))]
|
||||||
|
let _pll3 = init_pll(2, config.pll3, &pll_input);
|
||||||
|
|
||||||
|
// Configure sysclk
|
||||||
|
let (sys, sw) = match config.sys {
|
||||||
|
Sysclk::HSI => (unwrap!(hsi), Sw::HSI),
|
||||||
|
Sysclk::HSE => (unwrap!(hse), Sw::HSE),
|
||||||
|
Sysclk::CSI => (unwrap!(csi), Sw::CSI),
|
||||||
|
Sysclk::Pll1P => (unwrap!(pll1.p), Sw::PLL1),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check limits.
|
||||||
|
#[cfg(stm32h5)]
|
||||||
|
let (hclk_max, pclk_max) = match config.voltage_scale {
|
||||||
|
VoltageScale::Scale0 => (Hertz(250_000_000), Hertz(250_000_000)),
|
||||||
|
VoltageScale::Scale1 => (Hertz(200_000_000), Hertz(200_000_000)),
|
||||||
|
VoltageScale::Scale2 => (Hertz(150_000_000), Hertz(150_000_000)),
|
||||||
|
VoltageScale::Scale3 => (Hertz(100_000_000), Hertz(100_000_000)),
|
||||||
|
};
|
||||||
|
#[cfg(stm32h7)]
|
||||||
|
let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale {
|
||||||
|
VoltageScale::Scale0 => (Hertz(480_000_000), Hertz(240_000_000), Hertz(120_000_000)),
|
||||||
|
VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)),
|
||||||
|
VoltageScale::Scale2 => (Hertz(300_000_000), Hertz(150_000_000), Hertz(75_000_000)),
|
||||||
|
VoltageScale::Scale3 => (Hertz(200_000_000), Hertz(100_000_000), Hertz(50_000_000)),
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(stm32h7)]
|
||||||
|
let hclk = {
|
||||||
|
let d1cpre_clk = sys / config.d1c_pre;
|
||||||
|
assert!(d1cpre_clk <= d1cpre_clk_max);
|
||||||
|
sys / config.ahb_pre
|
||||||
|
};
|
||||||
|
#[cfg(stm32h5)]
|
||||||
|
let hclk = sys / config.ahb_pre;
|
||||||
|
assert!(hclk <= hclk_max);
|
||||||
|
|
||||||
|
let apb1 = hclk / config.apb1_pre;
|
||||||
|
let apb1_tim = apb_div_tim(&config.apb1_pre, hclk, config.timer_prescaler);
|
||||||
|
assert!(apb1 <= pclk_max);
|
||||||
|
let apb2 = hclk / config.apb2_pre;
|
||||||
|
let apb2_tim = apb_div_tim(&config.apb2_pre, hclk, config.timer_prescaler);
|
||||||
|
assert!(apb2 <= pclk_max);
|
||||||
|
let apb3 = hclk / config.apb3_pre;
|
||||||
|
assert!(apb3 <= pclk_max);
|
||||||
|
#[cfg(stm32h7)]
|
||||||
|
let apb4 = hclk / config.apb4_pre;
|
||||||
|
#[cfg(stm32h7)]
|
||||||
|
assert!(apb4 <= pclk_max);
|
||||||
|
|
||||||
|
let _per_ck = match config.per_clock_source {
|
||||||
|
Ckpersel::HSI => hsi,
|
||||||
|
Ckpersel::CSI => csi,
|
||||||
|
Ckpersel::HSE => hse,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(stm32h7)]
|
||||||
|
let adc = match config.adc_clock_source {
|
||||||
|
AdcClockSource::PLL2_P => pll2.p,
|
||||||
|
AdcClockSource::PLL3_R => _pll3.r,
|
||||||
|
AdcClockSource::PER => _per_ck,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
#[cfg(stm32h5)]
|
||||||
|
let adc = match config.adc_clock_source {
|
||||||
|
AdcClockSource::HCLK => Some(hclk),
|
||||||
|
AdcClockSource::SYSCLK => Some(sys),
|
||||||
|
AdcClockSource::PLL2_R => pll2.r,
|
||||||
|
AdcClockSource::HSE => hse,
|
||||||
|
AdcClockSource::HSI_KER => hsi,
|
||||||
|
AdcClockSource::CSI_KER => csi,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
flash_setup(hclk, config.voltage_scale);
|
||||||
|
|
||||||
|
#[cfg(stm32h7)]
|
||||||
|
{
|
||||||
|
RCC.d1cfgr().modify(|w| {
|
||||||
|
w.set_d1cpre(config.d1c_pre);
|
||||||
|
w.set_d1ppre(config.apb3_pre);
|
||||||
|
w.set_hpre(config.ahb_pre);
|
||||||
|
});
|
||||||
|
// Ensure core prescaler value is valid before future lower core voltage
|
||||||
|
while RCC.d1cfgr().read().d1cpre() != config.d1c_pre {}
|
||||||
|
|
||||||
|
RCC.d2cfgr().modify(|w| {
|
||||||
|
w.set_d2ppre1(config.apb1_pre);
|
||||||
|
w.set_d2ppre2(config.apb2_pre);
|
||||||
|
});
|
||||||
|
RCC.d3cfgr().modify(|w| {
|
||||||
|
w.set_d3ppre(config.apb4_pre);
|
||||||
|
});
|
||||||
|
|
||||||
|
RCC.d1ccipr().modify(|w| {
|
||||||
|
w.set_ckpersel(config.per_clock_source);
|
||||||
|
});
|
||||||
|
RCC.d3ccipr().modify(|w| {
|
||||||
|
w.set_adcsel(config.adc_clock_source);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#[cfg(stm32h5)]
|
||||||
|
{
|
||||||
|
// Set hpre
|
||||||
|
RCC.cfgr2().modify(|w| w.set_hpre(config.ahb_pre));
|
||||||
|
while RCC.cfgr2().read().hpre() != config.ahb_pre {}
|
||||||
|
|
||||||
|
// set ppre
|
||||||
|
RCC.cfgr2().modify(|w| {
|
||||||
|
w.set_ppre1(config.apb1_pre);
|
||||||
|
w.set_ppre2(config.apb2_pre);
|
||||||
|
w.set_ppre3(config.apb3_pre);
|
||||||
|
});
|
||||||
|
|
||||||
|
RCC.ccipr5().modify(|w| {
|
||||||
|
w.set_ckpersel(config.per_clock_source);
|
||||||
|
w.set_adcdacsel(config.adc_clock_source)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into()));
|
||||||
|
|
||||||
|
RCC.cfgr().modify(|w| w.set_sw(sw));
|
||||||
|
while RCC.cfgr().read().sws() != sw {}
|
||||||
|
|
||||||
|
// IO compensation cell - Requires CSI clock and SYSCFG
|
||||||
|
#[cfg(stm32h7)] // TODO h5
|
||||||
|
if csi.is_some() {
|
||||||
|
// Enable the compensation cell, using back-bias voltage code
|
||||||
|
// provide by the cell.
|
||||||
|
critical_section::with(|_| {
|
||||||
|
pac::SYSCFG.cccsr().modify(|w| {
|
||||||
|
w.set_en(true);
|
||||||
|
w.set_cs(false);
|
||||||
|
w.set_hslv(false);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
while !pac::SYSCFG.cccsr().read().ready() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
set_freqs(Clocks {
|
||||||
|
sys,
|
||||||
|
ahb1: hclk,
|
||||||
|
ahb2: hclk,
|
||||||
|
ahb3: hclk,
|
||||||
|
ahb4: hclk,
|
||||||
|
apb1,
|
||||||
|
apb2,
|
||||||
|
apb3,
|
||||||
|
#[cfg(stm32h7)]
|
||||||
|
apb4,
|
||||||
|
apb1_tim,
|
||||||
|
apb2_tim,
|
||||||
|
adc: adc,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PllInput {
|
||||||
|
hsi: Option<Hertz>,
|
||||||
|
hse: Option<Hertz>,
|
||||||
|
csi: Option<Hertz>,
|
||||||
|
#[cfg(stm32h7)]
|
||||||
|
source: PllSource,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PllOutput {
|
||||||
|
p: Option<Hertz>,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
q: Option<Hertz>,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
r: Option<Hertz>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
|
||||||
|
let Some(config) = config else {
|
||||||
|
// Stop PLL
|
||||||
|
RCC.cr().modify(|w| w.set_pllon(num, false));
|
||||||
|
while RCC.cr().read().pllrdy(num) {}
|
||||||
|
|
||||||
|
// "To save power when PLL1 is not used, the value of PLL1M must be set to 0.""
|
||||||
|
#[cfg(stm32h7)]
|
||||||
|
RCC.pllckselr().write(|w| w.set_divm(num, 0));
|
||||||
|
#[cfg(stm32h5)]
|
||||||
|
RCC.pllcfgr(num).write(|w| w.set_divm(0));
|
||||||
|
|
||||||
|
return PllOutput {
|
||||||
|
p: None,
|
||||||
|
q: None,
|
||||||
|
r: None,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(1 <= config.prediv && config.prediv <= 63);
|
||||||
|
assert!(4 <= config.mul && config.mul <= 512);
|
||||||
|
|
||||||
|
#[cfg(stm32h5)]
|
||||||
|
let source = config.source;
|
||||||
|
#[cfg(stm32h7)]
|
||||||
|
let source = input.source;
|
||||||
|
|
||||||
|
let (in_clk, src) = match source {
|
||||||
|
PllSource::Hsi => (unwrap!(input.hsi), Pllsrc::HSI),
|
||||||
|
PllSource::Hse => (unwrap!(input.hse), Pllsrc::HSE),
|
||||||
|
PllSource::Csi => (unwrap!(input.csi), Pllsrc::CSI),
|
||||||
|
};
|
||||||
|
|
||||||
|
let ref_clk = in_clk / config.prediv as u32;
|
||||||
|
|
||||||
|
let ref_range = match ref_clk.0 {
|
||||||
|
..=1_999_999 => Pllrge::RANGE1,
|
||||||
|
..=3_999_999 => Pllrge::RANGE2,
|
||||||
|
..=7_999_999 => Pllrge::RANGE4,
|
||||||
|
..=16_000_000 => Pllrge::RANGE8,
|
||||||
|
x => panic!("pll ref_clk out of range: {} mhz", x),
|
||||||
|
};
|
||||||
|
|
||||||
|
// The smaller range (150 to 420 MHz) must
|
||||||
|
// be chosen when the reference clock frequency is lower than 2 MHz.
|
||||||
|
let wide_allowed = ref_range != Pllrge::RANGE1;
|
||||||
|
|
||||||
|
let vco_clk = ref_clk * config.mul;
|
||||||
|
let vco_range = if VCO_RANGE.contains(&vco_clk.0) {
|
||||||
|
Pllvcosel::MEDIUMVCO
|
||||||
|
} else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk.0) {
|
||||||
|
Pllvcosel::WIDEVCO
|
||||||
|
} else {
|
||||||
|
panic!("pll vco_clk out of range: {} mhz", vco_clk.0)
|
||||||
|
};
|
||||||
|
|
||||||
|
let p = config.divp.map(|div| {
|
||||||
|
assert!(1 <= div && div <= 128);
|
||||||
|
if num == 0 {
|
||||||
|
// on PLL1, DIVP must be even.
|
||||||
|
assert!(div % 2 == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
vco_clk / div
|
||||||
|
});
|
||||||
|
let q = config.divq.map(|div| {
|
||||||
|
assert!(1 <= div && div <= 128);
|
||||||
|
vco_clk / div
|
||||||
|
});
|
||||||
|
let r = config.divr.map(|div| {
|
||||||
|
assert!(1 <= div && div <= 128);
|
||||||
|
vco_clk / div
|
||||||
|
});
|
||||||
|
|
||||||
|
#[cfg(stm32h5)]
|
||||||
|
RCC.pllcfgr(num).write(|w| {
|
||||||
|
w.set_pllsrc(src);
|
||||||
|
w.set_divm(config.prediv);
|
||||||
|
w.set_pllvcosel(vco_range);
|
||||||
|
w.set_pllrge(ref_range);
|
||||||
|
w.set_pllfracen(false);
|
||||||
|
w.set_pllpen(p.is_some());
|
||||||
|
w.set_pllqen(q.is_some());
|
||||||
|
w.set_pllren(r.is_some());
|
||||||
|
});
|
||||||
|
|
||||||
|
#[cfg(stm32h7)]
|
||||||
|
{
|
||||||
|
RCC.pllckselr().modify(|w| {
|
||||||
|
w.set_divm(num, config.prediv);
|
||||||
|
w.set_pllsrc(src);
|
||||||
|
});
|
||||||
|
RCC.pllcfgr().modify(|w| {
|
||||||
|
w.set_pllvcosel(num, vco_range);
|
||||||
|
w.set_pllrge(num, ref_range);
|
||||||
|
w.set_pllfracen(num, false);
|
||||||
|
w.set_divpen(num, p.is_some());
|
||||||
|
w.set_divqen(num, q.is_some());
|
||||||
|
w.set_divren(num, r.is_some());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
RCC.plldivr(num).write(|w| {
|
||||||
|
w.set_plln(config.mul - 1);
|
||||||
|
w.set_pllp((config.divp.unwrap_or(1) - 1) as u8);
|
||||||
|
w.set_pllq((config.divq.unwrap_or(1) - 1) as u8);
|
||||||
|
w.set_pllr((config.divr.unwrap_or(1) - 1) as u8);
|
||||||
|
});
|
||||||
|
|
||||||
|
RCC.cr().modify(|w| w.set_pllon(num, true));
|
||||||
|
while !RCC.cr().read().pllrdy(num) {}
|
||||||
|
|
||||||
|
PllOutput { p, q, r }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flash_setup(clk: Hertz, vos: VoltageScale) {
|
||||||
|
// RM0481 Rev 1, table 37
|
||||||
|
// LATENCY WRHIGHFREQ VOS3 VOS2 VOS1 VOS0
|
||||||
|
// 0 0 0 to 20 MHz 0 to 30 MHz 0 to 34 MHz 0 to 42 MHz
|
||||||
|
// 1 0 20 to 40 MHz 30 to 60 MHz 34 to 68 MHz 42 to 84 MHz
|
||||||
|
// 2 1 40 to 60 MHz 60 to 90 MHz 68 to 102 MHz 84 to 126 MHz
|
||||||
|
// 3 1 60 to 80 MHz 90 to 120 MHz 102 to 136 MHz 126 to 168 MHz
|
||||||
|
// 4 2 80 to 100 MHz 120 to 150 MHz 136 to 170 MHz 168 to 210 MHz
|
||||||
|
// 5 2 170 to 200 MHz 210 to 250 MHz
|
||||||
|
#[cfg(stm32h5)]
|
||||||
|
let (latency, wrhighfreq) = match (vos, clk.0) {
|
||||||
|
(VoltageScale::Scale0, ..=42_000_000) => (0, 0),
|
||||||
|
(VoltageScale::Scale0, ..=84_000_000) => (1, 0),
|
||||||
|
(VoltageScale::Scale0, ..=126_000_000) => (2, 1),
|
||||||
|
(VoltageScale::Scale0, ..=168_000_000) => (3, 1),
|
||||||
|
(VoltageScale::Scale0, ..=210_000_000) => (4, 2),
|
||||||
|
(VoltageScale::Scale0, ..=250_000_000) => (5, 2),
|
||||||
|
|
||||||
|
(VoltageScale::Scale1, ..=34_000_000) => (0, 0),
|
||||||
|
(VoltageScale::Scale1, ..=68_000_000) => (1, 0),
|
||||||
|
(VoltageScale::Scale1, ..=102_000_000) => (2, 1),
|
||||||
|
(VoltageScale::Scale1, ..=136_000_000) => (3, 1),
|
||||||
|
(VoltageScale::Scale1, ..=170_000_000) => (4, 2),
|
||||||
|
(VoltageScale::Scale1, ..=200_000_000) => (5, 2),
|
||||||
|
|
||||||
|
(VoltageScale::Scale2, ..=30_000_000) => (0, 0),
|
||||||
|
(VoltageScale::Scale2, ..=60_000_000) => (1, 0),
|
||||||
|
(VoltageScale::Scale2, ..=90_000_000) => (2, 1),
|
||||||
|
(VoltageScale::Scale2, ..=120_000_000) => (3, 1),
|
||||||
|
(VoltageScale::Scale2, ..=150_000_000) => (4, 2),
|
||||||
|
|
||||||
|
(VoltageScale::Scale3, ..=20_000_000) => (0, 0),
|
||||||
|
(VoltageScale::Scale3, ..=40_000_000) => (1, 0),
|
||||||
|
(VoltageScale::Scale3, ..=60_000_000) => (2, 1),
|
||||||
|
(VoltageScale::Scale3, ..=80_000_000) => (3, 1),
|
||||||
|
(VoltageScale::Scale3, ..=100_000_000) => (4, 2),
|
||||||
|
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(flash_h7)]
|
||||||
|
let (latency, wrhighfreq) = match (vos, clk.0) {
|
||||||
|
// VOS 0 range VCORE 1.26V - 1.40V
|
||||||
|
(VoltageScale::Scale0, ..=70_000_000) => (0, 0),
|
||||||
|
(VoltageScale::Scale0, ..=140_000_000) => (1, 1),
|
||||||
|
(VoltageScale::Scale0, ..=185_000_000) => (2, 1),
|
||||||
|
(VoltageScale::Scale0, ..=210_000_000) => (2, 2),
|
||||||
|
(VoltageScale::Scale0, ..=225_000_000) => (3, 2),
|
||||||
|
(VoltageScale::Scale0, ..=240_000_000) => (4, 2),
|
||||||
|
// VOS 1 range VCORE 1.15V - 1.26V
|
||||||
|
(VoltageScale::Scale1, ..=70_000_000) => (0, 0),
|
||||||
|
(VoltageScale::Scale1, ..=140_000_000) => (1, 1),
|
||||||
|
(VoltageScale::Scale1, ..=185_000_000) => (2, 1),
|
||||||
|
(VoltageScale::Scale1, ..=210_000_000) => (2, 2),
|
||||||
|
(VoltageScale::Scale1, ..=225_000_000) => (3, 2),
|
||||||
|
// VOS 2 range VCORE 1.05V - 1.15V
|
||||||
|
(VoltageScale::Scale2, ..=55_000_000) => (0, 0),
|
||||||
|
(VoltageScale::Scale2, ..=110_000_000) => (1, 1),
|
||||||
|
(VoltageScale::Scale2, ..=165_000_000) => (2, 1),
|
||||||
|
(VoltageScale::Scale2, ..=224_000_000) => (3, 2),
|
||||||
|
// VOS 3 range VCORE 0.95V - 1.05V
|
||||||
|
(VoltageScale::Scale3, ..=45_000_000) => (0, 0),
|
||||||
|
(VoltageScale::Scale3, ..=90_000_000) => (1, 1),
|
||||||
|
(VoltageScale::Scale3, ..=135_000_000) => (2, 1),
|
||||||
|
(VoltageScale::Scale3, ..=180_000_000) => (3, 2),
|
||||||
|
(VoltageScale::Scale3, ..=224_000_000) => (4, 2),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// See RM0455 Rev 10 Table 16. FLASH recommended number of wait
|
||||||
|
// states and programming delay
|
||||||
|
#[cfg(flash_h7ab)]
|
||||||
|
let (latency, wrhighfreq) = match (vos, clk.0) {
|
||||||
|
// VOS 0 range VCORE 1.25V - 1.35V
|
||||||
|
(VoltageScale::Scale0, ..=42_000_000) => (0, 0),
|
||||||
|
(VoltageScale::Scale0, ..=84_000_000) => (1, 0),
|
||||||
|
(VoltageScale::Scale0, ..=126_000_000) => (2, 1),
|
||||||
|
(VoltageScale::Scale0, ..=168_000_000) => (3, 1),
|
||||||
|
(VoltageScale::Scale0, ..=210_000_000) => (4, 2),
|
||||||
|
(VoltageScale::Scale0, ..=252_000_000) => (5, 2),
|
||||||
|
(VoltageScale::Scale0, ..=280_000_000) => (6, 3),
|
||||||
|
// VOS 1 range VCORE 1.15V - 1.25V
|
||||||
|
(VoltageScale::Scale1, ..=38_000_000) => (0, 0),
|
||||||
|
(VoltageScale::Scale1, ..=76_000_000) => (1, 0),
|
||||||
|
(VoltageScale::Scale1, ..=114_000_000) => (2, 1),
|
||||||
|
(VoltageScale::Scale1, ..=152_000_000) => (3, 1),
|
||||||
|
(VoltageScale::Scale1, ..=190_000_000) => (4, 2),
|
||||||
|
(VoltageScale::Scale1, ..=225_000_000) => (5, 2),
|
||||||
|
// VOS 2 range VCORE 1.05V - 1.15V
|
||||||
|
(VoltageScale::Scale2, ..=34) => (0, 0),
|
||||||
|
(VoltageScale::Scale2, ..=68) => (1, 0),
|
||||||
|
(VoltageScale::Scale2, ..=102) => (2, 1),
|
||||||
|
(VoltageScale::Scale2, ..=136) => (3, 1),
|
||||||
|
(VoltageScale::Scale2, ..=160) => (4, 2),
|
||||||
|
// VOS 3 range VCORE 0.95V - 1.05V
|
||||||
|
(VoltageScale::Scale3, ..=22) => (0, 0),
|
||||||
|
(VoltageScale::Scale3, ..=44) => (1, 0),
|
||||||
|
(VoltageScale::Scale3, ..=66) => (2, 1),
|
||||||
|
(VoltageScale::Scale3, ..=88) => (3, 1),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq);
|
||||||
|
|
||||||
|
FLASH.acr().write(|w| {
|
||||||
|
w.set_wrhighfreq(wrhighfreq);
|
||||||
|
w.set_latency(latency);
|
||||||
|
});
|
||||||
|
while FLASH.acr().read().latency() != latency {}
|
||||||
|
}
|
@ -1,511 +0,0 @@
|
|||||||
use core::marker::PhantomData;
|
|
||||||
|
|
||||||
use stm32_metapac::rcc::vals::Timpre;
|
|
||||||
|
|
||||||
use crate::pac::pwr::vals::Vos;
|
|
||||||
use crate::pac::rcc::vals::{Hseext, Hsidiv, Mco1, Mco2, Pllrge, Pllsrc, Pllvcosel, Sw};
|
|
||||||
use crate::pac::{FLASH, PWR, RCC};
|
|
||||||
use crate::rcc::{set_freqs, Clocks};
|
|
||||||
use crate::time::Hertz;
|
|
||||||
use crate::{peripherals, Peripheral};
|
|
||||||
|
|
||||||
/// HSI speed
|
|
||||||
pub const HSI_FREQ: Hertz = Hertz(64_000_000);
|
|
||||||
|
|
||||||
/// CSI speed
|
|
||||||
pub const CSI_FREQ: Hertz = Hertz(4_000_000);
|
|
||||||
|
|
||||||
/// HSI48 speed
|
|
||||||
pub const HSI48_FREQ: Hertz = Hertz(48_000_000);
|
|
||||||
|
|
||||||
/// LSI speed
|
|
||||||
pub const LSI_FREQ: Hertz = Hertz(32_000);
|
|
||||||
|
|
||||||
const VCO_MIN: u32 = 150_000_000;
|
|
||||||
const VCO_MAX: u32 = 420_000_000;
|
|
||||||
const VCO_WIDE_MIN: u32 = 128_000_000;
|
|
||||||
const VCO_WIDE_MAX: u32 = 560_000_000;
|
|
||||||
|
|
||||||
pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale};
|
|
||||||
|
|
||||||
pub enum HseMode {
|
|
||||||
/// crystal/ceramic oscillator (HSEBYP=0)
|
|
||||||
Oscillator,
|
|
||||||
/// external analog clock (low swing) (HSEBYP=1, HSEEXT=0)
|
|
||||||
BypassAnalog,
|
|
||||||
/// external digital clock (full swing) (HSEBYP=1, HSEEXT=1)
|
|
||||||
BypassDigital,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Hse {
|
|
||||||
/// HSE frequency.
|
|
||||||
pub freq: Hertz,
|
|
||||||
/// HSE mode.
|
|
||||||
pub mode: HseMode,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Hsi {
|
|
||||||
/// 64Mhz
|
|
||||||
Mhz64,
|
|
||||||
/// 32Mhz (divided by 2)
|
|
||||||
Mhz32,
|
|
||||||
/// 16Mhz (divided by 4)
|
|
||||||
Mhz16,
|
|
||||||
/// 8Mhz (divided by 8)
|
|
||||||
Mhz8,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum Sysclk {
|
|
||||||
/// HSI selected as sysclk
|
|
||||||
HSI,
|
|
||||||
/// HSE selected as sysclk
|
|
||||||
HSE,
|
|
||||||
/// CSI selected as sysclk
|
|
||||||
CSI,
|
|
||||||
/// PLL1_P selected as sysclk
|
|
||||||
Pll1P,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum PllSource {
|
|
||||||
Hsi,
|
|
||||||
Csi,
|
|
||||||
Hse,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Pll {
|
|
||||||
/// Source clock selection.
|
|
||||||
pub source: PllSource,
|
|
||||||
|
|
||||||
/// PLL pre-divider (DIVM). Must be between 1 and 63.
|
|
||||||
pub prediv: u8,
|
|
||||||
|
|
||||||
/// PLL multiplication factor. Must be between 4 and 512.
|
|
||||||
pub mul: u16,
|
|
||||||
|
|
||||||
/// PLL P division factor. If None, PLL P output is disabled. Must be between 1 and 128.
|
|
||||||
/// On PLL1, it must be even (in particular, it cannot be 1.)
|
|
||||||
pub divp: Option<u16>,
|
|
||||||
/// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128.
|
|
||||||
pub divq: Option<u16>,
|
|
||||||
/// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128.
|
|
||||||
pub divr: Option<u16>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl APBPrescaler {
|
|
||||||
fn div_tim(&self, clk: Hertz, tim: TimerPrescaler) -> Hertz {
|
|
||||||
match (tim, self) {
|
|
||||||
// The timers kernel clock is equal to rcc_hclk1 if PPRE1 or PPRE2 corresponds to a
|
|
||||||
// division by 1 or 2, else it is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2
|
|
||||||
(TimerPrescaler::DefaultX2, Self::NotDivided) => clk,
|
|
||||||
(TimerPrescaler::DefaultX2, Self::Div2) => clk,
|
|
||||||
(TimerPrescaler::DefaultX2, Self::Div4) => clk / 2u32,
|
|
||||||
(TimerPrescaler::DefaultX2, Self::Div8) => clk / 4u32,
|
|
||||||
(TimerPrescaler::DefaultX2, Self::Div16) => clk / 8u32,
|
|
||||||
// The timers kernel clock is equal to 2 x Frcc_pclk1 or 2 x Frcc_pclk2 if PPRE1 or PPRE2
|
|
||||||
// corresponds to a division by 1, 2 or 4, else it is equal to 4 x Frcc_pclk1 or 4 x Frcc_pclk2
|
|
||||||
// this makes NO SENSE and is different than in the H7. Mistake in the RM??
|
|
||||||
(TimerPrescaler::DefaultX4, Self::NotDivided) => clk * 2u32,
|
|
||||||
(TimerPrescaler::DefaultX4, Self::Div2) => clk,
|
|
||||||
(TimerPrescaler::DefaultX4, Self::Div4) => clk / 2u32,
|
|
||||||
(TimerPrescaler::DefaultX4, Self::Div8) => clk / 2u32,
|
|
||||||
(TimerPrescaler::DefaultX4, Self::Div16) => clk / 4u32,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// APB prescaler
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum TimerPrescaler {
|
|
||||||
DefaultX2,
|
|
||||||
DefaultX4,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<TimerPrescaler> for Timpre {
|
|
||||||
fn from(value: TimerPrescaler) -> Self {
|
|
||||||
match value {
|
|
||||||
TimerPrescaler::DefaultX2 => Timpre::DEFAULTX2,
|
|
||||||
TimerPrescaler::DefaultX4 => Timpre::DEFAULTX4,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Configuration of the core clocks
|
|
||||||
#[non_exhaustive]
|
|
||||||
pub struct Config {
|
|
||||||
pub hsi: Option<Hsi>,
|
|
||||||
pub hse: Option<Hse>,
|
|
||||||
pub csi: bool,
|
|
||||||
pub hsi48: bool,
|
|
||||||
pub sys: Sysclk,
|
|
||||||
|
|
||||||
pub pll1: Option<Pll>,
|
|
||||||
pub pll2: Option<Pll>,
|
|
||||||
#[cfg(rcc_h5)]
|
|
||||||
pub pll3: Option<Pll>,
|
|
||||||
|
|
||||||
pub ahb_pre: AHBPrescaler,
|
|
||||||
pub apb1_pre: APBPrescaler,
|
|
||||||
pub apb2_pre: APBPrescaler,
|
|
||||||
pub apb3_pre: APBPrescaler,
|
|
||||||
pub timer_prescaler: TimerPrescaler,
|
|
||||||
|
|
||||||
pub voltage_scale: VoltageScale,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Config {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
hsi: Some(Hsi::Mhz64),
|
|
||||||
hse: None,
|
|
||||||
csi: false,
|
|
||||||
hsi48: false,
|
|
||||||
sys: Sysclk::HSI,
|
|
||||||
pll1: None,
|
|
||||||
pll2: None,
|
|
||||||
#[cfg(rcc_h5)]
|
|
||||||
pll3: None,
|
|
||||||
|
|
||||||
ahb_pre: AHBPrescaler::NotDivided,
|
|
||||||
apb1_pre: APBPrescaler::NotDivided,
|
|
||||||
apb2_pre: APBPrescaler::NotDivided,
|
|
||||||
apb3_pre: APBPrescaler::NotDivided,
|
|
||||||
timer_prescaler: TimerPrescaler::DefaultX2,
|
|
||||||
|
|
||||||
voltage_scale: VoltageScale::Scale3,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) mod sealed {
|
|
||||||
pub trait McoInstance {
|
|
||||||
type Source;
|
|
||||||
unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait McoInstance: sealed::McoInstance + 'static {}
|
|
||||||
|
|
||||||
pin_trait!(McoPin, McoInstance);
|
|
||||||
|
|
||||||
macro_rules! impl_peri {
|
|
||||||
($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => {
|
|
||||||
impl sealed::McoInstance for peripherals::$peri {
|
|
||||||
type Source = $source;
|
|
||||||
|
|
||||||
unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) {
|
|
||||||
RCC.cfgr().modify(|w| {
|
|
||||||
w.$set_source(source);
|
|
||||||
w.$set_prescaler(prescaler);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl McoInstance for peripherals::$peri {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_peri!(MCO1, Mco1, set_mco1, set_mco1pre);
|
|
||||||
impl_peri!(MCO2, Mco2, set_mco2, set_mco2pre);
|
|
||||||
|
|
||||||
pub struct Mco<'d, T: McoInstance> {
|
|
||||||
phantom: PhantomData<&'d mut T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: McoInstance> Mco<'d, T> {
|
|
||||||
pub fn new(
|
|
||||||
_peri: impl Peripheral<P = T> + 'd,
|
|
||||||
_pin: impl Peripheral<P = impl McoPin<T>> + 'd,
|
|
||||||
_source: T::Source,
|
|
||||||
) -> Self {
|
|
||||||
todo!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) unsafe fn init(config: Config) {
|
|
||||||
let (vos, max_clk) = match config.voltage_scale {
|
|
||||||
VoltageScale::Scale0 => (Vos::SCALE0, Hertz(250_000_000)),
|
|
||||||
VoltageScale::Scale1 => (Vos::SCALE1, Hertz(200_000_000)),
|
|
||||||
VoltageScale::Scale2 => (Vos::SCALE2, Hertz(150_000_000)),
|
|
||||||
VoltageScale::Scale3 => (Vos::SCALE3, Hertz(100_000_000)),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Configure voltage scale.
|
|
||||||
PWR.voscr().modify(|w| w.set_vos(vos));
|
|
||||||
while !PWR.vossr().read().vosrdy() {}
|
|
||||||
|
|
||||||
// Configure HSI
|
|
||||||
let hsi = match config.hsi {
|
|
||||||
None => {
|
|
||||||
RCC.cr().modify(|w| w.set_hsion(false));
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Some(hsi) => {
|
|
||||||
let (freq, hsidiv) = match hsi {
|
|
||||||
Hsi::Mhz64 => (HSI_FREQ / 1u32, Hsidiv::DIV1),
|
|
||||||
Hsi::Mhz32 => (HSI_FREQ / 2u32, Hsidiv::DIV2),
|
|
||||||
Hsi::Mhz16 => (HSI_FREQ / 4u32, Hsidiv::DIV4),
|
|
||||||
Hsi::Mhz8 => (HSI_FREQ / 8u32, Hsidiv::DIV8),
|
|
||||||
};
|
|
||||||
RCC.cr().modify(|w| {
|
|
||||||
w.set_hsidiv(hsidiv);
|
|
||||||
w.set_hsion(true);
|
|
||||||
});
|
|
||||||
while !RCC.cr().read().hsirdy() {}
|
|
||||||
Some(freq)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Configure HSE
|
|
||||||
let hse = match config.hse {
|
|
||||||
None => {
|
|
||||||
RCC.cr().modify(|w| w.set_hseon(false));
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Some(hse) => {
|
|
||||||
let (byp, ext) = match hse.mode {
|
|
||||||
HseMode::Oscillator => (false, Hseext::ANALOG),
|
|
||||||
HseMode::BypassAnalog => (true, Hseext::ANALOG),
|
|
||||||
HseMode::BypassDigital => (true, Hseext::DIGITAL),
|
|
||||||
};
|
|
||||||
|
|
||||||
RCC.cr().modify(|w| {
|
|
||||||
w.set_hsebyp(byp);
|
|
||||||
w.set_hseext(ext);
|
|
||||||
});
|
|
||||||
RCC.cr().modify(|w| w.set_hseon(true));
|
|
||||||
while !RCC.cr().read().hserdy() {}
|
|
||||||
Some(hse.freq)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Configure HSI48.
|
|
||||||
RCC.cr().modify(|w| w.set_hsi48on(config.hsi48));
|
|
||||||
let _hsi48 = match config.hsi48 {
|
|
||||||
false => None,
|
|
||||||
true => {
|
|
||||||
while !RCC.cr().read().hsi48rdy() {}
|
|
||||||
Some(CSI_FREQ)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Configure CSI.
|
|
||||||
RCC.cr().modify(|w| w.set_csion(config.csi));
|
|
||||||
let csi = match config.csi {
|
|
||||||
false => None,
|
|
||||||
true => {
|
|
||||||
while !RCC.cr().read().csirdy() {}
|
|
||||||
Some(CSI_FREQ)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Configure PLLs.
|
|
||||||
let pll_input = PllInput { csi, hse, hsi };
|
|
||||||
let pll1 = init_pll(0, config.pll1, &pll_input);
|
|
||||||
let _pll2 = init_pll(1, config.pll2, &pll_input);
|
|
||||||
#[cfg(rcc_h5)]
|
|
||||||
let _pll3 = init_pll(2, config.pll3, &pll_input);
|
|
||||||
|
|
||||||
// Configure sysclk
|
|
||||||
let (sys, sw) = match config.sys {
|
|
||||||
Sysclk::HSI => (unwrap!(hsi), Sw::HSI),
|
|
||||||
Sysclk::HSE => (unwrap!(hse), Sw::HSE),
|
|
||||||
Sysclk::CSI => (unwrap!(csi), Sw::CSI),
|
|
||||||
Sysclk::Pll1P => (unwrap!(pll1.p), Sw::PLL1),
|
|
||||||
};
|
|
||||||
assert!(sys <= max_clk);
|
|
||||||
|
|
||||||
let hclk = sys / config.ahb_pre;
|
|
||||||
|
|
||||||
let apb1 = hclk / config.apb1_pre;
|
|
||||||
let apb1_tim = config.apb1_pre.div_tim(hclk, config.timer_prescaler);
|
|
||||||
let apb2 = hclk / config.apb2_pre;
|
|
||||||
let apb2_tim = config.apb2_pre.div_tim(hclk, config.timer_prescaler);
|
|
||||||
let apb3 = hclk / config.apb3_pre;
|
|
||||||
|
|
||||||
flash_setup(hclk, config.voltage_scale);
|
|
||||||
|
|
||||||
// Set hpre
|
|
||||||
let hpre = config.ahb_pre.into();
|
|
||||||
RCC.cfgr2().modify(|w| w.set_hpre(hpre));
|
|
||||||
while RCC.cfgr2().read().hpre() != hpre {}
|
|
||||||
|
|
||||||
// set ppre
|
|
||||||
RCC.cfgr2().modify(|w| {
|
|
||||||
w.set_ppre1(config.apb1_pre.into());
|
|
||||||
w.set_ppre2(config.apb2_pre.into());
|
|
||||||
w.set_ppre3(config.apb3_pre.into());
|
|
||||||
});
|
|
||||||
|
|
||||||
RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into()));
|
|
||||||
|
|
||||||
RCC.cfgr().modify(|w| w.set_sw(sw));
|
|
||||||
while RCC.cfgr().read().sws() != sw {}
|
|
||||||
|
|
||||||
set_freqs(Clocks {
|
|
||||||
sys,
|
|
||||||
ahb1: hclk,
|
|
||||||
ahb2: hclk,
|
|
||||||
ahb3: hclk,
|
|
||||||
ahb4: hclk,
|
|
||||||
apb1,
|
|
||||||
apb2,
|
|
||||||
apb3,
|
|
||||||
apb1_tim,
|
|
||||||
apb2_tim,
|
|
||||||
adc: None,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
struct PllInput {
|
|
||||||
hsi: Option<Hertz>,
|
|
||||||
hse: Option<Hertz>,
|
|
||||||
csi: Option<Hertz>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct PllOutput {
|
|
||||||
p: Option<Hertz>,
|
|
||||||
#[allow(dead_code)]
|
|
||||||
q: Option<Hertz>,
|
|
||||||
#[allow(dead_code)]
|
|
||||||
r: Option<Hertz>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
|
|
||||||
let Some(config) = config else {
|
|
||||||
// Stop PLL
|
|
||||||
RCC.cr().modify(|w| w.set_pllon(num, false));
|
|
||||||
while RCC.cr().read().pllrdy(num) {}
|
|
||||||
|
|
||||||
// "To save power when PLL1 is not used, the value of PLL1M must be set to 0.""
|
|
||||||
RCC.pllcfgr(num).write(|w| {
|
|
||||||
w.set_divm(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
return PllOutput {
|
|
||||||
p: None,
|
|
||||||
q: None,
|
|
||||||
r: None,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
assert!(1 <= config.prediv && config.prediv <= 63);
|
|
||||||
assert!(4 <= config.mul && config.mul <= 512);
|
|
||||||
|
|
||||||
let (in_clk, src) = match config.source {
|
|
||||||
PllSource::Hsi => (unwrap!(input.hsi), Pllsrc::HSI),
|
|
||||||
PllSource::Hse => (unwrap!(input.hse), Pllsrc::HSE),
|
|
||||||
PllSource::Csi => (unwrap!(input.csi), Pllsrc::CSI),
|
|
||||||
};
|
|
||||||
|
|
||||||
let ref_clk = in_clk / config.prediv as u32;
|
|
||||||
|
|
||||||
let ref_range = match ref_clk.0 {
|
|
||||||
..=1_999_999 => Pllrge::RANGE1,
|
|
||||||
..=3_999_999 => Pllrge::RANGE2,
|
|
||||||
..=7_999_999 => Pllrge::RANGE4,
|
|
||||||
..=16_000_000 => Pllrge::RANGE8,
|
|
||||||
x => panic!("pll ref_clk out of range: {} mhz", x),
|
|
||||||
};
|
|
||||||
|
|
||||||
// The smaller range (150 to 420 MHz) must
|
|
||||||
// be chosen when the reference clock frequency is lower than 2 MHz.
|
|
||||||
let wide_allowed = ref_range != Pllrge::RANGE1;
|
|
||||||
|
|
||||||
let vco_clk = ref_clk * config.mul;
|
|
||||||
let vco_range = match vco_clk.0 {
|
|
||||||
VCO_MIN..=VCO_MAX => Pllvcosel::MEDIUMVCO,
|
|
||||||
VCO_WIDE_MIN..=VCO_WIDE_MAX if wide_allowed => Pllvcosel::WIDEVCO,
|
|
||||||
x => panic!("pll vco_clk out of range: {} mhz", x),
|
|
||||||
};
|
|
||||||
|
|
||||||
let p = config.divp.map(|div| {
|
|
||||||
assert!(1 <= div && div <= 128);
|
|
||||||
if num == 0 {
|
|
||||||
// on PLL1, DIVP must be even.
|
|
||||||
assert!(div % 2 == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
vco_clk / div
|
|
||||||
});
|
|
||||||
let q = config.divq.map(|div| {
|
|
||||||
assert!(1 <= div && div <= 128);
|
|
||||||
vco_clk / div
|
|
||||||
});
|
|
||||||
let r = config.divr.map(|div| {
|
|
||||||
assert!(1 <= div && div <= 128);
|
|
||||||
vco_clk / div
|
|
||||||
});
|
|
||||||
|
|
||||||
RCC.pllcfgr(num).write(|w| {
|
|
||||||
w.set_pllsrc(src);
|
|
||||||
w.set_divm(config.prediv);
|
|
||||||
w.set_pllvcosel(vco_range);
|
|
||||||
w.set_pllrge(ref_range);
|
|
||||||
w.set_pllfracen(false);
|
|
||||||
w.set_pllpen(p.is_some());
|
|
||||||
w.set_pllqen(q.is_some());
|
|
||||||
w.set_pllren(r.is_some());
|
|
||||||
});
|
|
||||||
RCC.plldivr(num).write(|w| {
|
|
||||||
w.set_plln(config.mul - 1);
|
|
||||||
w.set_pllp((config.divp.unwrap_or(1) - 1) as u8);
|
|
||||||
w.set_pllq((config.divq.unwrap_or(1) - 1) as u8);
|
|
||||||
w.set_pllr((config.divr.unwrap_or(1) - 1) as u8);
|
|
||||||
});
|
|
||||||
|
|
||||||
RCC.cr().modify(|w| w.set_pllon(num, true));
|
|
||||||
while !RCC.cr().read().pllrdy(num) {}
|
|
||||||
|
|
||||||
PllOutput { p, q, r }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn flash_setup(clk: Hertz, vos: VoltageScale) {
|
|
||||||
// RM0481 Rev 1, table 37
|
|
||||||
// LATENCY WRHIGHFREQ VOS3 VOS2 VOS1 VOS0
|
|
||||||
// 0 0 0 to 20 MHz 0 to 30 MHz 0 to 34 MHz 0 to 42 MHz
|
|
||||||
// 1 0 20 to 40 MHz 30 to 60 MHz 34 to 68 MHz 42 to 84 MHz
|
|
||||||
// 2 1 40 to 60 MHz 60 to 90 MHz 68 to 102 MHz 84 to 126 MHz
|
|
||||||
// 3 1 60 to 80 MHz 90 to 120 MHz 102 to 136 MHz 126 to 168 MHz
|
|
||||||
// 4 2 80 to 100 MHz 120 to 150 MHz 136 to 170 MHz 168 to 210 MHz
|
|
||||||
// 5 2 170 to 200 MHz 210 to 250 MHz
|
|
||||||
|
|
||||||
// See RM0433 Rev 7 Table 17. FLASH recommended number of wait
|
|
||||||
// states and programming delay
|
|
||||||
let (latency, wrhighfreq) = match (vos, clk.0) {
|
|
||||||
(VoltageScale::Scale0, ..=42_000_000) => (0, 0),
|
|
||||||
(VoltageScale::Scale0, ..=84_000_000) => (1, 0),
|
|
||||||
(VoltageScale::Scale0, ..=126_000_000) => (2, 1),
|
|
||||||
(VoltageScale::Scale0, ..=168_000_000) => (3, 1),
|
|
||||||
(VoltageScale::Scale0, ..=210_000_000) => (4, 2),
|
|
||||||
(VoltageScale::Scale0, ..=250_000_000) => (5, 2),
|
|
||||||
|
|
||||||
(VoltageScale::Scale1, ..=34_000_000) => (0, 0),
|
|
||||||
(VoltageScale::Scale1, ..=68_000_000) => (1, 0),
|
|
||||||
(VoltageScale::Scale1, ..=102_000_000) => (2, 1),
|
|
||||||
(VoltageScale::Scale1, ..=136_000_000) => (3, 1),
|
|
||||||
(VoltageScale::Scale1, ..=170_000_000) => (4, 2),
|
|
||||||
(VoltageScale::Scale1, ..=200_000_000) => (5, 2),
|
|
||||||
|
|
||||||
(VoltageScale::Scale2, ..=30_000_000) => (0, 0),
|
|
||||||
(VoltageScale::Scale2, ..=60_000_000) => (1, 0),
|
|
||||||
(VoltageScale::Scale2, ..=90_000_000) => (2, 1),
|
|
||||||
(VoltageScale::Scale2, ..=120_000_000) => (3, 1),
|
|
||||||
(VoltageScale::Scale2, ..=150_000_000) => (4, 2),
|
|
||||||
|
|
||||||
(VoltageScale::Scale3, ..=20_000_000) => (0, 0),
|
|
||||||
(VoltageScale::Scale3, ..=40_000_000) => (1, 0),
|
|
||||||
(VoltageScale::Scale3, ..=60_000_000) => (2, 1),
|
|
||||||
(VoltageScale::Scale3, ..=80_000_000) => (3, 1),
|
|
||||||
(VoltageScale::Scale3, ..=100_000_000) => (4, 2),
|
|
||||||
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
defmt::debug!("flash: latency={} wrhighfreq={}", latency, wrhighfreq);
|
|
||||||
|
|
||||||
FLASH.acr().write(|w| {
|
|
||||||
w.set_wrhighfreq(wrhighfreq);
|
|
||||||
w.set_latency(latency);
|
|
||||||
});
|
|
||||||
while FLASH.acr().read().latency() != latency {}
|
|
||||||
}
|
|
@ -1,879 +0,0 @@
|
|||||||
use core::marker::PhantomData;
|
|
||||||
|
|
||||||
use embassy_hal_internal::into_ref;
|
|
||||||
pub use pll::PllConfig;
|
|
||||||
use stm32_metapac::rcc::vals::{Mco1, Mco2};
|
|
||||||
|
|
||||||
use crate::gpio::sealed::AFType;
|
|
||||||
use crate::gpio::Speed;
|
|
||||||
use crate::pac::rcc::vals::{Adcsel, Ckpersel, Dppre, Hpre, Hsidiv, Pllsrc, Sw, Timpre};
|
|
||||||
use crate::pac::{PWR, RCC, SYSCFG};
|
|
||||||
use crate::rcc::{set_freqs, Clocks};
|
|
||||||
use crate::time::Hertz;
|
|
||||||
use crate::{peripherals, Peripheral};
|
|
||||||
|
|
||||||
/// HSI speed
|
|
||||||
pub const HSI_FREQ: Hertz = Hertz(64_000_000);
|
|
||||||
|
|
||||||
/// CSI speed
|
|
||||||
pub const CSI_FREQ: Hertz = Hertz(4_000_000);
|
|
||||||
|
|
||||||
/// HSI48 speed
|
|
||||||
pub const HSI48_FREQ: Hertz = Hertz(48_000_000);
|
|
||||||
|
|
||||||
/// LSI speed
|
|
||||||
pub const LSI_FREQ: Hertz = Hertz(32_000);
|
|
||||||
|
|
||||||
pub use super::bus::VoltageScale;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub enum AdcClockSource {
|
|
||||||
Pll2PCk,
|
|
||||||
Pll3RCk,
|
|
||||||
PerCk,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AdcClockSource {
|
|
||||||
pub fn adcsel(&self) -> Adcsel {
|
|
||||||
match self {
|
|
||||||
AdcClockSource::Pll2PCk => Adcsel::PLL2_P,
|
|
||||||
AdcClockSource::Pll3RCk => Adcsel::PLL3_R,
|
|
||||||
AdcClockSource::PerCk => Adcsel::PER,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for AdcClockSource {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::Pll2PCk
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Core clock frequencies
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub struct CoreClocks {
|
|
||||||
pub hclk: Hertz,
|
|
||||||
pub pclk1: Hertz,
|
|
||||||
pub pclk2: Hertz,
|
|
||||||
pub pclk3: Hertz,
|
|
||||||
pub pclk4: Hertz,
|
|
||||||
pub ppre1: u8,
|
|
||||||
pub ppre2: u8,
|
|
||||||
pub ppre3: u8,
|
|
||||||
pub ppre4: u8,
|
|
||||||
pub csi_ck: Option<Hertz>,
|
|
||||||
pub hsi_ck: Option<Hertz>,
|
|
||||||
pub hsi48_ck: Option<Hertz>,
|
|
||||||
pub lsi_ck: Option<Hertz>,
|
|
||||||
pub per_ck: Option<Hertz>,
|
|
||||||
pub hse_ck: Option<Hertz>,
|
|
||||||
pub pll1_p_ck: Option<Hertz>,
|
|
||||||
pub pll1_q_ck: Option<Hertz>,
|
|
||||||
pub pll1_r_ck: Option<Hertz>,
|
|
||||||
pub pll2_p_ck: Option<Hertz>,
|
|
||||||
pub pll2_q_ck: Option<Hertz>,
|
|
||||||
pub pll2_r_ck: Option<Hertz>,
|
|
||||||
pub pll3_p_ck: Option<Hertz>,
|
|
||||||
pub pll3_q_ck: Option<Hertz>,
|
|
||||||
pub pll3_r_ck: Option<Hertz>,
|
|
||||||
pub timx_ker_ck: Option<Hertz>,
|
|
||||||
pub timy_ker_ck: Option<Hertz>,
|
|
||||||
pub adc_ker_ck: Option<Hertz>,
|
|
||||||
pub sys_ck: Hertz,
|
|
||||||
pub c_ck: Hertz,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Configuration of the core clocks
|
|
||||||
#[non_exhaustive]
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct Config {
|
|
||||||
pub hse: Option<Hertz>,
|
|
||||||
pub bypass_hse: bool,
|
|
||||||
pub sys_ck: Option<Hertz>,
|
|
||||||
pub per_ck: Option<Hertz>,
|
|
||||||
pub hclk: Option<Hertz>,
|
|
||||||
pub pclk1: Option<Hertz>,
|
|
||||||
pub pclk2: Option<Hertz>,
|
|
||||||
pub pclk3: Option<Hertz>,
|
|
||||||
pub pclk4: Option<Hertz>,
|
|
||||||
pub pll1: PllConfig,
|
|
||||||
pub pll2: PllConfig,
|
|
||||||
pub pll3: PllConfig,
|
|
||||||
pub adc_clock_source: AdcClockSource,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Setup traceclk
|
|
||||||
/// Returns a pll1_r_ck
|
|
||||||
fn traceclk_setup(config: &mut Config, sys_use_pll1_p: bool) {
|
|
||||||
let pll1_r_ck = match (sys_use_pll1_p, config.pll1.r_ck) {
|
|
||||||
// pll1_p_ck selected as system clock but pll1_r_ck not
|
|
||||||
// set. The traceclk mux is synchronous with the system
|
|
||||||
// clock mux, but has pll1_r_ck as an input. In order to
|
|
||||||
// keep traceclk running, we force a pll1_r_ck.
|
|
||||||
(true, None) => Some(Hertz(unwrap!(config.pll1.p_ck).0 / 2)),
|
|
||||||
|
|
||||||
// Either pll1 not selected as system clock, free choice
|
|
||||||
// of pll1_r_ck. Or pll1 is selected, assume user has set
|
|
||||||
// a suitable pll1_r_ck frequency.
|
|
||||||
_ => config.pll1.r_ck,
|
|
||||||
};
|
|
||||||
config.pll1.r_ck = pll1_r_ck;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Divider calculator for pclk 1 - 4
|
|
||||||
///
|
|
||||||
/// Returns real pclk, bits, ppre and the timer kernel clock
|
|
||||||
fn ppre_calculate(
|
|
||||||
requested_pclk: u32,
|
|
||||||
hclk: u32,
|
|
||||||
max_pclk: u32,
|
|
||||||
tim_pre: Option<Timpre>,
|
|
||||||
) -> (u32, u8, u8, Option<u32>) {
|
|
||||||
let (bits, ppre) = match (hclk + requested_pclk - 1) / requested_pclk {
|
|
||||||
0 => panic!(),
|
|
||||||
1 => (0b000, 1),
|
|
||||||
2 => (0b100, 2),
|
|
||||||
3..=5 => (0b101, 4),
|
|
||||||
6..=11 => (0b110, 8),
|
|
||||||
_ => (0b111, 16),
|
|
||||||
};
|
|
||||||
let real_pclk = hclk / u32::from(ppre);
|
|
||||||
assert!(real_pclk <= max_pclk);
|
|
||||||
|
|
||||||
let tim_ker_clk = if let Some(tim_pre) = tim_pre {
|
|
||||||
let clk = match (bits, tim_pre) {
|
|
||||||
(0b101, Timpre::DEFAULTX2) => hclk / 2,
|
|
||||||
(0b110, Timpre::DEFAULTX4) => hclk / 2,
|
|
||||||
(0b110, Timpre::DEFAULTX2) => hclk / 4,
|
|
||||||
(0b111, Timpre::DEFAULTX4) => hclk / 4,
|
|
||||||
(0b111, Timpre::DEFAULTX2) => hclk / 8,
|
|
||||||
_ => hclk,
|
|
||||||
};
|
|
||||||
Some(clk)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
(real_pclk, bits, ppre, tim_ker_clk)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Setup sys_ck
|
|
||||||
/// Returns sys_ck frequency, and a pll1_p_ck
|
|
||||||
fn sys_ck_setup(config: &mut Config, srcclk: Hertz) -> (Hertz, bool) {
|
|
||||||
// Compare available with wanted clocks
|
|
||||||
let sys_ck = config.sys_ck.unwrap_or(srcclk);
|
|
||||||
|
|
||||||
if sys_ck != srcclk {
|
|
||||||
// The requested system clock is not the immediately available
|
|
||||||
// HSE/HSI clock. Perhaps there are other ways of obtaining
|
|
||||||
// the requested system clock (such as `HSIDIV`) but we will
|
|
||||||
// ignore those for now.
|
|
||||||
//
|
|
||||||
// Therefore we must use pll1_p_ck
|
|
||||||
let pll1_p_ck = match config.pll1.p_ck {
|
|
||||||
Some(p_ck) => {
|
|
||||||
assert!(
|
|
||||||
p_ck == sys_ck,
|
|
||||||
"Error: Cannot set pll1_p_ck independently as it must be used to generate sys_ck"
|
|
||||||
);
|
|
||||||
Some(p_ck)
|
|
||||||
}
|
|
||||||
None => Some(sys_ck),
|
|
||||||
};
|
|
||||||
config.pll1.p_ck = pll1_p_ck;
|
|
||||||
|
|
||||||
(sys_ck, true)
|
|
||||||
} else {
|
|
||||||
// sys_ck is derived directly from a source clock
|
|
||||||
// (HSE/HSI). pll1_p_ck can be as requested
|
|
||||||
(sys_ck, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn flash_setup(rcc_aclk: u32, vos: VoltageScale) {
|
|
||||||
use crate::pac::FLASH;
|
|
||||||
|
|
||||||
// ACLK in MHz, round down and subtract 1 from integers. eg.
|
|
||||||
// 61_999_999 -> 61MHz
|
|
||||||
// 62_000_000 -> 61MHz
|
|
||||||
// 62_000_001 -> 62MHz
|
|
||||||
let rcc_aclk_mhz = (rcc_aclk - 1) / 1_000_000;
|
|
||||||
|
|
||||||
// See RM0433 Rev 7 Table 17. FLASH recommended number of wait
|
|
||||||
// states and programming delay
|
|
||||||
#[cfg(flash_h7)]
|
|
||||||
let (wait_states, progr_delay) = match vos {
|
|
||||||
// VOS 0 range VCORE 1.26V - 1.40V
|
|
||||||
VoltageScale::Scale0 => match rcc_aclk_mhz {
|
|
||||||
0..=69 => (0, 0),
|
|
||||||
70..=139 => (1, 1),
|
|
||||||
140..=184 => (2, 1),
|
|
||||||
185..=209 => (2, 2),
|
|
||||||
210..=224 => (3, 2),
|
|
||||||
225..=239 => (4, 2),
|
|
||||||
_ => (7, 3),
|
|
||||||
},
|
|
||||||
// VOS 1 range VCORE 1.15V - 1.26V
|
|
||||||
VoltageScale::Scale1 => match rcc_aclk_mhz {
|
|
||||||
0..=69 => (0, 0),
|
|
||||||
70..=139 => (1, 1),
|
|
||||||
140..=184 => (2, 1),
|
|
||||||
185..=209 => (2, 2),
|
|
||||||
210..=224 => (3, 2),
|
|
||||||
_ => (7, 3),
|
|
||||||
},
|
|
||||||
// VOS 2 range VCORE 1.05V - 1.15V
|
|
||||||
VoltageScale::Scale2 => match rcc_aclk_mhz {
|
|
||||||
0..=54 => (0, 0),
|
|
||||||
55..=109 => (1, 1),
|
|
||||||
110..=164 => (2, 1),
|
|
||||||
165..=224 => (3, 2),
|
|
||||||
_ => (7, 3),
|
|
||||||
},
|
|
||||||
// VOS 3 range VCORE 0.95V - 1.05V
|
|
||||||
VoltageScale::Scale3 => match rcc_aclk_mhz {
|
|
||||||
0..=44 => (0, 0),
|
|
||||||
45..=89 => (1, 1),
|
|
||||||
90..=134 => (2, 1),
|
|
||||||
135..=179 => (3, 2),
|
|
||||||
180..=224 => (4, 2),
|
|
||||||
_ => (7, 3),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// See RM0455 Rev 10 Table 16. FLASH recommended number of wait
|
|
||||||
// states and programming delay
|
|
||||||
#[cfg(flash_h7ab)]
|
|
||||||
let (wait_states, progr_delay) = match vos {
|
|
||||||
// VOS 0 range VCORE 1.25V - 1.35V
|
|
||||||
VoltageScale::Scale0 => match rcc_aclk_mhz {
|
|
||||||
0..=42 => (0, 0),
|
|
||||||
43..=84 => (1, 0),
|
|
||||||
85..=126 => (2, 1),
|
|
||||||
127..=168 => (3, 1),
|
|
||||||
169..=210 => (4, 2),
|
|
||||||
211..=252 => (5, 2),
|
|
||||||
253..=280 => (6, 3),
|
|
||||||
_ => (7, 3),
|
|
||||||
},
|
|
||||||
// VOS 1 range VCORE 1.15V - 1.25V
|
|
||||||
VoltageScale::Scale1 => match rcc_aclk_mhz {
|
|
||||||
0..=38 => (0, 0),
|
|
||||||
39..=76 => (1, 0),
|
|
||||||
77..=114 => (2, 1),
|
|
||||||
115..=152 => (3, 1),
|
|
||||||
153..=190 => (4, 2),
|
|
||||||
191..=225 => (5, 2),
|
|
||||||
_ => (7, 3),
|
|
||||||
},
|
|
||||||
// VOS 2 range VCORE 1.05V - 1.15V
|
|
||||||
VoltageScale::Scale2 => match rcc_aclk_mhz {
|
|
||||||
0..=34 => (0, 0),
|
|
||||||
35..=68 => (1, 0),
|
|
||||||
69..=102 => (2, 1),
|
|
||||||
103..=136 => (3, 1),
|
|
||||||
137..=160 => (4, 2),
|
|
||||||
_ => (7, 3),
|
|
||||||
},
|
|
||||||
// VOS 3 range VCORE 0.95V - 1.05V
|
|
||||||
VoltageScale::Scale3 => match rcc_aclk_mhz {
|
|
||||||
0..=22 => (0, 0),
|
|
||||||
23..=44 => (1, 0),
|
|
||||||
45..=66 => (2, 1),
|
|
||||||
67..=88 => (3, 1),
|
|
||||||
_ => (7, 3),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
FLASH.acr().write(|w| {
|
|
||||||
w.set_wrhighfreq(progr_delay);
|
|
||||||
w.set_latency(wait_states)
|
|
||||||
});
|
|
||||||
while FLASH.acr().read().latency() != wait_states {}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum McoClock {
|
|
||||||
Disabled,
|
|
||||||
Bypassed,
|
|
||||||
Divided(u8),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl McoClock {
|
|
||||||
fn into_raw(&self) -> u8 {
|
|
||||||
match self {
|
|
||||||
McoClock::Disabled => 0,
|
|
||||||
McoClock::Bypassed => 1,
|
|
||||||
McoClock::Divided(divisor) => {
|
|
||||||
if *divisor > 15 {
|
|
||||||
panic!("Mco divisor must be less than 15. Refer to the reference manual for more information.")
|
|
||||||
}
|
|
||||||
*divisor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub enum Mco1Source {
|
|
||||||
Hsi,
|
|
||||||
Lse,
|
|
||||||
Hse,
|
|
||||||
Pll1Q,
|
|
||||||
Hsi48,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Mco1Source {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::Hsi
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait McoSource {
|
|
||||||
type Raw;
|
|
||||||
|
|
||||||
fn into_raw(&self) -> Self::Raw;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl McoSource for Mco1Source {
|
|
||||||
type Raw = Mco1;
|
|
||||||
fn into_raw(&self) -> Self::Raw {
|
|
||||||
match self {
|
|
||||||
Mco1Source::Hsi => Mco1::HSI,
|
|
||||||
Mco1Source::Lse => Mco1::LSE,
|
|
||||||
Mco1Source::Hse => Mco1::HSE,
|
|
||||||
Mco1Source::Pll1Q => Mco1::PLL1_Q,
|
|
||||||
Mco1Source::Hsi48 => Mco1::HSI48,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
pub enum Mco2Source {
|
|
||||||
SysClk,
|
|
||||||
Pll2Q,
|
|
||||||
Hse,
|
|
||||||
Pll1Q,
|
|
||||||
Csi,
|
|
||||||
Lsi,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Mco2Source {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::SysClk
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl McoSource for Mco2Source {
|
|
||||||
type Raw = Mco2;
|
|
||||||
fn into_raw(&self) -> Self::Raw {
|
|
||||||
match self {
|
|
||||||
Mco2Source::SysClk => Mco2::SYSCLK,
|
|
||||||
Mco2Source::Pll2Q => Mco2::PLL2_P,
|
|
||||||
Mco2Source::Hse => Mco2::HSE,
|
|
||||||
Mco2Source::Pll1Q => Mco2::PLL1_P,
|
|
||||||
Mco2Source::Csi => Mco2::CSI,
|
|
||||||
Mco2Source::Lsi => Mco2::LSI,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) mod sealed {
|
|
||||||
pub trait McoInstance {
|
|
||||||
type Source;
|
|
||||||
unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait McoInstance: sealed::McoInstance + 'static {}
|
|
||||||
|
|
||||||
pin_trait!(McoPin, McoInstance);
|
|
||||||
|
|
||||||
macro_rules! impl_peri {
|
|
||||||
($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => {
|
|
||||||
impl sealed::McoInstance for peripherals::$peri {
|
|
||||||
type Source = $source;
|
|
||||||
|
|
||||||
unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) {
|
|
||||||
RCC.cfgr().modify(|w| {
|
|
||||||
w.$set_source(source);
|
|
||||||
w.$set_prescaler(prescaler);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl McoInstance for peripherals::$peri {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_peri!(MCO1, Mco1, set_mco1, set_mco1pre);
|
|
||||||
impl_peri!(MCO2, Mco2, set_mco2, set_mco2pre);
|
|
||||||
|
|
||||||
pub struct Mco<'d, T: McoInstance> {
|
|
||||||
phantom: PhantomData<&'d mut T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'d, T: McoInstance> Mco<'d, T> {
|
|
||||||
pub fn new(
|
|
||||||
_peri: impl Peripheral<P = T> + 'd,
|
|
||||||
pin: impl Peripheral<P = impl McoPin<T>> + 'd,
|
|
||||||
source: impl McoSource<Raw = T::Source>,
|
|
||||||
prescaler: McoClock,
|
|
||||||
) -> Self {
|
|
||||||
into_ref!(pin);
|
|
||||||
|
|
||||||
critical_section::with(|_| unsafe {
|
|
||||||
T::apply_clock_settings(source.into_raw(), prescaler.into_raw());
|
|
||||||
pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
|
|
||||||
pin.set_speed(Speed::VeryHigh);
|
|
||||||
});
|
|
||||||
|
|
||||||
Self { phantom: PhantomData }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) unsafe fn init(mut config: Config) {
|
|
||||||
// TODO make configurable?
|
|
||||||
let enable_overdrive = false;
|
|
||||||
|
|
||||||
// NB. The lower bytes of CR3 can only be written once after
|
|
||||||
// POR, and must be written with a valid combination. Refer to
|
|
||||||
// RM0433 Rev 7 6.8.4. This is partially enforced by dropping
|
|
||||||
// `self` at the end of this method, but of course we cannot
|
|
||||||
// know what happened between the previous POR and here.
|
|
||||||
#[cfg(pwr_h7)]
|
|
||||||
PWR.cr3().modify(|w| {
|
|
||||||
w.set_scuen(true);
|
|
||||||
w.set_ldoen(true);
|
|
||||||
w.set_bypass(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
#[cfg(pwr_h7smps)]
|
|
||||||
PWR.cr3().modify(|w| {
|
|
||||||
// hardcode "Direct SPMS" for now, this is what works on nucleos with the
|
|
||||||
// default solderbridge configuration.
|
|
||||||
w.set_sden(true);
|
|
||||||
w.set_ldoen(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Validate the supply configuration. If you are stuck here, it is
|
|
||||||
// because the voltages on your board do not match those specified
|
|
||||||
// in the D3CR.VOS and CR3.SDLEVEL fields. By default after reset
|
|
||||||
// VOS = Scale 3, so check that the voltage on the VCAP pins =
|
|
||||||
// 1.0V.
|
|
||||||
while !PWR.csr1().read().actvosrdy() {}
|
|
||||||
|
|
||||||
// Go to Scale 1
|
|
||||||
PWR.d3cr().modify(|w| w.set_vos(0b11));
|
|
||||||
while !PWR.d3cr().read().vosrdy() {}
|
|
||||||
|
|
||||||
let pwr_vos = if !enable_overdrive {
|
|
||||||
VoltageScale::Scale1
|
|
||||||
} else {
|
|
||||||
critical_section::with(|_| {
|
|
||||||
RCC.apb4enr().modify(|w| w.set_syscfgen(true));
|
|
||||||
|
|
||||||
SYSCFG.pwrcr().modify(|w| w.set_oden(1));
|
|
||||||
});
|
|
||||||
while !PWR.d3cr().read().vosrdy() {}
|
|
||||||
VoltageScale::Scale0
|
|
||||||
};
|
|
||||||
|
|
||||||
// Freeze the core clocks, returning a Core Clocks Distribution
|
|
||||||
// and Reset (CCDR) structure. The actual frequency of the clocks
|
|
||||||
// configured is returned in the `clocks` member of the CCDR
|
|
||||||
// structure.
|
|
||||||
//
|
|
||||||
// Note that `freeze` will never result in a clock _faster_ than
|
|
||||||
// that specified. It may result in a clock that is a factor of [1,
|
|
||||||
// 2) slower.
|
|
||||||
//
|
|
||||||
// `syscfg` is required to enable the I/O compensation cell.
|
|
||||||
//
|
|
||||||
// # Panics
|
|
||||||
//
|
|
||||||
// If a clock specification cannot be achieved within the
|
|
||||||
// hardware specification then this function will panic. This
|
|
||||||
// function may also panic if a clock specification can be
|
|
||||||
// achieved, but the mechanism for doing so is not yet
|
|
||||||
// implemented here.
|
|
||||||
|
|
||||||
let srcclk = config.hse.unwrap_or(HSI_FREQ); // Available clocks
|
|
||||||
let (sys_ck, sys_use_pll1_p) = sys_ck_setup(&mut config, srcclk);
|
|
||||||
|
|
||||||
// Configure traceclk from PLL if needed
|
|
||||||
traceclk_setup(&mut config, sys_use_pll1_p);
|
|
||||||
|
|
||||||
let (pll1_p_ck, pll1_q_ck, pll1_r_ck) = pll::pll_setup(srcclk.0, &config.pll1, 0);
|
|
||||||
let (pll2_p_ck, pll2_q_ck, pll2_r_ck) = pll::pll_setup(srcclk.0, &config.pll2, 1);
|
|
||||||
let (pll3_p_ck, pll3_q_ck, pll3_r_ck) = pll::pll_setup(srcclk.0, &config.pll3, 2);
|
|
||||||
|
|
||||||
let sys_ck = if sys_use_pll1_p {
|
|
||||||
Hertz(unwrap!(pll1_p_ck)) // Must have been set by sys_ck_setup
|
|
||||||
} else {
|
|
||||||
sys_ck
|
|
||||||
};
|
|
||||||
|
|
||||||
// This routine does not support HSIDIV != 1. To
|
|
||||||
// do so it would need to ensure all PLLxON bits are clear
|
|
||||||
// before changing the value of HSIDIV
|
|
||||||
let cr = RCC.cr().read();
|
|
||||||
assert!(cr.hsion());
|
|
||||||
assert!(cr.hsidiv() == Hsidiv::DIV1);
|
|
||||||
|
|
||||||
RCC.csr().modify(|w| w.set_lsion(true));
|
|
||||||
while !RCC.csr().read().lsirdy() {}
|
|
||||||
|
|
||||||
// per_ck from HSI by default
|
|
||||||
let (per_ck, ckpersel) = match (config.per_ck == config.hse, config.per_ck) {
|
|
||||||
(true, Some(hse)) => (hse, Ckpersel::HSE), // HSE
|
|
||||||
(_, Some(CSI_FREQ)) => (CSI_FREQ, Ckpersel::CSI), // CSI
|
|
||||||
_ => (HSI_FREQ, Ckpersel::HSI), // HSI
|
|
||||||
};
|
|
||||||
|
|
||||||
// D1 Core Prescaler
|
|
||||||
// Set to 1
|
|
||||||
let d1cpre_bits = 0;
|
|
||||||
let d1cpre_div = 1;
|
|
||||||
let sys_d1cpre_ck = sys_ck.0 / d1cpre_div;
|
|
||||||
|
|
||||||
// Refer to part datasheet "General operating conditions"
|
|
||||||
// table for (rev V). We do not assert checks for earlier
|
|
||||||
// revisions which may have lower limits.
|
|
||||||
let (sys_d1cpre_ck_max, rcc_hclk_max, pclk_max) = match pwr_vos {
|
|
||||||
VoltageScale::Scale0 => (480_000_000, 240_000_000, 120_000_000),
|
|
||||||
VoltageScale::Scale1 => (400_000_000, 200_000_000, 100_000_000),
|
|
||||||
VoltageScale::Scale2 => (300_000_000, 150_000_000, 75_000_000),
|
|
||||||
_ => (200_000_000, 100_000_000, 50_000_000),
|
|
||||||
};
|
|
||||||
assert!(sys_d1cpre_ck <= sys_d1cpre_ck_max);
|
|
||||||
|
|
||||||
let rcc_hclk = config.hclk.map(|v| v.0).unwrap_or(sys_d1cpre_ck / 2);
|
|
||||||
assert!(rcc_hclk <= rcc_hclk_max);
|
|
||||||
|
|
||||||
// Estimate divisor
|
|
||||||
let (hpre_bits, hpre_div) = match (sys_d1cpre_ck + rcc_hclk - 1) / rcc_hclk {
|
|
||||||
0 => panic!(),
|
|
||||||
1 => (Hpre::DIV1, 1),
|
|
||||||
2 => (Hpre::DIV2, 2),
|
|
||||||
3..=5 => (Hpre::DIV4, 4),
|
|
||||||
6..=11 => (Hpre::DIV8, 8),
|
|
||||||
12..=39 => (Hpre::DIV16, 16),
|
|
||||||
40..=95 => (Hpre::DIV64, 64),
|
|
||||||
96..=191 => (Hpre::DIV128, 128),
|
|
||||||
192..=383 => (Hpre::DIV256, 256),
|
|
||||||
_ => (Hpre::DIV512, 512),
|
|
||||||
};
|
|
||||||
// Calculate real AXI and AHB clock
|
|
||||||
let rcc_hclk = sys_d1cpre_ck / hpre_div;
|
|
||||||
assert!(rcc_hclk <= rcc_hclk_max);
|
|
||||||
let rcc_aclk = rcc_hclk; // AXI clock is always equal to AHB clock on H7
|
|
||||||
// Timer prescaler selection
|
|
||||||
let timpre = Timpre::DEFAULTX2;
|
|
||||||
|
|
||||||
let requested_pclk1 = config.pclk1.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
|
|
||||||
let (rcc_pclk1, ppre1_bits, ppre1, rcc_timerx_ker_ck) =
|
|
||||||
ppre_calculate(requested_pclk1, rcc_hclk, pclk_max, Some(timpre));
|
|
||||||
|
|
||||||
let requested_pclk2 = config.pclk2.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
|
|
||||||
let (rcc_pclk2, ppre2_bits, ppre2, rcc_timery_ker_ck) =
|
|
||||||
ppre_calculate(requested_pclk2, rcc_hclk, pclk_max, Some(timpre));
|
|
||||||
|
|
||||||
let requested_pclk3 = config.pclk3.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
|
|
||||||
let (rcc_pclk3, ppre3_bits, ppre3, _) = ppre_calculate(requested_pclk3, rcc_hclk, pclk_max, None);
|
|
||||||
|
|
||||||
let requested_pclk4 = config.pclk4.map(|v| v.0).unwrap_or_else(|| pclk_max.min(rcc_hclk / 2));
|
|
||||||
let (rcc_pclk4, ppre4_bits, ppre4, _) = ppre_calculate(requested_pclk4, rcc_hclk, pclk_max, None);
|
|
||||||
|
|
||||||
// Start switching clocks -------------------
|
|
||||||
|
|
||||||
// Ensure CSI is on and stable
|
|
||||||
RCC.cr().modify(|w| w.set_csion(true));
|
|
||||||
while !RCC.cr().read().csirdy() {}
|
|
||||||
|
|
||||||
// Ensure HSI48 is on and stable
|
|
||||||
RCC.cr().modify(|w| w.set_hsi48on(true));
|
|
||||||
while !RCC.cr().read().hsi48on() {}
|
|
||||||
|
|
||||||
// XXX: support MCO ?
|
|
||||||
|
|
||||||
let hse_ck = match config.hse {
|
|
||||||
Some(hse) => {
|
|
||||||
// Ensure HSE is on and stable
|
|
||||||
RCC.cr().modify(|w| {
|
|
||||||
w.set_hseon(true);
|
|
||||||
w.set_hsebyp(config.bypass_hse);
|
|
||||||
});
|
|
||||||
while !RCC.cr().read().hserdy() {}
|
|
||||||
Some(hse)
|
|
||||||
}
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let pllsrc = if config.hse.is_some() { Pllsrc::HSE } else { Pllsrc::HSI };
|
|
||||||
RCC.pllckselr().modify(|w| w.set_pllsrc(pllsrc));
|
|
||||||
|
|
||||||
let enable_pll = |pll| {
|
|
||||||
RCC.cr().modify(|w| w.set_pllon(pll, true));
|
|
||||||
while !RCC.cr().read().pllrdy(pll) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
if pll1_p_ck.is_some() {
|
|
||||||
enable_pll(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if pll2_p_ck.is_some() {
|
|
||||||
enable_pll(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if pll3_p_ck.is_some() {
|
|
||||||
enable_pll(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Core Prescaler / AHB Prescaler / APB3 Prescaler
|
|
||||||
RCC.d1cfgr().modify(|w| {
|
|
||||||
w.set_d1cpre(Hpre::from_bits(d1cpre_bits));
|
|
||||||
w.set_d1ppre(Dppre::from_bits(ppre3_bits));
|
|
||||||
w.set_hpre(hpre_bits)
|
|
||||||
});
|
|
||||||
// Ensure core prescaler value is valid before future lower
|
|
||||||
// core voltage
|
|
||||||
while RCC.d1cfgr().read().d1cpre().to_bits() != d1cpre_bits {}
|
|
||||||
|
|
||||||
flash_setup(rcc_aclk, pwr_vos);
|
|
||||||
|
|
||||||
// APB1 / APB2 Prescaler
|
|
||||||
RCC.d2cfgr().modify(|w| {
|
|
||||||
w.set_d2ppre1(Dppre::from_bits(ppre1_bits));
|
|
||||||
w.set_d2ppre2(Dppre::from_bits(ppre2_bits));
|
|
||||||
});
|
|
||||||
|
|
||||||
// APB4 Prescaler
|
|
||||||
RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre::from_bits(ppre4_bits)));
|
|
||||||
|
|
||||||
// Peripheral Clock (per_ck)
|
|
||||||
RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel));
|
|
||||||
|
|
||||||
// ADC clock MUX
|
|
||||||
RCC.d3ccipr().modify(|w| w.set_adcsel(config.adc_clock_source.adcsel()));
|
|
||||||
|
|
||||||
let adc_ker_ck = match config.adc_clock_source {
|
|
||||||
AdcClockSource::Pll2PCk => pll2_p_ck.map(Hertz),
|
|
||||||
AdcClockSource::Pll3RCk => pll3_r_ck.map(Hertz),
|
|
||||||
AdcClockSource::PerCk => Some(per_ck),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set timer clocks prescaler setting
|
|
||||||
RCC.cfgr().modify(|w| w.set_timpre(timpre));
|
|
||||||
|
|
||||||
// Select system clock source
|
|
||||||
let sw = match (sys_use_pll1_p, config.hse.is_some()) {
|
|
||||||
(true, _) => Sw::PLL1,
|
|
||||||
(false, true) => Sw::HSE,
|
|
||||||
_ => Sw::HSI,
|
|
||||||
};
|
|
||||||
RCC.cfgr().modify(|w| w.set_sw(sw));
|
|
||||||
while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {}
|
|
||||||
|
|
||||||
// IO compensation cell - Requires CSI clock and SYSCFG
|
|
||||||
assert!(RCC.cr().read().csirdy());
|
|
||||||
RCC.apb4enr().modify(|w| w.set_syscfgen(true));
|
|
||||||
|
|
||||||
// Enable the compensation cell, using back-bias voltage code
|
|
||||||
// provide by the cell.
|
|
||||||
critical_section::with(|_| {
|
|
||||||
SYSCFG.cccsr().modify(|w| {
|
|
||||||
w.set_en(true);
|
|
||||||
w.set_cs(false);
|
|
||||||
w.set_hslv(false);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
while !SYSCFG.cccsr().read().ready() {}
|
|
||||||
|
|
||||||
let core_clocks = CoreClocks {
|
|
||||||
hclk: Hertz(rcc_hclk),
|
|
||||||
pclk1: Hertz(rcc_pclk1),
|
|
||||||
pclk2: Hertz(rcc_pclk2),
|
|
||||||
pclk3: Hertz(rcc_pclk3),
|
|
||||||
pclk4: Hertz(rcc_pclk4),
|
|
||||||
ppre1,
|
|
||||||
ppre2,
|
|
||||||
ppre3,
|
|
||||||
ppre4,
|
|
||||||
csi_ck: Some(CSI_FREQ),
|
|
||||||
hsi_ck: Some(HSI_FREQ),
|
|
||||||
hsi48_ck: Some(HSI48_FREQ),
|
|
||||||
lsi_ck: Some(LSI_FREQ),
|
|
||||||
per_ck: Some(per_ck),
|
|
||||||
hse_ck,
|
|
||||||
pll1_p_ck: pll1_p_ck.map(Hertz),
|
|
||||||
pll1_q_ck: pll1_q_ck.map(Hertz),
|
|
||||||
pll1_r_ck: pll1_r_ck.map(Hertz),
|
|
||||||
pll2_p_ck: pll2_p_ck.map(Hertz),
|
|
||||||
pll2_q_ck: pll2_q_ck.map(Hertz),
|
|
||||||
pll2_r_ck: pll2_r_ck.map(Hertz),
|
|
||||||
pll3_p_ck: pll3_p_ck.map(Hertz),
|
|
||||||
pll3_q_ck: pll3_q_ck.map(Hertz),
|
|
||||||
pll3_r_ck: pll3_r_ck.map(Hertz),
|
|
||||||
timx_ker_ck: rcc_timerx_ker_ck.map(Hertz),
|
|
||||||
timy_ker_ck: rcc_timery_ker_ck.map(Hertz),
|
|
||||||
adc_ker_ck,
|
|
||||||
sys_ck,
|
|
||||||
c_ck: Hertz(sys_d1cpre_ck),
|
|
||||||
};
|
|
||||||
|
|
||||||
set_freqs(Clocks {
|
|
||||||
sys: core_clocks.c_ck,
|
|
||||||
ahb1: core_clocks.hclk,
|
|
||||||
ahb2: core_clocks.hclk,
|
|
||||||
ahb3: core_clocks.hclk,
|
|
||||||
ahb4: core_clocks.hclk,
|
|
||||||
apb1: core_clocks.pclk1,
|
|
||||||
apb2: core_clocks.pclk2,
|
|
||||||
apb4: core_clocks.pclk4,
|
|
||||||
apb1_tim: core_clocks.timx_ker_ck.unwrap_or(core_clocks.pclk1),
|
|
||||||
apb2_tim: core_clocks.timy_ker_ck.unwrap_or(core_clocks.pclk2),
|
|
||||||
adc: core_clocks.adc_ker_ck,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
mod pll {
|
|
||||||
use super::{Hertz, RCC};
|
|
||||||
|
|
||||||
const VCO_MIN: u32 = 150_000_000;
|
|
||||||
const VCO_MAX: u32 = 420_000_000;
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct PllConfig {
|
|
||||||
pub p_ck: Option<Hertz>,
|
|
||||||
pub q_ck: Option<Hertz>,
|
|
||||||
pub r_ck: Option<Hertz>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) struct PllConfigResults {
|
|
||||||
pub ref_x_ck: u32,
|
|
||||||
pub pll_x_m: u32,
|
|
||||||
pub pll_x_p: u32,
|
|
||||||
pub vco_ck_target: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vco_output_divider_setup(output: u32, plln: usize) -> (u32, u32) {
|
|
||||||
let pll_x_p = if plln == 0 {
|
|
||||||
if output > VCO_MAX / 2 {
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
((VCO_MAX / output) | 1) - 1 // Must be even or unity
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Specific to PLL2/3, will subtract 1 later
|
|
||||||
if output > VCO_MAX / 2 {
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
VCO_MAX / output
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let vco_ck = output * pll_x_p;
|
|
||||||
|
|
||||||
assert!(pll_x_p < 128);
|
|
||||||
assert!(vco_ck >= VCO_MIN);
|
|
||||||
assert!(vco_ck <= VCO_MAX);
|
|
||||||
|
|
||||||
(vco_ck, pll_x_p)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// Must have exclusive access to the RCC register block
|
|
||||||
fn vco_setup(pll_src: u32, requested_output: u32, plln: usize) -> PllConfigResults {
|
|
||||||
use crate::pac::rcc::vals::{Pllrge, Pllvcosel};
|
|
||||||
|
|
||||||
let (vco_ck_target, pll_x_p) = vco_output_divider_setup(requested_output, plln);
|
|
||||||
|
|
||||||
// Input divisor, resulting in a reference clock in the range
|
|
||||||
// 1 to 2 MHz. Choose the highest reference clock (lowest m)
|
|
||||||
let pll_x_m = (pll_src + 1_999_999) / 2_000_000;
|
|
||||||
assert!(pll_x_m < 64);
|
|
||||||
|
|
||||||
// Calculate resulting reference clock
|
|
||||||
let ref_x_ck = pll_src / pll_x_m;
|
|
||||||
assert!((1_000_000..=2_000_000).contains(&ref_x_ck));
|
|
||||||
|
|
||||||
RCC.pllcfgr().modify(|w| {
|
|
||||||
w.set_pllvcosel(plln, Pllvcosel::MEDIUMVCO);
|
|
||||||
w.set_pllrge(plln, Pllrge::RANGE1);
|
|
||||||
});
|
|
||||||
PllConfigResults {
|
|
||||||
ref_x_ck,
|
|
||||||
pll_x_m,
|
|
||||||
pll_x_p,
|
|
||||||
vco_ck_target,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// Must have exclusive access to the RCC register block
|
|
||||||
pub(super) fn pll_setup(pll_src: u32, config: &PllConfig, plln: usize) -> (Option<u32>, Option<u32>, Option<u32>) {
|
|
||||||
use crate::pac::rcc::vals::Divp;
|
|
||||||
|
|
||||||
match config.p_ck {
|
|
||||||
Some(requested_output) => {
|
|
||||||
let config_results = vco_setup(pll_src, requested_output.0, plln);
|
|
||||||
let PllConfigResults {
|
|
||||||
ref_x_ck,
|
|
||||||
pll_x_m,
|
|
||||||
pll_x_p,
|
|
||||||
vco_ck_target,
|
|
||||||
} = config_results;
|
|
||||||
|
|
||||||
RCC.pllckselr().modify(|w| w.set_divm(plln, pll_x_m as u8));
|
|
||||||
|
|
||||||
// Feedback divider. Integer only
|
|
||||||
let pll_x_n = vco_ck_target / ref_x_ck;
|
|
||||||
assert!(pll_x_n >= 4);
|
|
||||||
assert!(pll_x_n <= 512);
|
|
||||||
RCC.plldivr(plln).modify(|w| w.set_divn1((pll_x_n - 1) as u16));
|
|
||||||
|
|
||||||
// No FRACN
|
|
||||||
RCC.pllcfgr().modify(|w| w.set_pllfracen(plln, false));
|
|
||||||
let vco_ck = ref_x_ck * pll_x_n;
|
|
||||||
|
|
||||||
RCC.plldivr(plln)
|
|
||||||
.modify(|w| w.set_divp1(Divp::from_bits((pll_x_p - 1) as u8)));
|
|
||||||
RCC.pllcfgr().modify(|w| w.set_divpen(plln, true));
|
|
||||||
|
|
||||||
// Calulate additional output dividers
|
|
||||||
let q_ck = match config.q_ck {
|
|
||||||
Some(Hertz(ck)) if ck > 0 => {
|
|
||||||
let div = (vco_ck + ck - 1) / ck;
|
|
||||||
RCC.plldivr(plln).modify(|w| w.set_divq1((div - 1) as u8));
|
|
||||||
RCC.pllcfgr().modify(|w| w.set_divqen(plln, true));
|
|
||||||
Some(vco_ck / div)
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
let r_ck = match config.r_ck {
|
|
||||||
Some(Hertz(ck)) if ck > 0 => {
|
|
||||||
let div = (vco_ck + ck - 1) / ck;
|
|
||||||
RCC.plldivr(plln).modify(|w| w.set_divr1((div - 1) as u8));
|
|
||||||
RCC.pllcfgr().modify(|w| w.set_divren(plln, true));
|
|
||||||
Some(vco_ck / div)
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
(Some(vco_ck / pll_x_p), q_ck, r_ck)
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
assert!(
|
|
||||||
config.q_ck.is_none(),
|
|
||||||
"Must set PLL P clock for Q clock to take effect!"
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
config.r_ck.is_none(),
|
|
||||||
"Must set PLL P clock for R clock to take effect!"
|
|
||||||
);
|
|
||||||
(None, None, None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +1,11 @@
|
|||||||
|
use super::bd::BackupDomain;
|
||||||
pub use super::bus::{AHBPrescaler, APBPrescaler};
|
pub use super::bus::{AHBPrescaler, APBPrescaler};
|
||||||
|
use super::RtcClockSource;
|
||||||
|
pub use crate::pac::pwr::vals::Vos as VoltageScale;
|
||||||
use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
|
use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
|
||||||
use crate::pac::RCC;
|
|
||||||
#[cfg(crs)]
|
#[cfg(crs)]
|
||||||
use crate::pac::{crs, CRS, SYSCFG};
|
use crate::pac::{crs, CRS, SYSCFG};
|
||||||
|
use crate::pac::{FLASH, PWR, RCC};
|
||||||
use crate::rcc::{set_freqs, Clocks};
|
use crate::rcc::{set_freqs, Clocks};
|
||||||
use crate::time::Hertz;
|
use crate::time::Hertz;
|
||||||
|
|
||||||
@ -135,6 +138,10 @@ pub struct Config {
|
|||||||
pub apb2_pre: APBPrescaler,
|
pub apb2_pre: APBPrescaler,
|
||||||
#[cfg(crs)]
|
#[cfg(crs)]
|
||||||
pub enable_hsi48: bool,
|
pub enable_hsi48: bool,
|
||||||
|
pub rtc: Option<RtcClockSource>,
|
||||||
|
pub lse: Option<Hertz>,
|
||||||
|
pub lsi: bool,
|
||||||
|
pub voltage_scale: VoltageScale,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
@ -142,16 +149,25 @@ impl Default for Config {
|
|||||||
fn default() -> Config {
|
fn default() -> Config {
|
||||||
Config {
|
Config {
|
||||||
mux: ClockSrc::MSI(MSIRange::default()),
|
mux: ClockSrc::MSI(MSIRange::default()),
|
||||||
ahb_pre: AHBPrescaler::NotDivided,
|
ahb_pre: AHBPrescaler::DIV1,
|
||||||
apb1_pre: APBPrescaler::NotDivided,
|
apb1_pre: APBPrescaler::DIV1,
|
||||||
apb2_pre: APBPrescaler::NotDivided,
|
apb2_pre: APBPrescaler::DIV1,
|
||||||
#[cfg(crs)]
|
#[cfg(crs)]
|
||||||
enable_hsi48: false,
|
enable_hsi48: false,
|
||||||
|
rtc: None,
|
||||||
|
lse: None,
|
||||||
|
lsi: false,
|
||||||
|
voltage_scale: VoltageScale::RANGE1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn init(config: Config) {
|
pub(crate) unsafe fn init(config: Config) {
|
||||||
|
// Set voltage scale
|
||||||
|
while PWR.csr().read().vosf() {}
|
||||||
|
PWR.cr().write(|w| w.set_vos(config.voltage_scale));
|
||||||
|
while PWR.csr().read().vosf() {}
|
||||||
|
|
||||||
let (sys_clk, sw) = match config.mux {
|
let (sys_clk, sw) = match config.mux {
|
||||||
ClockSrc::MSI(range) => {
|
ClockSrc::MSI(range) => {
|
||||||
// Set MSI range
|
// Set MSI range
|
||||||
@ -231,6 +247,28 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BackupDomain::configure_ls(
|
||||||
|
config.rtc.unwrap_or(RtcClockSource::NOCLOCK),
|
||||||
|
config.lsi,
|
||||||
|
config.lse.map(|_| Default::default()),
|
||||||
|
);
|
||||||
|
|
||||||
|
let wait_states = match config.voltage_scale {
|
||||||
|
VoltageScale::RANGE1 => match sys_clk {
|
||||||
|
..=16_000_000 => 0,
|
||||||
|
_ => 1,
|
||||||
|
},
|
||||||
|
VoltageScale::RANGE2 => match sys_clk {
|
||||||
|
..=8_000_000 => 0,
|
||||||
|
_ => 1,
|
||||||
|
},
|
||||||
|
VoltageScale::RANGE3 => 0,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
FLASH.acr().modify(|w| {
|
||||||
|
w.set_latency(wait_states != 0);
|
||||||
|
});
|
||||||
|
|
||||||
RCC.cfgr().modify(|w| {
|
RCC.cfgr().modify(|w| {
|
||||||
w.set_sw(sw);
|
w.set_sw(sw);
|
||||||
w.set_hpre(config.ahb_pre.into());
|
w.set_hpre(config.ahb_pre.into());
|
||||||
@ -239,7 +277,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let ahb_freq: u32 = match config.ahb_pre {
|
let ahb_freq: u32 = match config.ahb_pre {
|
||||||
AHBPrescaler::NotDivided => sys_clk,
|
AHBPrescaler::DIV1 => sys_clk,
|
||||||
pre => {
|
pre => {
|
||||||
let pre: Hpre = pre.into();
|
let pre: Hpre = pre.into();
|
||||||
let pre = 1 << (pre.to_bits() as u32 - 7);
|
let pre = 1 << (pre.to_bits() as u32 - 7);
|
||||||
@ -248,7 +286,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
|
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
|
||||||
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
|
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||||
pre => {
|
pre => {
|
||||||
let pre: Ppre = pre.into();
|
let pre: Ppre = pre.into();
|
||||||
let pre: u8 = 1 << (pre.to_bits() - 3);
|
let pre: u8 = 1 << (pre.to_bits() - 3);
|
||||||
@ -258,7 +296,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
|
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
|
||||||
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
|
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||||
pre => {
|
pre => {
|
||||||
let pre: Ppre = pre.into();
|
let pre: Ppre = pre.into();
|
||||||
let pre: u8 = 1 << (pre.to_bits() - 3);
|
let pre: u8 = 1 << (pre.to_bits() - 3);
|
||||||
@ -269,13 +307,6 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
|
|
||||||
#[cfg(crs)]
|
#[cfg(crs)]
|
||||||
if config.enable_hsi48 {
|
if config.enable_hsi48 {
|
||||||
// Reset SYSCFG peripheral
|
|
||||||
RCC.apb2rstr().modify(|w| w.set_syscfgrst(true));
|
|
||||||
RCC.apb2rstr().modify(|w| w.set_syscfgrst(false));
|
|
||||||
|
|
||||||
// Enable SYSCFG peripheral
|
|
||||||
RCC.apb2enr().modify(|w| w.set_syscfgen(true));
|
|
||||||
|
|
||||||
// Reset CRS peripheral
|
// Reset CRS peripheral
|
||||||
RCC.apb1rstr().modify(|w| w.set_crsrst(true));
|
RCC.apb1rstr().modify(|w| w.set_crsrst(true));
|
||||||
RCC.apb1rstr().modify(|w| w.set_crsrst(false));
|
RCC.apb1rstr().modify(|w| w.set_crsrst(false));
|
||||||
|
@ -138,9 +138,9 @@ impl Default for Config {
|
|||||||
fn default() -> Config {
|
fn default() -> Config {
|
||||||
Config {
|
Config {
|
||||||
mux: ClockSrc::MSI(MSIRange::default()),
|
mux: ClockSrc::MSI(MSIRange::default()),
|
||||||
ahb_pre: AHBPrescaler::NotDivided,
|
ahb_pre: AHBPrescaler::DIV1,
|
||||||
apb1_pre: APBPrescaler::NotDivided,
|
apb1_pre: APBPrescaler::DIV1,
|
||||||
apb2_pre: APBPrescaler::NotDivided,
|
apb2_pre: APBPrescaler::DIV1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -240,7 +240,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let ahb_freq: u32 = match config.ahb_pre {
|
let ahb_freq: u32 = match config.ahb_pre {
|
||||||
AHBPrescaler::NotDivided => sys_clk,
|
AHBPrescaler::DIV1 => sys_clk,
|
||||||
pre => {
|
pre => {
|
||||||
let pre: Hpre = pre.into();
|
let pre: Hpre = pre.into();
|
||||||
let pre = 1 << (pre.to_bits() as u32 - 7);
|
let pre = 1 << (pre.to_bits() as u32 - 7);
|
||||||
@ -249,7 +249,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
|
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
|
||||||
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
|
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||||
pre => {
|
pre => {
|
||||||
let pre: Ppre = pre.into();
|
let pre: Ppre = pre.into();
|
||||||
let pre: u8 = 1 << (pre.to_bits() - 3);
|
let pre: u8 = 1 << (pre.to_bits() - 3);
|
||||||
@ -259,7 +259,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
|
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
|
||||||
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
|
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||||
pre => {
|
pre => {
|
||||||
let pre: Ppre = pre.into();
|
let pre: Ppre = pre.into();
|
||||||
let pre: u8 = 1 << (pre.to_bits() - 3);
|
let pre: u8 = 1 << (pre.to_bits() - 3);
|
||||||
|
@ -241,6 +241,8 @@ pub struct Config {
|
|||||||
#[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
|
#[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
|
||||||
pub hsi48: bool,
|
pub hsi48: bool,
|
||||||
pub rtc_mux: RtcClockSource,
|
pub rtc_mux: RtcClockSource,
|
||||||
|
pub lse: Option<Hertz>,
|
||||||
|
pub lsi: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
@ -248,13 +250,15 @@ impl Default for Config {
|
|||||||
fn default() -> Config {
|
fn default() -> Config {
|
||||||
Config {
|
Config {
|
||||||
mux: ClockSrc::MSI(MSIRange::Range6),
|
mux: ClockSrc::MSI(MSIRange::Range6),
|
||||||
ahb_pre: AHBPrescaler::NotDivided,
|
ahb_pre: AHBPrescaler::DIV1,
|
||||||
apb1_pre: APBPrescaler::NotDivided,
|
apb1_pre: APBPrescaler::DIV1,
|
||||||
apb2_pre: APBPrescaler::NotDivided,
|
apb2_pre: APBPrescaler::DIV1,
|
||||||
pllsai1: None,
|
pllsai1: None,
|
||||||
#[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
|
#[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
|
||||||
hsi48: false,
|
hsi48: false,
|
||||||
rtc_mux: RtcClockSource::LSI,
|
rtc_mux: RtcClockSource::LSI,
|
||||||
|
lsi: true,
|
||||||
|
lse: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -405,9 +409,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
while RCC.cfgr().read().sws() != Sw::MSI {}
|
while RCC.cfgr().read().sws() != Sw::MSI {}
|
||||||
}
|
}
|
||||||
|
|
||||||
RCC.apb1enr1().modify(|w| w.set_pwren(true));
|
BackupDomain::configure_ls(config.rtc_mux, config.lsi, config.lse.map(|_| Default::default()));
|
||||||
|
|
||||||
BackupDomain::configure_ls(config.rtc_mux, None);
|
|
||||||
|
|
||||||
let (sys_clk, sw) = match config.mux {
|
let (sys_clk, sw) = match config.mux {
|
||||||
ClockSrc::MSI(range) => {
|
ClockSrc::MSI(range) => {
|
||||||
@ -576,7 +578,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let ahb_freq: u32 = match config.ahb_pre {
|
let ahb_freq: u32 = match config.ahb_pre {
|
||||||
AHBPrescaler::NotDivided => sys_clk,
|
AHBPrescaler::DIV1 => sys_clk,
|
||||||
pre => {
|
pre => {
|
||||||
let pre: Hpre = pre.into();
|
let pre: Hpre = pre.into();
|
||||||
let pre = 1 << (pre.to_bits() as u32 - 7);
|
let pre = 1 << (pre.to_bits() as u32 - 7);
|
||||||
@ -585,7 +587,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
|
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
|
||||||
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
|
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||||
pre => {
|
pre => {
|
||||||
let pre: Ppre = pre.into();
|
let pre: Ppre = pre.into();
|
||||||
let pre: u8 = 1 << (pre.to_bits() - 3);
|
let pre: u8 = 1 << (pre.to_bits() - 3);
|
||||||
@ -595,7 +597,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
|
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
|
||||||
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
|
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||||
pre => {
|
pre => {
|
||||||
let pre: Ppre = pre.into();
|
let pre: Ppre = pre.into();
|
||||||
let pre: u8 = 1 << (pre.to_bits() - 3);
|
let pre: u8 = 1 << (pre.to_bits() - 3);
|
||||||
@ -604,8 +606,6 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
RCC.apb1enr1().modify(|w| w.set_pwren(true));
|
|
||||||
|
|
||||||
set_freqs(Clocks {
|
set_freqs(Clocks {
|
||||||
sys: Hertz(sys_clk),
|
sys: Hertz(sys_clk),
|
||||||
ahb1: Hertz(ahb_freq),
|
ahb1: Hertz(ahb_freq),
|
||||||
|
@ -238,9 +238,9 @@ impl Default for Config {
|
|||||||
fn default() -> Config {
|
fn default() -> Config {
|
||||||
Config {
|
Config {
|
||||||
mux: ClockSrc::MSI(MSIRange::Range6),
|
mux: ClockSrc::MSI(MSIRange::Range6),
|
||||||
ahb_pre: AHBPrescaler::NotDivided,
|
ahb_pre: AHBPrescaler::DIV1,
|
||||||
apb1_pre: APBPrescaler::NotDivided,
|
apb1_pre: APBPrescaler::DIV1,
|
||||||
apb2_pre: APBPrescaler::NotDivided,
|
apb2_pre: APBPrescaler::DIV1,
|
||||||
pllsai1: None,
|
pllsai1: None,
|
||||||
hsi48: false,
|
hsi48: false,
|
||||||
}
|
}
|
||||||
@ -317,11 +317,6 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
|
|
||||||
let freq = (src_freq / prediv.to_div() * mul.to_mul()) / div.to_div();
|
let freq = (src_freq / prediv.to_div() * mul.to_mul()) / div.to_div();
|
||||||
|
|
||||||
#[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx))]
|
|
||||||
assert!(freq <= 120_000_000);
|
|
||||||
#[cfg(not(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx)))]
|
|
||||||
assert!(freq <= 80_000_000);
|
|
||||||
|
|
||||||
RCC.pllcfgr().write(move |w| {
|
RCC.pllcfgr().write(move |w| {
|
||||||
w.set_plln(mul.into());
|
w.set_plln(mul.into());
|
||||||
w.set_pllm(prediv.into());
|
w.set_pllm(prediv.into());
|
||||||
@ -407,7 +402,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let ahb_freq: u32 = match config.ahb_pre {
|
let ahb_freq: u32 = match config.ahb_pre {
|
||||||
AHBPrescaler::NotDivided => sys_clk,
|
AHBPrescaler::DIV1 => sys_clk,
|
||||||
pre => {
|
pre => {
|
||||||
let pre: Hpre = pre.into();
|
let pre: Hpre = pre.into();
|
||||||
let pre = 1 << (pre.to_bits() as u32 - 7);
|
let pre = 1 << (pre.to_bits() as u32 - 7);
|
||||||
@ -416,7 +411,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
|
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
|
||||||
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
|
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||||
pre => {
|
pre => {
|
||||||
let pre: Ppre = pre.into();
|
let pre: Ppre = pre.into();
|
||||||
let pre: u8 = 1 << (pre.to_bits() - 3);
|
let pre: u8 = 1 << (pre.to_bits() - 3);
|
||||||
@ -426,7 +421,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
|
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
|
||||||
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
|
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||||
pre => {
|
pre => {
|
||||||
let pre: Ppre = pre.into();
|
let pre: Ppre = pre.into();
|
||||||
let pre: u8 = 1 << (pre.to_bits() - 3);
|
let pre: u8 = 1 << (pre.to_bits() - 3);
|
||||||
|
71
embassy-stm32/src/rcc/mco.rs
Normal file
71
embassy-stm32/src/rcc/mco.rs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
use embassy_hal_internal::into_ref;
|
||||||
|
|
||||||
|
use crate::gpio::sealed::AFType;
|
||||||
|
use crate::gpio::Speed;
|
||||||
|
pub use crate::pac::rcc::vals::{Mco1 as Mco1Source, Mco2 as Mco2Source};
|
||||||
|
use crate::pac::RCC;
|
||||||
|
use crate::{peripherals, Peripheral};
|
||||||
|
|
||||||
|
pub(crate) mod sealed {
|
||||||
|
pub trait McoInstance {
|
||||||
|
type Source;
|
||||||
|
unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait McoInstance: sealed::McoInstance + 'static {}
|
||||||
|
|
||||||
|
pin_trait!(McoPin, McoInstance);
|
||||||
|
|
||||||
|
macro_rules! impl_peri {
|
||||||
|
($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => {
|
||||||
|
impl sealed::McoInstance for peripherals::$peri {
|
||||||
|
type Source = $source;
|
||||||
|
|
||||||
|
unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) {
|
||||||
|
RCC.cfgr().modify(|w| {
|
||||||
|
w.$set_source(source);
|
||||||
|
w.$set_prescaler(prescaler);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl McoInstance for peripherals::$peri {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_peri!(MCO1, Mco1Source, set_mco1, set_mco1pre);
|
||||||
|
impl_peri!(MCO2, Mco2Source, set_mco2, set_mco2pre);
|
||||||
|
|
||||||
|
pub struct Mco<'d, T: McoInstance> {
|
||||||
|
phantom: PhantomData<&'d mut T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'d, T: McoInstance> Mco<'d, T> {
|
||||||
|
/// Create a new MCO instance.
|
||||||
|
///
|
||||||
|
/// `prescaler` must be between 1 and 15.
|
||||||
|
pub fn new(
|
||||||
|
_peri: impl Peripheral<P = T> + 'd,
|
||||||
|
pin: impl Peripheral<P = impl McoPin<T>> + 'd,
|
||||||
|
source: T::Source,
|
||||||
|
prescaler: u8,
|
||||||
|
) -> Self {
|
||||||
|
into_ref!(pin);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
1 <= prescaler && prescaler <= 15,
|
||||||
|
"Mco prescaler must be between 1 and 15. Refer to the reference manual for more information."
|
||||||
|
);
|
||||||
|
|
||||||
|
critical_section::with(|_| unsafe {
|
||||||
|
T::apply_clock_settings(source, prescaler);
|
||||||
|
pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
|
||||||
|
pin.set_speed(Speed::VeryHigh);
|
||||||
|
});
|
||||||
|
|
||||||
|
Self { phantom: PhantomData }
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,17 @@
|
|||||||
#![macro_use]
|
#![macro_use]
|
||||||
|
|
||||||
pub(crate) mod bd;
|
|
||||||
pub mod bus;
|
|
||||||
use core::mem::MaybeUninit;
|
use core::mem::MaybeUninit;
|
||||||
|
|
||||||
pub use crate::rcc::bd::RtcClockSource;
|
pub use crate::rcc::bd::RtcClockSource;
|
||||||
use crate::time::Hertz;
|
use crate::time::Hertz;
|
||||||
|
|
||||||
|
pub(crate) mod bd;
|
||||||
|
mod bus;
|
||||||
|
#[cfg(any(stm32h5, stm32h7))]
|
||||||
|
mod mco;
|
||||||
|
#[cfg(any(stm32h5, stm32h7))]
|
||||||
|
pub use mco::*;
|
||||||
|
|
||||||
#[cfg_attr(rcc_f0, path = "f0.rs")]
|
#[cfg_attr(rcc_f0, path = "f0.rs")]
|
||||||
#[cfg_attr(any(rcc_f1, rcc_f100, rcc_f1cl), path = "f1.rs")]
|
#[cfg_attr(any(rcc_f1, rcc_f100, rcc_f1cl), path = "f1.rs")]
|
||||||
#[cfg_attr(rcc_f2, path = "f2.rs")]
|
#[cfg_attr(rcc_f2, path = "f2.rs")]
|
||||||
@ -16,20 +21,30 @@ use crate::time::Hertz;
|
|||||||
#[cfg_attr(rcc_c0, path = "c0.rs")]
|
#[cfg_attr(rcc_c0, path = "c0.rs")]
|
||||||
#[cfg_attr(rcc_g0, path = "g0.rs")]
|
#[cfg_attr(rcc_g0, path = "g0.rs")]
|
||||||
#[cfg_attr(rcc_g4, path = "g4.rs")]
|
#[cfg_attr(rcc_g4, path = "g4.rs")]
|
||||||
#[cfg_attr(any(rcc_h7, rcc_h7ab), path = "h7.rs")]
|
#[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab), path = "h.rs")]
|
||||||
#[cfg_attr(rcc_l0, path = "l0.rs")]
|
#[cfg_attr(rcc_l0, path = "l0.rs")]
|
||||||
#[cfg_attr(rcc_l1, path = "l1.rs")]
|
#[cfg_attr(rcc_l1, path = "l1.rs")]
|
||||||
#[cfg_attr(rcc_l4, path = "l4.rs")]
|
#[cfg_attr(rcc_l4, path = "l4.rs")]
|
||||||
#[cfg_attr(rcc_l5, path = "l5.rs")]
|
#[cfg_attr(rcc_l5, path = "l5.rs")]
|
||||||
#[cfg_attr(rcc_u5, path = "u5.rs")]
|
#[cfg_attr(rcc_u5, path = "u5.rs")]
|
||||||
#[cfg_attr(rcc_wb, path = "wb.rs")]
|
#[cfg_attr(rcc_wb, path = "wb.rs")]
|
||||||
|
#[cfg_attr(rcc_wba, path = "wba.rs")]
|
||||||
#[cfg_attr(any(rcc_wl5, rcc_wle), path = "wl.rs")]
|
#[cfg_attr(any(rcc_wl5, rcc_wle), path = "wl.rs")]
|
||||||
#[cfg_attr(any(rcc_h5, rcc_h50), path = "h5.rs")]
|
|
||||||
mod _version;
|
mod _version;
|
||||||
pub use _version::*;
|
pub use _version::*;
|
||||||
#[cfg(feature = "low-power")]
|
#[cfg(feature = "low-power")]
|
||||||
use atomic_polyfill::{AtomicU32, Ordering};
|
use atomic_polyfill::{AtomicU32, Ordering};
|
||||||
|
|
||||||
|
// Model Clock Configuration
|
||||||
|
//
|
||||||
|
// pub struct Clocks {
|
||||||
|
// hse: Option<Hertz>,
|
||||||
|
// hsi: bool,
|
||||||
|
// lse: Option<Hertz>,
|
||||||
|
// lsi: bool,
|
||||||
|
// rtc: RtcSource,
|
||||||
|
// }
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub struct Clocks {
|
pub struct Clocks {
|
||||||
@ -42,16 +57,18 @@ pub struct Clocks {
|
|||||||
pub apb2: Hertz,
|
pub apb2: Hertz,
|
||||||
#[cfg(not(any(rcc_c0, rcc_g0)))]
|
#[cfg(not(any(rcc_c0, rcc_g0)))]
|
||||||
pub apb2_tim: Hertz,
|
pub apb2_tim: Hertz,
|
||||||
#[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_u5))]
|
#[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_u5))]
|
||||||
pub apb3: Hertz,
|
pub apb3: Hertz,
|
||||||
#[cfg(any(rcc_h7, rcc_h7ab))]
|
#[cfg(any(rcc_h7, rcc_h7ab))]
|
||||||
pub apb4: Hertz,
|
pub apb4: Hertz,
|
||||||
|
#[cfg(any(rcc_wba))]
|
||||||
|
pub apb7: Hertz,
|
||||||
|
|
||||||
// AHB
|
// AHB
|
||||||
pub ahb1: Hertz,
|
pub ahb1: Hertz,
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
rcc_l4, rcc_l5, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_g4, rcc_u5, rcc_wb,
|
rcc_l4, rcc_l5, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_g4, rcc_u5, rcc_wb,
|
||||||
rcc_wl5, rcc_wle
|
rcc_wba, rcc_wl5, rcc_wle
|
||||||
))]
|
))]
|
||||||
pub ahb2: Hertz,
|
pub ahb2: Hertz,
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
@ -59,7 +76,7 @@ pub struct Clocks {
|
|||||||
rcc_wle
|
rcc_wle
|
||||||
))]
|
))]
|
||||||
pub ahb3: Hertz,
|
pub ahb3: Hertz,
|
||||||
#[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab))]
|
#[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_wba))]
|
||||||
pub ahb4: Hertz,
|
pub ahb4: Hertz,
|
||||||
|
|
||||||
#[cfg(any(rcc_f2, rcc_f4, rcc_f410, rcc_f7))]
|
#[cfg(any(rcc_f2, rcc_f4, rcc_f410, rcc_f7))]
|
||||||
@ -80,7 +97,7 @@ pub struct Clocks {
|
|||||||
#[cfg(stm32f334)]
|
#[cfg(stm32f334)]
|
||||||
pub hrtim: Option<Hertz>,
|
pub hrtim: Option<Hertz>,
|
||||||
|
|
||||||
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
|
#[cfg(any(rcc_wb, rcc_f4, rcc_f410, rcc_f7))]
|
||||||
/// Set only if the lsi or lse is configured, indicates stop is supported
|
/// Set only if the lsi or lse is configured, indicates stop is supported
|
||||||
pub rtc: Option<Hertz>,
|
pub rtc: Option<Hertz>,
|
||||||
|
|
||||||
@ -94,8 +111,7 @@ static CLOCK_REFCOUNT: AtomicU32 = AtomicU32::new(0);
|
|||||||
|
|
||||||
#[cfg(feature = "low-power")]
|
#[cfg(feature = "low-power")]
|
||||||
pub fn low_power_ready() -> bool {
|
pub fn low_power_ready() -> bool {
|
||||||
trace!("clock refcount: {}", CLOCK_REFCOUNT.load(Ordering::SeqCst));
|
// trace!("clock refcount: {}", CLOCK_REFCOUNT.load(Ordering::SeqCst));
|
||||||
|
|
||||||
CLOCK_REFCOUNT.load(Ordering::SeqCst) == 0
|
CLOCK_REFCOUNT.load(Ordering::SeqCst) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000);
|
|||||||
/// LSI speed
|
/// LSI speed
|
||||||
pub const LSI_FREQ: Hertz = Hertz(32_000);
|
pub const LSI_FREQ: Hertz = Hertz(32_000);
|
||||||
|
|
||||||
pub use super::bus::VoltageScale;
|
pub use crate::pac::pwr::vals::Vos as VoltageScale;
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub enum ClockSrc {
|
pub enum ClockSrc {
|
||||||
@ -119,53 +119,13 @@ impl Into<Pllm> for PllM {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<u8> for AHBPrescaler {
|
|
||||||
fn into(self) -> u8 {
|
|
||||||
match self {
|
|
||||||
AHBPrescaler::NotDivided => 1,
|
|
||||||
AHBPrescaler::Div2 => 0x08,
|
|
||||||
AHBPrescaler::Div4 => 0x09,
|
|
||||||
AHBPrescaler::Div8 => 0x0a,
|
|
||||||
AHBPrescaler::Div16 => 0x0b,
|
|
||||||
AHBPrescaler::Div64 => 0x0c,
|
|
||||||
AHBPrescaler::Div128 => 0x0d,
|
|
||||||
AHBPrescaler::Div256 => 0x0e,
|
|
||||||
AHBPrescaler::Div512 => 0x0f,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for AHBPrescaler {
|
|
||||||
fn default() -> Self {
|
|
||||||
AHBPrescaler::NotDivided
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for APBPrescaler {
|
|
||||||
fn default() -> Self {
|
|
||||||
APBPrescaler::NotDivided
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<u8> for APBPrescaler {
|
|
||||||
fn into(self) -> u8 {
|
|
||||||
match self {
|
|
||||||
APBPrescaler::NotDivided => 1,
|
|
||||||
APBPrescaler::Div2 => 0x04,
|
|
||||||
APBPrescaler::Div4 => 0x05,
|
|
||||||
APBPrescaler::Div8 => 0x06,
|
|
||||||
APBPrescaler::Div16 => 0x07,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<Sw> for ClockSrc {
|
impl Into<Sw> for ClockSrc {
|
||||||
fn into(self) -> Sw {
|
fn into(self) -> Sw {
|
||||||
match self {
|
match self {
|
||||||
ClockSrc::MSI(..) => Sw::MSIS,
|
ClockSrc::MSI(..) => Sw::MSIS,
|
||||||
ClockSrc::HSE(..) => Sw::HSE,
|
ClockSrc::HSE(..) => Sw::HSE,
|
||||||
ClockSrc::HSI16 => Sw::HSI16,
|
ClockSrc::HSI16 => Sw::HSI16,
|
||||||
ClockSrc::PLL1R(..) => Sw::PLL1R,
|
ClockSrc::PLL1R(..) => Sw::PLL1_R,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -239,10 +199,10 @@ impl Default for Config {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
mux: ClockSrc::MSI(MSIRange::default()),
|
mux: ClockSrc::MSI(MSIRange::default()),
|
||||||
ahb_pre: Default::default(),
|
ahb_pre: AHBPrescaler::DIV1,
|
||||||
apb1_pre: Default::default(),
|
apb1_pre: APBPrescaler::DIV1,
|
||||||
apb2_pre: Default::default(),
|
apb2_pre: APBPrescaler::DIV1,
|
||||||
apb3_pre: Default::default(),
|
apb3_pre: APBPrescaler::DIV1,
|
||||||
hsi48: false,
|
hsi48: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -326,12 +286,12 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO make configurable
|
// TODO make configurable
|
||||||
let power_vos = VoltageScale::Scale3;
|
let power_vos = VoltageScale::RANGE3;
|
||||||
|
|
||||||
// states and programming delay
|
// states and programming delay
|
||||||
let wait_states = match power_vos {
|
let wait_states = match power_vos {
|
||||||
// VOS 0 range VCORE 1.26V - 1.40V
|
// VOS 1 range VCORE 1.26V - 1.40V
|
||||||
VoltageScale::Scale0 => {
|
VoltageScale::RANGE1 => {
|
||||||
if sys_clk < 32_000_000 {
|
if sys_clk < 32_000_000 {
|
||||||
0
|
0
|
||||||
} else if sys_clk < 64_000_000 {
|
} else if sys_clk < 64_000_000 {
|
||||||
@ -344,8 +304,8 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
4
|
4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// VOS 1 range VCORE 1.15V - 1.26V
|
// VOS 2 range VCORE 1.15V - 1.26V
|
||||||
VoltageScale::Scale1 => {
|
VoltageScale::RANGE2 => {
|
||||||
if sys_clk < 30_000_000 {
|
if sys_clk < 30_000_000 {
|
||||||
0
|
0
|
||||||
} else if sys_clk < 60_000_000 {
|
} else if sys_clk < 60_000_000 {
|
||||||
@ -356,8 +316,8 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
3
|
3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// VOS 2 range VCORE 1.05V - 1.15V
|
// VOS 3 range VCORE 1.05V - 1.15V
|
||||||
VoltageScale::Scale2 => {
|
VoltageScale::RANGE3 => {
|
||||||
if sys_clk < 24_000_000 {
|
if sys_clk < 24_000_000 {
|
||||||
0
|
0
|
||||||
} else if sys_clk < 48_000_000 {
|
} else if sys_clk < 48_000_000 {
|
||||||
@ -366,8 +326,8 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
2
|
2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// VOS 3 range VCORE 0.95V - 1.05V
|
// VOS 4 range VCORE 0.95V - 1.05V
|
||||||
VoltageScale::Scale3 => {
|
VoltageScale::RANGE4 => {
|
||||||
if sys_clk < 12_000_000 {
|
if sys_clk < 12_000_000 {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
@ -395,7 +355,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let ahb_freq: u32 = match config.ahb_pre {
|
let ahb_freq: u32 = match config.ahb_pre {
|
||||||
AHBPrescaler::NotDivided => sys_clk,
|
AHBPrescaler::DIV1 => sys_clk,
|
||||||
pre => {
|
pre => {
|
||||||
let pre: u8 = pre.into();
|
let pre: u8 = pre.into();
|
||||||
let pre = 1 << (pre as u32 - 7);
|
let pre = 1 << (pre as u32 - 7);
|
||||||
@ -404,7 +364,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
|
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
|
||||||
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
|
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||||
pre => {
|
pre => {
|
||||||
let pre: u8 = pre.into();
|
let pre: u8 = pre.into();
|
||||||
let pre: u8 = 1 << (pre - 3);
|
let pre: u8 = 1 << (pre - 3);
|
||||||
@ -414,7 +374,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
|
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
|
||||||
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
|
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||||
pre => {
|
pre => {
|
||||||
let pre: u8 = pre.into();
|
let pre: u8 = pre.into();
|
||||||
let pre: u8 = 1 << (pre - 3);
|
let pre: u8 = 1 << (pre - 3);
|
||||||
@ -424,7 +384,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (apb3_freq, _apb3_tim_freq) = match config.apb3_pre {
|
let (apb3_freq, _apb3_tim_freq) = match config.apb3_pre {
|
||||||
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
|
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||||
pre => {
|
pre => {
|
||||||
let pre: u8 = pre.into();
|
let pre: u8 = pre.into();
|
||||||
let pre: u8 = 1 << (pre - 3);
|
let pre: u8 = 1 << (pre - 3);
|
||||||
|
@ -108,6 +108,7 @@ pub struct Pll {
|
|||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub hse: Option<Hse>,
|
pub hse: Option<Hse>,
|
||||||
pub lse: Option<Hertz>,
|
pub lse: Option<Hertz>,
|
||||||
|
pub lsi: bool,
|
||||||
pub sys: Sysclk,
|
pub sys: Sysclk,
|
||||||
pub mux: Option<PllMux>,
|
pub mux: Option<PllMux>,
|
||||||
pub pll48: Option<Pll48Source>,
|
pub pll48: Option<Pll48Source>,
|
||||||
@ -135,7 +136,8 @@ pub const WPAN_DEFAULT: Config = Config {
|
|||||||
prediv: 2,
|
prediv: 2,
|
||||||
}),
|
}),
|
||||||
pll48: None,
|
pll48: None,
|
||||||
rtc: None,
|
rtc: Some(RtcClockSource::LSE),
|
||||||
|
lsi: false,
|
||||||
|
|
||||||
pll: Some(Pll {
|
pll: Some(Pll {
|
||||||
mul: 12,
|
mul: 12,
|
||||||
@ -145,11 +147,11 @@ pub const WPAN_DEFAULT: Config = Config {
|
|||||||
}),
|
}),
|
||||||
pllsai: None,
|
pllsai: None,
|
||||||
|
|
||||||
ahb1_pre: AHBPrescaler::NotDivided,
|
ahb1_pre: AHBPrescaler::DIV1,
|
||||||
ahb2_pre: AHBPrescaler::Div2,
|
ahb2_pre: AHBPrescaler::DIV2,
|
||||||
ahb3_pre: AHBPrescaler::NotDivided,
|
ahb3_pre: AHBPrescaler::DIV1,
|
||||||
apb1_pre: APBPrescaler::NotDivided,
|
apb1_pre: APBPrescaler::DIV1,
|
||||||
apb2_pre: APBPrescaler::NotDivided,
|
apb2_pre: APBPrescaler::DIV1,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
@ -164,12 +166,13 @@ impl Default for Config {
|
|||||||
pll: None,
|
pll: None,
|
||||||
pllsai: None,
|
pllsai: None,
|
||||||
rtc: None,
|
rtc: None,
|
||||||
|
lsi: false,
|
||||||
|
|
||||||
ahb1_pre: AHBPrescaler::NotDivided,
|
ahb1_pre: AHBPrescaler::DIV1,
|
||||||
ahb2_pre: AHBPrescaler::NotDivided,
|
ahb2_pre: AHBPrescaler::DIV1,
|
||||||
ahb3_pre: AHBPrescaler::NotDivided,
|
ahb3_pre: AHBPrescaler::DIV1,
|
||||||
apb1_pre: APBPrescaler::NotDivided,
|
apb1_pre: APBPrescaler::DIV1,
|
||||||
apb2_pre: APBPrescaler::NotDivided,
|
apb2_pre: APBPrescaler::DIV1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -209,7 +212,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let ahb1_clk = match config.ahb1_pre {
|
let ahb1_clk = match config.ahb1_pre {
|
||||||
AHBPrescaler::NotDivided => sys_clk,
|
AHBPrescaler::DIV1 => sys_clk,
|
||||||
pre => {
|
pre => {
|
||||||
let pre: u8 = pre.into();
|
let pre: u8 = pre.into();
|
||||||
let pre = 1u32 << (pre as u32 - 7);
|
let pre = 1u32 << (pre as u32 - 7);
|
||||||
@ -218,7 +221,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let ahb2_clk = match config.ahb2_pre {
|
let ahb2_clk = match config.ahb2_pre {
|
||||||
AHBPrescaler::NotDivided => sys_clk,
|
AHBPrescaler::DIV1 => sys_clk,
|
||||||
pre => {
|
pre => {
|
||||||
let pre: u8 = pre.into();
|
let pre: u8 = pre.into();
|
||||||
let pre = 1u32 << (pre as u32 - 7);
|
let pre = 1u32 << (pre as u32 - 7);
|
||||||
@ -227,7 +230,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let ahb3_clk = match config.ahb3_pre {
|
let ahb3_clk = match config.ahb3_pre {
|
||||||
AHBPrescaler::NotDivided => sys_clk,
|
AHBPrescaler::DIV1 => sys_clk,
|
||||||
pre => {
|
pre => {
|
||||||
let pre: u8 = pre.into();
|
let pre: u8 = pre.into();
|
||||||
let pre = 1u32 << (pre as u32 - 7);
|
let pre = 1u32 << (pre as u32 - 7);
|
||||||
@ -236,7 +239,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (apb1_clk, apb1_tim_clk) = match config.apb1_pre {
|
let (apb1_clk, apb1_tim_clk) = match config.apb1_pre {
|
||||||
APBPrescaler::NotDivided => (ahb1_clk, ahb1_clk),
|
APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk),
|
||||||
pre => {
|
pre => {
|
||||||
let pre: u8 = pre.into();
|
let pre: u8 = pre.into();
|
||||||
let pre: u8 = 1 << (pre - 3);
|
let pre: u8 = 1 << (pre - 3);
|
||||||
@ -246,7 +249,7 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (apb2_clk, apb2_tim_clk) = match config.apb2_pre {
|
let (apb2_clk, apb2_tim_clk) = match config.apb2_pre {
|
||||||
APBPrescaler::NotDivided => (ahb1_clk, ahb1_clk),
|
APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk),
|
||||||
pre => {
|
pre => {
|
||||||
let pre: u8 = pre.into();
|
let pre: u8 = pre.into();
|
||||||
let pre: u8 = 1 << (pre - 3);
|
let pre: u8 = 1 << (pre - 3);
|
||||||
@ -294,9 +297,11 @@ pub(crate) fn configure_clocks(config: &Config) {
|
|||||||
|
|
||||||
rcc.cfgr().modify(|w| w.set_stopwuck(true));
|
rcc.cfgr().modify(|w| w.set_stopwuck(true));
|
||||||
|
|
||||||
config
|
BackupDomain::configure_ls(
|
||||||
.rtc
|
config.rtc.unwrap_or(RtcClockSource::NOCLOCK),
|
||||||
.map(|clock_source| BackupDomain::configure_ls(clock_source, None));
|
config.lsi,
|
||||||
|
config.lse.map(|_| Default::default()),
|
||||||
|
);
|
||||||
|
|
||||||
match &config.hse {
|
match &config.hse {
|
||||||
Some(hse) => {
|
Some(hse) => {
|
||||||
|
154
embassy-stm32/src/rcc/wba.rs
Normal file
154
embassy-stm32/src/rcc/wba.rs
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
use stm32_metapac::rcc::vals::{Pllsrc, Sw};
|
||||||
|
|
||||||
|
use crate::pac::{FLASH, RCC};
|
||||||
|
use crate::rcc::{set_freqs, Clocks};
|
||||||
|
use crate::time::Hertz;
|
||||||
|
|
||||||
|
/// HSI speed
|
||||||
|
pub const HSI_FREQ: Hertz = Hertz(16_000_000);
|
||||||
|
|
||||||
|
/// LSI speed
|
||||||
|
pub const LSI_FREQ: Hertz = Hertz(32_000);
|
||||||
|
|
||||||
|
pub use crate::pac::pwr::vals::Vos as VoltageScale;
|
||||||
|
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub enum ClockSrc {
|
||||||
|
HSE(Hertz),
|
||||||
|
HSI16,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum PllSrc {
|
||||||
|
HSE(Hertz),
|
||||||
|
HSI16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<Pllsrc> for PllSrc {
|
||||||
|
fn into(self) -> Pllsrc {
|
||||||
|
match self {
|
||||||
|
PllSrc::HSE(..) => Pllsrc::HSE32,
|
||||||
|
PllSrc::HSI16 => Pllsrc::HSI16,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<Sw> for ClockSrc {
|
||||||
|
fn into(self) -> Sw {
|
||||||
|
match self {
|
||||||
|
ClockSrc::HSE(..) => Sw::HSE32,
|
||||||
|
ClockSrc::HSI16 => Sw::HSI16,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct Config {
|
||||||
|
pub mux: ClockSrc,
|
||||||
|
pub ahb_pre: AHBPrescaler,
|
||||||
|
pub apb1_pre: APBPrescaler,
|
||||||
|
pub apb2_pre: APBPrescaler,
|
||||||
|
pub apb7_pre: APBPrescaler,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Config {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
mux: ClockSrc::HSI16,
|
||||||
|
ahb_pre: AHBPrescaler::DIV1,
|
||||||
|
apb1_pre: APBPrescaler::DIV1,
|
||||||
|
apb2_pre: APBPrescaler::DIV1,
|
||||||
|
apb7_pre: APBPrescaler::DIV1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn init(config: Config) {
|
||||||
|
let sys_clk = match config.mux {
|
||||||
|
ClockSrc::HSE(freq) => {
|
||||||
|
RCC.cr().write(|w| w.set_hseon(true));
|
||||||
|
while !RCC.cr().read().hserdy() {}
|
||||||
|
|
||||||
|
freq
|
||||||
|
}
|
||||||
|
ClockSrc::HSI16 => {
|
||||||
|
RCC.cr().write(|w| w.set_hsion(true));
|
||||||
|
while !RCC.cr().read().hsirdy() {}
|
||||||
|
|
||||||
|
HSI_FREQ
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO make configurable
|
||||||
|
let power_vos = VoltageScale::RANGE1;
|
||||||
|
|
||||||
|
// states and programming delay
|
||||||
|
let wait_states = match power_vos {
|
||||||
|
VoltageScale::RANGE1 => match sys_clk.0 {
|
||||||
|
..=32_000_000 => 0,
|
||||||
|
..=64_000_000 => 1,
|
||||||
|
..=96_000_000 => 2,
|
||||||
|
..=100_000_000 => 3,
|
||||||
|
_ => 4,
|
||||||
|
},
|
||||||
|
VoltageScale::RANGE2 => match sys_clk.0 {
|
||||||
|
..=8_000_000 => 0,
|
||||||
|
..=16_000_000 => 1,
|
||||||
|
_ => 2,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
FLASH.acr().modify(|w| {
|
||||||
|
w.set_latency(wait_states);
|
||||||
|
});
|
||||||
|
|
||||||
|
RCC.cfgr1().modify(|w| {
|
||||||
|
w.set_sw(config.mux.into());
|
||||||
|
});
|
||||||
|
|
||||||
|
RCC.cfgr2().modify(|w| {
|
||||||
|
w.set_hpre(config.ahb_pre.into());
|
||||||
|
w.set_ppre1(config.apb1_pre.into());
|
||||||
|
w.set_ppre2(config.apb2_pre.into());
|
||||||
|
});
|
||||||
|
|
||||||
|
RCC.cfgr3().modify(|w| {
|
||||||
|
w.set_ppre7(config.apb7_pre.into());
|
||||||
|
});
|
||||||
|
|
||||||
|
let ahb_freq = sys_clk / config.ahb_pre;
|
||||||
|
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
|
||||||
|
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||||
|
pre => {
|
||||||
|
let freq = ahb_freq / pre;
|
||||||
|
(freq, freq * 2u32)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
|
||||||
|
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||||
|
pre => {
|
||||||
|
let freq = ahb_freq / pre;
|
||||||
|
(freq, freq * 2u32)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let (apb7_freq, _apb7_tim_freq) = match config.apb7_pre {
|
||||||
|
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||||
|
pre => {
|
||||||
|
let freq = ahb_freq / pre;
|
||||||
|
(freq, freq * 2u32)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
set_freqs(Clocks {
|
||||||
|
sys: sys_clk,
|
||||||
|
ahb1: ahb_freq,
|
||||||
|
ahb2: ahb_freq,
|
||||||
|
ahb4: ahb_freq,
|
||||||
|
apb1: apb1_freq,
|
||||||
|
apb2: apb2_freq,
|
||||||
|
apb7: apb7_freq,
|
||||||
|
apb1_tim: apb1_tim_freq,
|
||||||
|
apb2_tim: apb2_tim_freq,
|
||||||
|
});
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
pub use super::bus::{AHBPrescaler, APBPrescaler, VoltageScale};
|
pub use super::bus::{AHBPrescaler, APBPrescaler};
|
||||||
|
pub use crate::pac::pwr::vals::Vos as VoltageScale;
|
||||||
use crate::pac::rcc::vals::Adcsel;
|
use crate::pac::rcc::vals::Adcsel;
|
||||||
use crate::pac::{FLASH, RCC};
|
use crate::pac::{FLASH, RCC};
|
||||||
use crate::rcc::bd::{BackupDomain, RtcClockSource};
|
use crate::rcc::bd::{BackupDomain, RtcClockSource};
|
||||||
@ -75,9 +76,9 @@ impl MSIRange {
|
|||||||
|
|
||||||
fn vos(&self) -> VoltageScale {
|
fn vos(&self) -> VoltageScale {
|
||||||
if self > &MSIRange::Range8 {
|
if self > &MSIRange::Range8 {
|
||||||
VoltageScale::Scale0
|
VoltageScale::RANGE1
|
||||||
} else {
|
} else {
|
||||||
VoltageScale::Scale1
|
VoltageScale::RANGE2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -138,6 +139,8 @@ pub struct Config {
|
|||||||
pub apb1_pre: APBPrescaler,
|
pub apb1_pre: APBPrescaler,
|
||||||
pub apb2_pre: APBPrescaler,
|
pub apb2_pre: APBPrescaler,
|
||||||
pub rtc_mux: RtcClockSource,
|
pub rtc_mux: RtcClockSource,
|
||||||
|
pub lse: Option<Hertz>,
|
||||||
|
pub lsi: bool,
|
||||||
pub adc_clock_source: AdcClockSource,
|
pub adc_clock_source: AdcClockSource,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,11 +149,13 @@ impl Default for Config {
|
|||||||
fn default() -> Config {
|
fn default() -> Config {
|
||||||
Config {
|
Config {
|
||||||
mux: ClockSrc::MSI(MSIRange::default()),
|
mux: ClockSrc::MSI(MSIRange::default()),
|
||||||
ahb_pre: AHBPrescaler::NotDivided,
|
ahb_pre: AHBPrescaler::DIV1,
|
||||||
shd_ahb_pre: AHBPrescaler::NotDivided,
|
shd_ahb_pre: AHBPrescaler::DIV1,
|
||||||
apb1_pre: APBPrescaler::NotDivided,
|
apb1_pre: APBPrescaler::DIV1,
|
||||||
apb2_pre: APBPrescaler::NotDivided,
|
apb2_pre: APBPrescaler::DIV1,
|
||||||
rtc_mux: RtcClockSource::LSI,
|
rtc_mux: RtcClockSource::LSI,
|
||||||
|
lsi: true,
|
||||||
|
lse: None,
|
||||||
adc_clock_source: AdcClockSource::default(),
|
adc_clock_source: AdcClockSource::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,13 +171,13 @@ pub enum Lsedrv {
|
|||||||
|
|
||||||
pub(crate) unsafe fn init(config: Config) {
|
pub(crate) unsafe fn init(config: Config) {
|
||||||
let (sys_clk, sw, vos) = match config.mux {
|
let (sys_clk, sw, vos) = match config.mux {
|
||||||
ClockSrc::HSI16 => (HSI_FREQ.0, 0x01, VoltageScale::Scale1),
|
ClockSrc::HSI16 => (HSI_FREQ.0, 0x01, VoltageScale::RANGE2),
|
||||||
ClockSrc::HSE32 => (HSE32_FREQ.0, 0x02, VoltageScale::Scale0),
|
ClockSrc::HSE32 => (HSE32_FREQ.0, 0x02, VoltageScale::RANGE1),
|
||||||
ClockSrc::MSI(range) => (range.freq(), 0x00, range.vos()),
|
ClockSrc::MSI(range) => (range.freq(), 0x00, range.vos()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let ahb_freq: u32 = match config.ahb_pre {
|
let ahb_freq: u32 = match config.ahb_pre {
|
||||||
AHBPrescaler::NotDivided => sys_clk,
|
AHBPrescaler::DIV1 => sys_clk,
|
||||||
pre => {
|
pre => {
|
||||||
let pre: u8 = pre.into();
|
let pre: u8 = pre.into();
|
||||||
let pre = 1 << (pre as u32 - 7);
|
let pre = 1 << (pre as u32 - 7);
|
||||||
@ -181,7 +186,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let shd_ahb_freq: u32 = match config.shd_ahb_pre {
|
let shd_ahb_freq: u32 = match config.shd_ahb_pre {
|
||||||
AHBPrescaler::NotDivided => sys_clk,
|
AHBPrescaler::DIV1 => sys_clk,
|
||||||
pre => {
|
pre => {
|
||||||
let pre: u8 = pre.into();
|
let pre: u8 = pre.into();
|
||||||
let pre = 1 << (pre as u32 - 7);
|
let pre = 1 << (pre as u32 - 7);
|
||||||
@ -190,7 +195,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
|
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
|
||||||
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
|
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||||
pre => {
|
pre => {
|
||||||
let pre: u8 = pre.into();
|
let pre: u8 = pre.into();
|
||||||
let pre: u8 = 1 << (pre - 3);
|
let pre: u8 = 1 << (pre - 3);
|
||||||
@ -200,7 +205,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
|
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
|
||||||
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
|
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||||
pre => {
|
pre => {
|
||||||
let pre: u8 = pre.into();
|
let pre: u8 = pre.into();
|
||||||
let pre: u8 = 1 << (pre - 3);
|
let pre: u8 = 1 << (pre - 3);
|
||||||
@ -212,16 +217,17 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
// Adjust flash latency
|
// Adjust flash latency
|
||||||
let flash_clk_src_freq: u32 = shd_ahb_freq;
|
let flash_clk_src_freq: u32 = shd_ahb_freq;
|
||||||
let ws = match vos {
|
let ws = match vos {
|
||||||
VoltageScale::Scale0 => match flash_clk_src_freq {
|
VoltageScale::RANGE1 => match flash_clk_src_freq {
|
||||||
0..=18_000_000 => 0b000,
|
0..=18_000_000 => 0b000,
|
||||||
18_000_001..=36_000_000 => 0b001,
|
18_000_001..=36_000_000 => 0b001,
|
||||||
_ => 0b010,
|
_ => 0b010,
|
||||||
},
|
},
|
||||||
VoltageScale::Scale1 => match flash_clk_src_freq {
|
VoltageScale::RANGE2 => match flash_clk_src_freq {
|
||||||
0..=6_000_000 => 0b000,
|
0..=6_000_000 => 0b000,
|
||||||
6_000_001..=12_000_000 => 0b001,
|
6_000_001..=12_000_000 => 0b001,
|
||||||
_ => 0b010,
|
_ => 0b010,
|
||||||
},
|
},
|
||||||
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
FLASH.acr().modify(|w| {
|
FLASH.acr().modify(|w| {
|
||||||
@ -231,7 +237,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
while FLASH.acr().read().latency() != ws {}
|
while FLASH.acr().read().latency() != ws {}
|
||||||
|
|
||||||
// Enables the LSI if configured
|
// Enables the LSI if configured
|
||||||
BackupDomain::configure_ls(config.rtc_mux, None);
|
BackupDomain::configure_ls(config.rtc_mux, config.lsi, config.lse.map(|_| Default::default()));
|
||||||
|
|
||||||
match config.mux {
|
match config.mux {
|
||||||
ClockSrc::HSI16 => {
|
ClockSrc::HSI16 => {
|
||||||
@ -267,7 +273,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RCC.extcfgr().modify(|w| {
|
RCC.extcfgr().modify(|w| {
|
||||||
if config.shd_ahb_pre == AHBPrescaler::NotDivided {
|
if config.shd_ahb_pre == AHBPrescaler::DIV1 {
|
||||||
w.set_shdhpre(0);
|
w.set_shdhpre(0);
|
||||||
} else {
|
} else {
|
||||||
w.set_shdhpre(config.shd_ahb_pre.into());
|
w.set_shdhpre(config.shd_ahb_pre.into());
|
||||||
@ -276,11 +282,7 @@ pub(crate) unsafe fn init(config: Config) {
|
|||||||
|
|
||||||
RCC.cfgr().modify(|w| {
|
RCC.cfgr().modify(|w| {
|
||||||
w.set_sw(sw.into());
|
w.set_sw(sw.into());
|
||||||
if config.ahb_pre == AHBPrescaler::NotDivided {
|
w.set_hpre(config.ahb_pre);
|
||||||
w.set_hpre(0);
|
|
||||||
} else {
|
|
||||||
w.set_hpre(config.ahb_pre.into());
|
|
||||||
}
|
|
||||||
w.set_ppre1(config.apb1_pre.into());
|
w.set_ppre1(config.apb1_pre.into());
|
||||||
w.set_ppre2(config.apb2_pre.into());
|
w.set_ppre2(config.apb2_pre.into());
|
||||||
});
|
});
|
||||||
|
@ -164,7 +164,7 @@ impl<'d, T: Instance> Rng<'d, T> {
|
|||||||
return Err(Error::SeedError);
|
return Err(Error::SeedError);
|
||||||
}
|
}
|
||||||
// write bytes to chunk
|
// write bytes to chunk
|
||||||
for (dest, src) in chunk.iter_mut().zip(random_word.to_be_bytes().iter()) {
|
for (dest, src) in chunk.iter_mut().zip(random_word.to_ne_bytes().iter()) {
|
||||||
*dest = *src
|
*dest = *src
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -195,7 +195,7 @@ impl<'d, T: Instance> RngCore for Rng<'d, T> {
|
|||||||
fn fill_bytes(&mut self, dest: &mut [u8]) {
|
fn fill_bytes(&mut self, dest: &mut [u8]) {
|
||||||
for chunk in dest.chunks_mut(4) {
|
for chunk in dest.chunks_mut(4) {
|
||||||
let rand = self.next_u32();
|
let rand = self.next_u32();
|
||||||
for (slot, num) in chunk.iter_mut().zip(rand.to_be_bytes().iter()) {
|
for (slot, num) in chunk.iter_mut().zip(rand.to_ne_bytes().iter()) {
|
||||||
*slot = *num
|
*slot = *num
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
|||||||
use embassy_sync::blocking_mutex::Mutex;
|
use embassy_sync::blocking_mutex::Mutex;
|
||||||
|
|
||||||
pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError};
|
pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError};
|
||||||
use crate::rcc::bd::BackupDomain;
|
|
||||||
pub use crate::rcc::RtcClockSource;
|
pub use crate::rcc::RtcClockSource;
|
||||||
use crate::time::Hertz;
|
use crate::time::Hertz;
|
||||||
|
|
||||||
@ -83,12 +82,44 @@ impl core::ops::Sub for RtcInstant {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct RtcTimeProvider {
|
||||||
|
_private: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RtcTimeProvider {
|
||||||
|
/// Return the current datetime.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`].
|
||||||
|
pub fn now(&self) -> Result<DateTime, RtcError> {
|
||||||
|
let r = RTC::regs();
|
||||||
|
let tr = r.tr().read();
|
||||||
|
let second = bcd2_to_byte((tr.st(), tr.su()));
|
||||||
|
let minute = bcd2_to_byte((tr.mnt(), tr.mnu()));
|
||||||
|
let hour = bcd2_to_byte((tr.ht(), tr.hu()));
|
||||||
|
// Reading either RTC_SSR or RTC_TR locks the values in the higher-order
|
||||||
|
// calendar shadow registers until RTC_DR is read.
|
||||||
|
let dr = r.dr().read();
|
||||||
|
|
||||||
|
let weekday = dr.wdu();
|
||||||
|
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;
|
||||||
|
|
||||||
|
self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// RTC Abstraction
|
/// RTC Abstraction
|
||||||
pub struct Rtc {
|
pub struct Rtc {
|
||||||
#[cfg(feature = "low-power")]
|
#[cfg(feature = "low-power")]
|
||||||
stop_time: Mutex<CriticalSectionRawMutex, Cell<Option<RtcInstant>>>,
|
stop_time: Mutex<CriticalSectionRawMutex, Cell<Option<RtcInstant>>>,
|
||||||
|
#[cfg(not(feature = "low-power"))]
|
||||||
|
_private: (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[non_exhaustive]
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub struct RtcConfig {
|
pub struct RtcConfig {
|
||||||
/// The subsecond counter frequency; default is 256
|
/// The subsecond counter frequency; default is 256
|
||||||
@ -124,31 +155,17 @@ impl Default for RtcCalibrationCyclePeriod {
|
|||||||
|
|
||||||
impl Rtc {
|
impl Rtc {
|
||||||
pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self {
|
pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self {
|
||||||
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
|
#[cfg(any(rcc_wle, rcc_wl5, rcc_g4, rcc_g0, rtc_v2l4, rtc_v2wb))]
|
||||||
use crate::rcc::get_freqs;
|
<RTC as crate::rcc::sealed::RccPeripheral>::enable();
|
||||||
|
|
||||||
RTC::enable_peripheral_clk();
|
|
||||||
BackupDomain::enable_rtc();
|
|
||||||
|
|
||||||
let mut this = Self {
|
let mut this = Self {
|
||||||
#[cfg(feature = "low-power")]
|
#[cfg(feature = "low-power")]
|
||||||
stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)),
|
stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)),
|
||||||
|
#[cfg(not(feature = "low-power"))]
|
||||||
|
_private: (),
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
|
let frequency = Self::frequency();
|
||||||
let freqs = unsafe { get_freqs() };
|
|
||||||
|
|
||||||
// Load the clock frequency from the rcc mod, if supported
|
|
||||||
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
|
|
||||||
let frequency = match freqs.rtc {
|
|
||||||
Some(hertz) => hertz,
|
|
||||||
None => freqs.rtc_hse.unwrap(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Assume the default value, if not supported
|
|
||||||
#[cfg(not(any(rcc_wb, rcc_f4, rcc_f410)))]
|
|
||||||
let frequency = Hertz(32_768);
|
|
||||||
|
|
||||||
let async_psc = ((frequency.0 / rtc_config.frequency.0) - 1) as u8;
|
let async_psc = ((frequency.0 / rtc_config.frequency.0) - 1) as u8;
|
||||||
let sync_psc = (rtc_config.frequency.0 - 1) as u16;
|
let sync_psc = (rtc_config.frequency.0 - 1) as u16;
|
||||||
|
|
||||||
@ -157,6 +174,27 @@ impl Rtc {
|
|||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn frequency() -> Hertz {
|
||||||
|
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
|
||||||
|
let freqs = unsafe { crate::rcc::get_freqs() };
|
||||||
|
|
||||||
|
// Load the clock frequency from the rcc mod, if supported
|
||||||
|
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
|
||||||
|
match freqs.rtc {
|
||||||
|
Some(hertz) => hertz,
|
||||||
|
None => freqs.rtc_hse.unwrap(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume the default value, if not supported
|
||||||
|
#[cfg(not(any(rcc_wb, rcc_f4, rcc_f410)))]
|
||||||
|
Hertz(32_768)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Acquire a [`RtcTimeProvider`] instance.
|
||||||
|
pub const fn time_provider(&self) -> RtcTimeProvider {
|
||||||
|
RtcTimeProvider { _private: () }
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the datetime to a new value.
|
/// Set the datetime to a new value.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
@ -189,21 +227,7 @@ impl Rtc {
|
|||||||
///
|
///
|
||||||
/// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`].
|
/// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`].
|
||||||
pub fn now(&self) -> Result<DateTime, RtcError> {
|
pub fn now(&self) -> Result<DateTime, RtcError> {
|
||||||
let r = RTC::regs();
|
self.time_provider().now()
|
||||||
let tr = r.tr().read();
|
|
||||||
let second = bcd2_to_byte((tr.st(), tr.su()));
|
|
||||||
let minute = bcd2_to_byte((tr.mnt(), tr.mnu()));
|
|
||||||
let hour = bcd2_to_byte((tr.ht(), tr.hu()));
|
|
||||||
// Reading either RTC_SSR or RTC_TR locks the values in the higher-order
|
|
||||||
// calendar shadow registers until RTC_DR is read.
|
|
||||||
let dr = r.dr().read();
|
|
||||||
|
|
||||||
let weekday = dr.wdu();
|
|
||||||
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;
|
|
||||||
|
|
||||||
self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if daylight savings time is active.
|
/// Check if daylight savings time is active.
|
||||||
@ -264,12 +288,16 @@ pub(crate) mod sealed {
|
|||||||
pub trait Instance {
|
pub trait Instance {
|
||||||
const BACKUP_REGISTER_COUNT: usize;
|
const BACKUP_REGISTER_COUNT: usize;
|
||||||
|
|
||||||
|
#[cfg(feature = "low-power")]
|
||||||
|
const EXTI_WAKEUP_LINE: usize;
|
||||||
|
|
||||||
|
#[cfg(feature = "low-power")]
|
||||||
|
type WakeupInterrupt: crate::interrupt::typelevel::Interrupt;
|
||||||
|
|
||||||
fn regs() -> Rtc {
|
fn regs() -> Rtc {
|
||||||
crate::pac::RTC
|
crate::pac::RTC
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enable_peripheral_clk();
|
|
||||||
|
|
||||||
/// Read content of the backup register.
|
/// Read content of the backup register.
|
||||||
///
|
///
|
||||||
/// The registers retain their values during wakes from standby mode or system resets. They also
|
/// The registers retain their values during wakes from standby mode or system resets. They also
|
||||||
|
@ -15,7 +15,7 @@ pub(crate) enum WakeupPrescaler {
|
|||||||
Div16 = 16,
|
Div16 = 16,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(stm32wb, stm32f4))]
|
#[cfg(any(stm32wb, stm32f4, stm32l0))]
|
||||||
impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
|
impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
|
||||||
fn from(val: WakeupPrescaler) -> Self {
|
fn from(val: WakeupPrescaler) -> Self {
|
||||||
use crate::pac::rtc::vals::Wucksel;
|
use crate::pac::rtc::vals::Wucksel;
|
||||||
@ -29,7 +29,7 @@ impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(stm32wb, stm32f4))]
|
#[cfg(any(stm32wb, stm32f4, stm32l0))]
|
||||||
impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler {
|
impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler {
|
||||||
fn from(val: crate::pac::rtc::vals::Wucksel) -> Self {
|
fn from(val: crate::pac::rtc::vals::Wucksel) -> Self {
|
||||||
use crate::pac::rtc::vals::Wucksel;
|
use crate::pac::rtc::vals::Wucksel;
|
||||||
@ -64,24 +64,25 @@ impl super::Rtc {
|
|||||||
#[cfg(feature = "low-power")]
|
#[cfg(feature = "low-power")]
|
||||||
/// start the wakeup alarm and wtih a duration that is as close to but less than
|
/// start the wakeup alarm and wtih a duration that is as close to but less than
|
||||||
/// the requested duration, and record the instant the wakeup alarm was started
|
/// the requested duration, and record the instant the wakeup alarm was started
|
||||||
pub(crate) fn start_wakeup_alarm(&self, requested_duration: embassy_time::Duration) {
|
pub(crate) fn start_wakeup_alarm(
|
||||||
|
&self,
|
||||||
|
requested_duration: embassy_time::Duration,
|
||||||
|
cs: critical_section::CriticalSection,
|
||||||
|
) {
|
||||||
use embassy_time::{Duration, TICK_HZ};
|
use embassy_time::{Duration, TICK_HZ};
|
||||||
|
|
||||||
use crate::rcc::get_freqs;
|
// Panic if the rcc mod knows we're not using low-power rtc
|
||||||
|
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
|
||||||
|
unsafe { crate::rcc::get_freqs() }.rtc.unwrap();
|
||||||
|
|
||||||
let rtc_hz = unsafe { get_freqs() }.rtc.unwrap().0 as u64;
|
let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64);
|
||||||
|
let rtc_hz = Self::frequency().0 as u64;
|
||||||
let rtc_ticks = requested_duration.as_ticks() * rtc_hz / TICK_HZ;
|
let rtc_ticks = requested_duration * rtc_hz / TICK_HZ;
|
||||||
let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32);
|
let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32);
|
||||||
|
|
||||||
// adjust the rtc ticks to the prescaler and subtract one rtc tick
|
// adjust the rtc ticks to the prescaler and subtract one rtc tick
|
||||||
let rtc_ticks = rtc_ticks / prescaler as u64;
|
let rtc_ticks = rtc_ticks / prescaler as u64;
|
||||||
let rtc_ticks = if rtc_ticks >= u16::MAX as u64 {
|
let rtc_ticks = rtc_ticks.clamp(0, (u16::MAX - 1) as u64).saturating_sub(1) as u16;
|
||||||
u16::MAX - 1
|
|
||||||
} else {
|
|
||||||
rtc_ticks as u16
|
|
||||||
}
|
|
||||||
.saturating_sub(1);
|
|
||||||
|
|
||||||
self.write(false, |regs| {
|
self.write(false, |regs| {
|
||||||
regs.cr().modify(|w| w.set_wute(false));
|
regs.cr().modify(|w| w.set_wute(false));
|
||||||
@ -102,41 +103,47 @@ impl super::Rtc {
|
|||||||
self.instant(),
|
self.instant(),
|
||||||
);
|
);
|
||||||
|
|
||||||
critical_section::with(|cs| assert!(self.stop_time.borrow(cs).replace(Some(self.instant())).is_none()))
|
assert!(self.stop_time.borrow(cs).replace(Some(self.instant())).is_none())
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "low-power")]
|
|
||||||
pub(crate) fn enable_wakeup_line(&self) {
|
|
||||||
use crate::pac::EXTI;
|
|
||||||
|
|
||||||
EXTI.rtsr(0).modify(|w| w.set_line(22, true));
|
|
||||||
EXTI.imr(0).modify(|w| w.set_line(22, true));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "low-power")]
|
#[cfg(feature = "low-power")]
|
||||||
/// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm`
|
/// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm`
|
||||||
/// was called, otherwise none
|
/// was called, otherwise none
|
||||||
pub(crate) fn stop_wakeup_alarm(&self) -> Option<embassy_time::Duration> {
|
pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> {
|
||||||
use crate::interrupt::typelevel::Interrupt;
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
|
|
||||||
trace!("rtc: stop wakeup alarm at {}", self.instant());
|
if RTC::regs().cr().read().wute() {
|
||||||
|
trace!("rtc: stop wakeup alarm at {}", self.instant());
|
||||||
|
|
||||||
self.write(false, |regs| {
|
self.write(false, |regs| {
|
||||||
regs.cr().modify(|w| w.set_wutie(false));
|
regs.cr().modify(|w| w.set_wutie(false));
|
||||||
regs.cr().modify(|w| w.set_wute(false));
|
regs.cr().modify(|w| w.set_wute(false));
|
||||||
regs.isr().modify(|w| w.set_wutf(false));
|
regs.isr().modify(|w| w.set_wutf(false));
|
||||||
|
|
||||||
crate::pac::EXTI.pr(0).modify(|w| w.set_line(22, true));
|
crate::pac::EXTI
|
||||||
crate::interrupt::typelevel::RTC_WKUP::unpend();
|
.pr(0)
|
||||||
});
|
.modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
|
||||||
|
|
||||||
critical_section::with(|cs| {
|
<RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend();
|
||||||
if let Some(stop_time) = self.stop_time.borrow(cs).take() {
|
});
|
||||||
Some(self.instant() - stop_time)
|
}
|
||||||
} else {
|
|
||||||
None
|
self.stop_time
|
||||||
}
|
.borrow(cs)
|
||||||
})
|
.take()
|
||||||
|
.map(|stop_time| self.instant() - stop_time)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "low-power")]
|
||||||
|
pub(crate) fn enable_wakeup_line(&self) {
|
||||||
|
use crate::interrupt::typelevel::Interrupt;
|
||||||
|
use crate::pac::EXTI;
|
||||||
|
|
||||||
|
<RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::unpend();
|
||||||
|
unsafe { <RTC as crate::rtc::sealed::Instance>::WakeupInterrupt::enable() };
|
||||||
|
|
||||||
|
EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
|
||||||
|
EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Applies the RTC config
|
/// Applies the RTC config
|
||||||
@ -259,30 +266,17 @@ impl super::Rtc {
|
|||||||
impl sealed::Instance for crate::peripherals::RTC {
|
impl sealed::Instance for crate::peripherals::RTC {
|
||||||
const BACKUP_REGISTER_COUNT: usize = 20;
|
const BACKUP_REGISTER_COUNT: usize = 20;
|
||||||
|
|
||||||
fn enable_peripheral_clk() {
|
#[cfg(all(feature = "low-power", stm32f4))]
|
||||||
#[cfg(any(rtc_v2l4, rtc_v2wb))]
|
const EXTI_WAKEUP_LINE: usize = 22;
|
||||||
{
|
|
||||||
// enable peripheral clock for communication
|
|
||||||
crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true));
|
|
||||||
|
|
||||||
// read to allow the pwr clock to enable
|
#[cfg(all(feature = "low-power", stm32l0))]
|
||||||
crate::pac::PWR.cr1().read();
|
const EXTI_WAKEUP_LINE: usize = 20;
|
||||||
}
|
|
||||||
#[cfg(any(rtc_v2f2))]
|
|
||||||
{
|
|
||||||
// enable peripheral clock for communication
|
|
||||||
crate::pac::RCC.apb1enr().modify(|w| w.set_pwren(true));
|
|
||||||
|
|
||||||
// read to allow the pwr clock to enable
|
#[cfg(all(feature = "low-power", stm32f4))]
|
||||||
crate::pac::PWR.cr().read();
|
type WakeupInterrupt = crate::interrupt::typelevel::RTC_WKUP;
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(rtc_v2f0))]
|
#[cfg(all(feature = "low-power", stm32l0))]
|
||||||
{
|
type WakeupInterrupt = crate::interrupt::typelevel::RTC;
|
||||||
// enable peripheral clock for communication
|
|
||||||
crate::pac::RCC.apb1enr().modify(|w| w.set_pwren(true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_backup_register(rtc: &Rtc, register: usize) -> Option<u32> {
|
fn read_backup_register(rtc: &Rtc, register: usize) -> Option<u32> {
|
||||||
if register < Self::BACKUP_REGISTER_COUNT {
|
if register < Self::BACKUP_REGISTER_COUNT {
|
||||||
|
@ -128,23 +128,6 @@ impl super::Rtc {
|
|||||||
impl sealed::Instance for crate::peripherals::RTC {
|
impl sealed::Instance for crate::peripherals::RTC {
|
||||||
const BACKUP_REGISTER_COUNT: usize = 32;
|
const BACKUP_REGISTER_COUNT: usize = 32;
|
||||||
|
|
||||||
fn enable_peripheral_clk() {
|
|
||||||
#[cfg(any(rcc_wle, rcc_wl5, rcc_g4))]
|
|
||||||
{
|
|
||||||
// enable peripheral clock for communication
|
|
||||||
crate::pac::RCC.apb1enr1().modify(|w| w.set_rtcapben(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(rcc_g0)]
|
|
||||||
{
|
|
||||||
// enable peripheral clock for communication
|
|
||||||
crate::pac::RCC.apbenr1().modify(|w| w.set_rtcapben(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
// read to allow the pwr clock to enable
|
|
||||||
crate::pac::PWR.cr1().read();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_backup_register(_rtc: &Rtc, register: usize) -> Option<u32> {
|
fn read_backup_register(_rtc: &Rtc, register: usize) -> Option<u32> {
|
||||||
#[allow(clippy::if_same_then_else)]
|
#[allow(clippy::if_same_then_else)]
|
||||||
if register < Self::BACKUP_REGISTER_COUNT {
|
if register < Self::BACKUP_REGISTER_COUNT {
|
||||||
|
1066
embassy-stm32/src/sai/mod.rs
Normal file
1066
embassy-stm32/src/sai/mod.rs
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user