Compare commits
332 Commits
embassy-sy
...
embassy-ti
Author | SHA1 | Date | |
---|---|---|---|
1d810baa18 | |||
213b4c9dca | |||
889d482d2d | |||
ea0e83a7f9 | |||
f0497039ed | |||
aff77d2b65 | |||
a7c6999670 | |||
18e96898ea | |||
870dcc5970 | |||
5c5e681819 | |||
f54753beaa | |||
b24520579a | |||
1fc35c753b | |||
cd92bc3145 | |||
4a156df7a1 | |||
c46e758e2c | |||
8a10948ce9 | |||
7045c53170 | |||
0621e957a0 | |||
a818f33658 | |||
3bfbf2697f | |||
7559f9e583 | |||
c8fdbe19f9 | |||
2e50bf667a | |||
ba62037642 | |||
824556c9c8 | |||
f7c0ec66d2 | |||
69bb455c60 | |||
575db17264 | |||
0aa99e66f7 | |||
3264941c1b | |||
a57d383b1d | |||
9a7fda87b0 | |||
adc810d24b | |||
75baf186f3 | |||
a6bbb130c5 | |||
d1ac6d2824 | |||
636958ff70 | |||
7f6fe93f55 | |||
e9b1904db8 | |||
02d2c06b23 | |||
debda2f52c | |||
97ca0e77bf | |||
66e399b5c6 | |||
01eb1a7339 | |||
f0d6ee69bc | |||
65f81a1f57 | |||
ecdd7c0e2f | |||
d7d79f3068 | |||
f65a96c541 | |||
eb368f77a4 | |||
57ccc1051a | |||
ac84631a2a | |||
70a91945fc | |||
32b89eeba1 | |||
063e6f96da | |||
4cec4b0548 | |||
e6c47c3718 | |||
2f7c2750d1 | |||
032b1f2d59 | |||
f76d50e837 | |||
ee5ea7aa06 | |||
251d004708 | |||
cd68f85501 | |||
b6c0ddb7df | |||
ee93bbf1d4 | |||
7b1cd42936 | |||
1cd3ae9bd5 | |||
bfcca79c1e | |||
c283e2d1b9 | |||
4a43cd3982 | |||
0dda888c95 | |||
b91d1eaca0 | |||
5a19d18b9c | |||
ed7b6056a6 | |||
322f9cb153 | |||
3ec4e6320a | |||
233aa1b53a | |||
21915a9a3f | |||
d0d0ceec6a | |||
9be61a2967 | |||
0cfa8d1bb5 | |||
cd12c9cbce | |||
eff73d6dfa | |||
3616d68aaa | |||
904f1cfc7a | |||
e62bf6a9fd | |||
7526b8edba | |||
c3ef98a73d | |||
6186fe0807 | |||
c4cff0b79b | |||
2e5ab7981e | |||
9d311121f2 | |||
25c3754cd2 | |||
85c6f23dcb | |||
9c6a2d9cbd | |||
b67b179933 | |||
d4ed8e5779 | |||
3e054a6f0d | |||
c6d53e7bce | |||
3bf8e4de5f | |||
9090a78df4 | |||
022d870d61 | |||
534eb960e9 | |||
7a2b8481f7 | |||
710874021a | |||
3a8e0d4a27 | |||
b217d147de | |||
68c4820dde | |||
f30fc949ff | |||
75c1a9a3aa | |||
4075ac84e1 | |||
f01609036f | |||
930b8f3495 | |||
38e7709a24 | |||
65ed19aae2 | |||
be9c05fbc9 | |||
42176b1a3a | |||
e1a0635ca3 | |||
b887b7516e | |||
c6513f93fe | |||
59f706ee2f | |||
ba7d74ac16 | |||
0324cee0ca | |||
8ac5c1a963 | |||
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 | |||
b9d4b18f14 | |||
3a1ed823f8 | |||
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_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 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
|
||||
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 save /ci/cache/filetime.json
|
||||
|
||||
|
9
.github/ci/doc.sh
vendored
9
.github/ci/doc.sh
vendored
@ -49,8 +49,7 @@ kubectl cp webroot/static $POD:/data
|
||||
# build and upload stm32 last
|
||||
# so that it doesn't prevent other crates from getting docs updates when it breaks.
|
||||
|
||||
# temporarily disabled because it's bringing CI down.
|
||||
#rm -rf webroot
|
||||
#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})
|
||||
#kubectl cp webroot/crates $POD:/data
|
||||
rm -rf webroot
|
||||
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})
|
||||
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_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 save /ci/cache/filetime.json
|
||||
|
||||
|
@ -62,9 +62,9 @@ async fn blink(pin: AnyPin) {
|
||||
loop {
|
||||
// Timekeeping is globally available, no need to mess with hardware timers.
|
||||
led.set_high();
|
||||
Timer::after(Duration::from_millis(150)).await;
|
||||
Timer::after_millis(150).await;
|
||||
led.set_low();
|
||||
Timer::after(Duration::from_millis(150)).await;
|
||||
Timer::after_millis(150).await;
|
||||
}
|
||||
}
|
||||
|
||||
|
119
ci.sh
119
ci.sh
@ -1,9 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
set -eo pipefail
|
||||
|
||||
export RUSTFLAGS=-Dwarnings
|
||||
export DEFMT_LOG=trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info
|
||||
if [[ -z "${CARGO_TARGET_DIR}" ]]; then
|
||||
export CARGO_TARGET_DIR=target_ci
|
||||
fi
|
||||
|
||||
TARGET=$(rustc -vV | sed -n 's|host: ||p')
|
||||
|
||||
@ -36,7 +39,7 @@ cargo batch \
|
||||
--- 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,dhcpv4,medium-ethernet,nightly,dhcpv4-hostname \
|
||||
--- 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 \
|
||||
@ -66,46 +69,68 @@ cargo batch \
|
||||
--- 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,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,time \
|
||||
--- 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 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,stm32f401ve,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f405zg,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f407zg,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f410tb,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f411ce,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f412zg,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f413vh,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f415zg,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f417zg,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f423zh,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f427zi,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,unstable-traits,embedded-sdmmc,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f437zi,log,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f439zi,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f446ze,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f469zi,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f479zi,defmt,exti,time-driver-any,unstable-traits,embedded-sdmmc,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f730i8,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h753zi,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h735zg,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l422cb,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wb15cc,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l072cz,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l041f6,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l073cz,defmt,exti,time-driver-any,unstable-traits,low-power,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f398ve,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f378cc,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32g0c1ve,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f217zg,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,stm32l552ze,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32wl54jc-cm0p,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wle5jb,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32g474pe,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f107vc,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f103re,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f100c4,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32h503rb,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32h562ag,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- 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' \
|
||||
@ -144,6 +169,7 @@ cargo batch \
|
||||
--- 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 \
|
||||
@ -169,17 +195,28 @@ cargo batch \
|
||||
--- 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/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 out/tests/stm32wb55rg/wpan_mac
|
||||
rm out/tests/stm32wb55rg/wpan_ble
|
||||
rm out/tests/stm32f207zg/eth
|
||||
|
||||
if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
|
||||
echo No teleprobe token found, skipping running HIL tests
|
||||
exit
|
||||
fi
|
||||
|
||||
rm out/tests/stm32wb55rg/wpan_ble
|
||||
|
||||
teleprobe client run -r out/tests
|
||||
|
61
ci_stable.sh
61
ci_stable.sh
@ -40,33 +40,38 @@ cargo batch \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585zi,defmt,exti,time-driver-any,unstable-traits \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55vy,defmt,exti,time-driver-any,unstable-traits \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55cc-cm4,defmt,exti,time-driver-any,unstable-traits \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4r9zi,defmt,exti,time-driver-any,unstable-traits \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303vc,defmt,exti,time-driver-any,unstable-traits \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any,unstable-traits \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any,unstable-traits \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,time-driver-any \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,time-driver-any,unstable-traits \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,time-driver-any \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,time-driver-any,unstable-traits \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any,unstable-traits \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,time-driver-any \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,time-driver-any,unstable-traits \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any,unstable-traits \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,unstable-traits \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,unstable-traits \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any,unstable-traits \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,unstable-traits \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g473cc,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g491re,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585zi,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55vy,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55cc-cm4,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4r9zi,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303vc,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,unstable-traits,time \
|
||||
--- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --no-default-features --out-dir out/examples/nrf52840 --bin raw_spawn \
|
||||
--- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --no-default-features --out-dir out/examples/stm32l0 --bin raw_spawn \
|
||||
|
@ -11,11 +11,10 @@ log = ["dep:log"]
|
||||
firmware-logs = []
|
||||
|
||||
[dependencies]
|
||||
embassy-time = { version = "0.1.3", path = "../embassy-time"}
|
||||
embassy-time = { version = "0.1.5", path = "../embassy-time"}
|
||||
embassy-sync = { version = "0.3.0", path = "../embassy-sync"}
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
|
||||
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"}
|
||||
atomic-polyfill = "0.1.5"
|
||||
|
||||
defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.17", optional = true }
|
||||
|
@ -1,5 +1,5 @@
|
||||
use embassy_futures::yield_now;
|
||||
use embassy_time::{Duration, Timer};
|
||||
use embassy_time::Timer;
|
||||
use embedded_hal_1::digital::OutputPin;
|
||||
use futures::FutureExt;
|
||||
|
||||
@ -51,9 +51,9 @@ where
|
||||
pub async fn init(&mut self) {
|
||||
// Reset
|
||||
self.pwr.set_low().unwrap();
|
||||
Timer::after(Duration::from_millis(20)).await;
|
||||
Timer::after_millis(20).await;
|
||||
self.pwr.set_high().unwrap();
|
||||
Timer::after(Duration::from_millis(250)).await;
|
||||
Timer::after_millis(250).await;
|
||||
|
||||
while self
|
||||
.read32_swapped(REG_BUS_TEST_RO)
|
||||
|
@ -2,7 +2,7 @@ use core::cmp::{max, min};
|
||||
|
||||
use ch::driver::LinkState;
|
||||
use embassy_net_driver_channel as ch;
|
||||
use embassy_time::{Duration, Timer};
|
||||
use embassy_time::Timer;
|
||||
|
||||
pub use crate::bus::SpiBusCyw43;
|
||||
use crate::consts::*;
|
||||
@ -87,22 +87,22 @@ impl<'a> Control<'a> {
|
||||
self.set_iovar("country", &country_info.to_bytes()).await;
|
||||
|
||||
// set country takes some time, next ioctls fail if we don't wait.
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
Timer::after_millis(100).await;
|
||||
|
||||
// Set antenna to chip antenna
|
||||
self.ioctl_set_u32(IOCTL_CMD_ANTDIV, 0, 0).await;
|
||||
|
||||
self.set_iovar_u32("bus:txglom", 0).await;
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
Timer::after_millis(100).await;
|
||||
//self.set_iovar_u32("apsta", 1).await; // this crashes, also we already did it before...??
|
||||
//Timer::after(Duration::from_millis(100)).await;
|
||||
//Timer::after_millis(100).await;
|
||||
self.set_iovar_u32("ampdu_ba_wsize", 8).await;
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
Timer::after_millis(100).await;
|
||||
self.set_iovar_u32("ampdu_mpdu", 4).await;
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
Timer::after_millis(100).await;
|
||||
//self.set_iovar_u32("ampdu_rx_factor", 0).await; // this crashes
|
||||
|
||||
//Timer::after(Duration::from_millis(100)).await;
|
||||
//Timer::after_millis(100).await;
|
||||
|
||||
// evts
|
||||
let mut evts = EventMask {
|
||||
@ -121,17 +121,17 @@ impl<'a> Control<'a> {
|
||||
|
||||
self.set_iovar("bsscfg:event_msgs", &evts.to_bytes()).await;
|
||||
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
Timer::after_millis(100).await;
|
||||
|
||||
// set wifi up
|
||||
self.up().await;
|
||||
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
Timer::after_millis(100).await;
|
||||
|
||||
self.ioctl_set_u32(110, 0, 1).await; // SET_GMODE = auto
|
||||
self.ioctl_set_u32(142, 0, 0).await; // SET_BAND = any
|
||||
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
Timer::after_millis(100).await;
|
||||
|
||||
self.state_ch.set_ethernet_address(mac_addr);
|
||||
|
||||
@ -185,7 +185,7 @@ impl<'a> Control<'a> {
|
||||
self.set_iovar_u32x2("bsscfg:sup_wpa2_eapver", 0, 0xFFFF_FFFF).await;
|
||||
self.set_iovar_u32x2("bsscfg:sup_wpa_tmo", 0, 2500).await;
|
||||
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
Timer::after_millis(100).await;
|
||||
|
||||
let mut pfi = PassphraseInfo {
|
||||
len: passphrase.len() as _,
|
||||
@ -297,7 +297,7 @@ impl<'a> Control<'a> {
|
||||
if security != Security::OPEN {
|
||||
self.set_iovar_u32x2("bsscfg:wpa_auth", 0, 0x0084).await; // wpa_auth = WPA2_AUTH_PSK | WPA_AUTH_PSK
|
||||
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
Timer::after_millis(100).await;
|
||||
|
||||
// Set passphrase
|
||||
let mut pfi = PassphraseInfo {
|
||||
|
@ -555,14 +555,14 @@ where
|
||||
|
||||
self.bus.bp_write8(base + AI_RESETCTRL_OFFSET, 0).await;
|
||||
|
||||
Timer::after(Duration::from_millis(1)).await;
|
||||
Timer::after_millis(1).await;
|
||||
|
||||
self.bus
|
||||
.bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_CLOCK_EN)
|
||||
.await;
|
||||
let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
|
||||
|
||||
Timer::after(Duration::from_millis(1)).await;
|
||||
Timer::after_millis(1).await;
|
||||
}
|
||||
|
||||
async fn core_is_up(&mut self, core: Core) -> bool {
|
||||
|
@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
embassy-executor = { version = "0.3.0", path = "../../../../../embassy-executor", features = ["defmt", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] }
|
||||
embassy-time = { version = "0.1.0", path = "../../../../../embassy-time", features = ["defmt", "nightly"] }
|
||||
embassy-time = { version = "0.1.4", path = "../../../../../embassy-time", features = ["defmt", "nightly"] }
|
||||
embassy-nrf = { version = "0.1.0", path = "../../../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "nightly"] }
|
||||
|
||||
defmt = "0.3"
|
||||
|
@ -1,6 +1,6 @@
|
||||
* xref:getting_started.adoc[Getting started]
|
||||
** 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:hal.adoc[HAL]
|
||||
** xref:nrf.adoc[nRF]
|
||||
@ -8,3 +8,5 @@
|
||||
* xref:bootloader.adoc[Bootloader]
|
||||
|
||||
* 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:
|
||||
|
||||
* 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.
|
||||
|
||||
@ -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]
|
||||
|
||||
=== ESP32
|
||||
|
||||
* link:https://github.com/esp-rs/esp-rust-board[ESP32C3]
|
||||
|
||||
== Running an example
|
||||
|
||||
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
|
||||
cd embassy
|
||||
git submodule update --init
|
||||
----
|
||||
|
||||
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
|
||||
|
||||
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?
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
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?
|
||||
|
||||
@ -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.
|
||||
** 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-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.
|
||||
|
||||
* **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.
|
||||
|
||||
* **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.
|
||||
|
||||
@ -8,8 +8,7 @@ The application we'll write is a simple 'push button, blink led' application, wh
|
||||
|
||||
== 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
|
||||
to make accessing peripheral registers easier, but it does not prevent you from writing unsafe code.
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
The following peripherals have a HAL implementation at present:
|
||||
The following peripherals have a HAL implementation at present
|
||||
|
||||
* PWM
|
||||
* SPIM
|
||||
@ -23,3 +23,7 @@ The following peripherals have a HAL implementation at present:
|
||||
* UARTE
|
||||
* TWIM
|
||||
* SAADC
|
||||
|
||||
== Bluetooth
|
||||
|
||||
For bluetooth, you can use the link:https://github.com/embassy-rs/nrf-softdevice[nrf-softdevice] crate.
|
||||
|
@ -6,11 +6,11 @@ The Embassy executor is an async/await executor designed for embedded usage alon
|
||||
|
||||
* No `alloc`, no heap needed. Task are statically allocated.
|
||||
* No "fixed capacity" data structures, executor works with 1 or 1000 tasks without needing config/tuning.
|
||||
* Integrated timer queue: sleeping is easy, just do `Timer::after(Duration::from_secs(1)).await;`.
|
||||
* Integrated timer queue: sleeping is easy, just do `Timer::after_secs(1).await;`.
|
||||
* 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.
|
||||
* 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
|
||||
|
||||
|
@ -21,7 +21,7 @@ default = ["time"]
|
||||
[dependencies]
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures", optional = true }
|
||||
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.5", path = "../embassy-time", optional = true }
|
||||
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [
|
||||
"unproven",
|
||||
] }
|
||||
|
@ -11,7 +11,7 @@ pub use asynch::Partition;
|
||||
pub use blocking::BlockingPartition;
|
||||
|
||||
/// Partition error
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum Error<T> {
|
||||
/// The requested flash area is outside the partition
|
||||
|
@ -1,5 +1,5 @@
|
||||
#![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)]
|
||||
|
||||
//! Utilities to use `embedded-hal` traits with Embassy.
|
||||
@ -26,6 +26,18 @@ pub trait SetConfig {
|
||||
/// The configuration type used by this driver.
|
||||
type Config;
|
||||
|
||||
/// The error type that can occur if `set_config` fails.
|
||||
type ConfigError;
|
||||
|
||||
/// 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>> {
|
||||
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)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), I2cDeviceError<BUS::Error>> {
|
||||
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)?;
|
||||
Ok(())
|
||||
}
|
||||
@ -144,7 +144,7 @@ where
|
||||
rd_buffer: &mut [u8],
|
||||
) -> Result<(), I2cDeviceError<BUS::Error>> {
|
||||
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)
|
||||
.await
|
||||
.map_err(I2cDeviceError::I2c)?;
|
||||
@ -153,7 +153,7 @@ where
|
||||
|
||||
async fn transaction(&mut self, address: u8, operations: &mut [i2c::Operation<'_>]) -> Result<(), Self::Error> {
|
||||
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)
|
||||
.await
|
||||
.map_err(I2cDeviceError::I2c)?;
|
||||
|
@ -76,9 +76,7 @@ where
|
||||
#[cfg(not(feature = "time"))]
|
||||
Operation::DelayUs(_) => return Err(SpiDeviceError::DelayUsNotSupported),
|
||||
#[cfg(feature = "time")]
|
||||
Operation::DelayUs(us) => {
|
||||
embassy_time::Timer::after(embassy_time::Duration::from_micros(*us as _)).await
|
||||
}
|
||||
Operation::DelayUs(us) => embassy_time::Timer::after_micros(*us as _).await,
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -130,7 +128,7 @@ where
|
||||
{
|
||||
async fn transaction(&mut self, operations: &mut [spi::Operation<'_, u8>]) -> Result<(), Self::Error> {
|
||||
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)?;
|
||||
|
||||
let op_res: Result<(), BUS::Error> = try {
|
||||
@ -143,9 +141,7 @@ where
|
||||
#[cfg(not(feature = "time"))]
|
||||
Operation::DelayUs(_) => return Err(SpiDeviceError::DelayUsNotSupported),
|
||||
#[cfg(feature = "time")]
|
||||
Operation::DelayUs(us) => {
|
||||
embassy_time::Timer::after(embassy_time::Duration::from_micros(*us as _)).await
|
||||
}
|
||||
Operation::DelayUs(us) => embassy_time::Timer::after_micros(*us as _).await,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -148,7 +148,7 @@ where
|
||||
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
|
||||
self.bus.lock(|bus| {
|
||||
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)
|
||||
})
|
||||
}
|
||||
@ -156,7 +156,7 @@ where
|
||||
fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> {
|
||||
self.bus.lock(|bus| {
|
||||
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)
|
||||
})
|
||||
}
|
||||
@ -164,7 +164,7 @@ where
|
||||
fn write_read(&mut self, address: u8, wr_buffer: &[u8], rd_buffer: &mut [u8]) -> Result<(), Self::Error> {
|
||||
self.bus.lock(|bus| {
|
||||
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)
|
||||
.map_err(I2cDeviceError::I2c)
|
||||
})
|
||||
|
@ -163,7 +163,7 @@ where
|
||||
fn transaction(&mut self, operations: &mut [Operation<'_, u8>]) -> Result<(), Self::Error> {
|
||||
self.bus.lock(|bus| {
|
||||
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)?;
|
||||
|
||||
let op_res = operations.iter_mut().try_for_each(|op| match op {
|
||||
|
@ -14,6 +14,8 @@ pub mod blocking;
|
||||
pub enum I2cDeviceError<BUS> {
|
||||
/// An operation on the inner I2C bus failed.
|
||||
I2c(BUS),
|
||||
/// Configuration of the inner I2C bus failed.
|
||||
Config,
|
||||
}
|
||||
|
||||
impl<BUS> i2c::Error for I2cDeviceError<BUS>
|
||||
@ -23,6 +25,7 @@ where
|
||||
fn kind(&self) -> i2c::ErrorKind {
|
||||
match self {
|
||||
Self::I2c(e) => e.kind(),
|
||||
Self::Config => i2c::ErrorKind::Other,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -38,6 +41,8 @@ pub enum SpiDeviceError<BUS, CS> {
|
||||
Cs(CS),
|
||||
/// DelayUs operations are not supported when the `time` Cargo feature is not enabled.
|
||||
DelayUsNotSupported,
|
||||
/// The SPI bus could not be configured.
|
||||
Config,
|
||||
}
|
||||
|
||||
impl<BUS, CS> spi::Error for SpiDeviceError<BUS, CS>
|
||||
@ -50,6 +55,7 @@ where
|
||||
Self::Spi(e) => e.kind(),
|
||||
Self::Cs(_) => spi::ErrorKind::Other,
|
||||
Self::DelayUsNotSupported => spi::ErrorKind::Other,
|
||||
Self::Config => spi::ErrorKind::Other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ rtos-trace = { version = "0.1.2", optional = true }
|
||||
|
||||
futures-util = { version = "0.3.17", default-features = false }
|
||||
embassy-macros = { version = "0.2.1", path = "../embassy-macros" }
|
||||
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true}
|
||||
embassy-time = { version = "0.1.5", path = "../embassy-time", optional = true}
|
||||
atomic-polyfill = "1.0.1"
|
||||
critical-section = "1.1"
|
||||
static_cell = "1.1"
|
||||
|
@ -4,7 +4,7 @@ An async/await executor designed for embedded usage.
|
||||
|
||||
- No `alloc`, no heap needed. Task futures are statically allocated.
|
||||
- No "fixed capacity" data structures, executor works with 1 or 1000 tasks without needing config/tuning.
|
||||
- Integrated timer queue: sleeping is easy, just do `Timer::after(Duration::from_secs(1)).await;`.
|
||||
- Integrated timer queue: sleeping is easy, just do `Timer::after_secs(1).await;`.
|
||||
- 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.
|
||||
- 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.
|
||||
|
@ -73,9 +73,10 @@ mod thread {
|
||||
pub fn start(&'static mut self, init: impl FnOnce(Spawner)) {
|
||||
unsafe {
|
||||
let executor = &self.inner;
|
||||
self.ctx.closure.write(Closure::new(move |_| {
|
||||
let future = Closure::new(move |_| {
|
||||
executor.poll();
|
||||
}));
|
||||
});
|
||||
self.ctx.closure.write_in_place(|| future);
|
||||
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> {
|
||||
unsafe {
|
||||
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);
|
||||
|
||||
|
@ -17,8 +17,9 @@ impl<T> UninitCell<T> {
|
||||
&mut *self.as_mut_ptr()
|
||||
}
|
||||
|
||||
pub unsafe fn write(&self, val: T) {
|
||||
ptr::write(self.as_mut_ptr(), val)
|
||||
#[inline(never)]
|
||||
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) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
# embassy-macros
|
||||
# embassy-hal-internal
|
||||
|
||||
An [Embassy](https://embassy.dev) project.
|
||||
|
||||
|
@ -4,6 +4,7 @@ use core::sync::atomic::{compiler_fence, Ordering};
|
||||
|
||||
use cortex_m::interrupt::InterruptNumber;
|
||||
use cortex_m::peripheral::NVIC;
|
||||
use critical_section::CriticalSection;
|
||||
|
||||
/// Generate a standard `mod interrupt` for a HAL.
|
||||
#[macro_export]
|
||||
@ -91,6 +92,12 @@ macro_rules! interrupt_mod {
|
||||
fn set_priority(prio: crate::interrupt::Priority) {
|
||||
Self::IRQ.set_priority(prio)
|
||||
}
|
||||
|
||||
/// Set the interrupt priority with an already-acquired critical section
|
||||
#[inline]
|
||||
fn set_priority_with_cs(cs: critical_section::CriticalSection, prio: crate::interrupt::Priority) {
|
||||
Self::IRQ.set_priority_with_cs(cs, prio)
|
||||
}
|
||||
}
|
||||
|
||||
$(
|
||||
@ -195,10 +202,29 @@ pub unsafe trait InterruptExt: InterruptNumber + Copy {
|
||||
/// Set the interrupt priority.
|
||||
#[inline]
|
||||
fn set_priority(self, prio: Priority) {
|
||||
critical_section::with(|_| unsafe {
|
||||
unsafe {
|
||||
let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(());
|
||||
nvic.set_priority(self, prio.into())
|
||||
})
|
||||
|
||||
// On thumbv6, set_priority must do a RMW to change 8bit in a 32bit reg.
|
||||
#[cfg(armv6m)]
|
||||
critical_section::with(|_| nvic.set_priority(self, prio.into()));
|
||||
// On thumbv7+, set_priority does an atomic 8bit write, so no CS needed.
|
||||
#[cfg(not(armv6m))]
|
||||
nvic.set_priority(self, prio.into());
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the interrupt priority with an already-acquired critical section
|
||||
///
|
||||
/// Equivalent to `set_priority`, except you pass a `CriticalSection` to prove
|
||||
/// you've already acquired a critical section. This prevents acquiring another
|
||||
/// one, which saves code size.
|
||||
#[inline]
|
||||
fn set_priority_with_cs(self, _cs: CriticalSection, prio: Priority) {
|
||||
unsafe {
|
||||
let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(());
|
||||
nvic.set_priority(self, prio.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,6 @@ pub mod drop;
|
||||
mod macros;
|
||||
mod peripheral;
|
||||
pub mod ratio;
|
||||
pub mod ring_buffer;
|
||||
pub use peripheral::{Peripheral, PeripheralRef};
|
||||
|
||||
#[cfg(feature = "cortex-m")]
|
||||
|
@ -48,17 +48,23 @@ macro_rules! peripherals_struct {
|
||||
///Returns all the peripherals *once*
|
||||
#[inline]
|
||||
pub(crate) fn take() -> Self {
|
||||
critical_section::with(Self::take_with_cs)
|
||||
}
|
||||
|
||||
///Returns all the peripherals *once*
|
||||
#[inline]
|
||||
pub(crate) fn take_with_cs(_cs: critical_section::CriticalSection) -> Self {
|
||||
#[no_mangle]
|
||||
static mut _EMBASSY_DEVICE_PERIPHERALS: bool = false;
|
||||
|
||||
critical_section::with(|_| unsafe {
|
||||
// safety: OK because we're inside a CS.
|
||||
unsafe {
|
||||
if _EMBASSY_DEVICE_PERIPHERALS {
|
||||
panic!("init called more than once!")
|
||||
}
|
||||
_EMBASSY_DEVICE_PERIPHERALS = true;
|
||||
Self::steal()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,136 +0,0 @@
|
||||
pub struct RingBuffer<'a> {
|
||||
buf: &'a mut [u8],
|
||||
start: usize,
|
||||
end: usize,
|
||||
empty: bool,
|
||||
}
|
||||
|
||||
impl<'a> RingBuffer<'a> {
|
||||
pub fn new(buf: &'a mut [u8]) -> Self {
|
||||
Self {
|
||||
buf,
|
||||
start: 0,
|
||||
end: 0,
|
||||
empty: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_buf(&mut self) -> &mut [u8] {
|
||||
if self.start == self.end && !self.empty {
|
||||
trace!(" ringbuf: push_buf empty");
|
||||
return &mut self.buf[..0];
|
||||
}
|
||||
|
||||
let n = if self.start <= self.end {
|
||||
self.buf.len() - self.end
|
||||
} else {
|
||||
self.start - self.end
|
||||
};
|
||||
|
||||
trace!(" ringbuf: push_buf {:?}..{:?}", self.end, self.end + n);
|
||||
&mut self.buf[self.end..self.end + n]
|
||||
}
|
||||
|
||||
pub fn push(&mut self, n: usize) {
|
||||
trace!(" ringbuf: push {:?}", n);
|
||||
if n == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
self.end = self.wrap(self.end + n);
|
||||
self.empty = false;
|
||||
}
|
||||
|
||||
pub fn pop_buf(&mut self) -> &mut [u8] {
|
||||
if self.empty {
|
||||
trace!(" ringbuf: pop_buf empty");
|
||||
return &mut self.buf[..0];
|
||||
}
|
||||
|
||||
let n = if self.end <= self.start {
|
||||
self.buf.len() - self.start
|
||||
} else {
|
||||
self.end - self.start
|
||||
};
|
||||
|
||||
trace!(" ringbuf: pop_buf {:?}..{:?}", self.start, self.start + n);
|
||||
&mut self.buf[self.start..self.start + n]
|
||||
}
|
||||
|
||||
pub fn pop(&mut self, n: usize) {
|
||||
trace!(" ringbuf: pop {:?}", n);
|
||||
if n == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
self.start = self.wrap(self.start + n);
|
||||
self.empty = self.start == self.end;
|
||||
}
|
||||
|
||||
pub fn is_full(&self) -> bool {
|
||||
self.start == self.end && !self.empty
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.empty
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.start = 0;
|
||||
self.end = 0;
|
||||
self.empty = true;
|
||||
}
|
||||
|
||||
fn wrap(&self, n: usize) -> usize {
|
||||
assert!(n <= self.buf.len());
|
||||
if n == self.buf.len() {
|
||||
0
|
||||
} else {
|
||||
n
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn push_pop() {
|
||||
let mut b = [0; 4];
|
||||
let mut rb = RingBuffer::new(&mut b);
|
||||
let buf = rb.push_buf();
|
||||
assert_eq!(4, buf.len());
|
||||
buf[0] = 1;
|
||||
buf[1] = 2;
|
||||
buf[2] = 3;
|
||||
buf[3] = 4;
|
||||
rb.push(4);
|
||||
|
||||
let buf = rb.pop_buf();
|
||||
assert_eq!(4, buf.len());
|
||||
assert_eq!(1, buf[0]);
|
||||
rb.pop(1);
|
||||
|
||||
let buf = rb.pop_buf();
|
||||
assert_eq!(3, buf.len());
|
||||
assert_eq!(2, buf[0]);
|
||||
rb.pop(1);
|
||||
|
||||
let buf = rb.pop_buf();
|
||||
assert_eq!(2, buf.len());
|
||||
assert_eq!(3, buf[0]);
|
||||
rb.pop(1);
|
||||
|
||||
let buf = rb.pop_buf();
|
||||
assert_eq!(1, buf.len());
|
||||
assert_eq!(4, buf[0]);
|
||||
rb.pop(1);
|
||||
|
||||
let buf = rb.pop_buf();
|
||||
assert_eq!(0, buf.len());
|
||||
|
||||
let buf = rb.push_buf();
|
||||
assert_eq!(4, buf.len());
|
||||
}
|
||||
}
|
@ -20,15 +20,12 @@ defmt = ["dep:defmt", "lorawan-device/defmt"]
|
||||
defmt = { version = "0.3", 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.5", path = "../embassy-time", optional = true }
|
||||
embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
|
||||
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 = { version = "0.2", features = ["unproven"] }
|
||||
|
||||
futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] }
|
||||
lora-phy = { version = "1" }
|
||||
lorawan-device = { version = "0.10.0", default-features = false, features = ["async"], optional = true }
|
||||
|
||||
[patch.crates-io]
|
||||
lora-phy = { git = "https://github.com/embassy-rs/lora-phy", rev = "1323eccc1c470d4259f95f4f315d1be830d572a3"}
|
||||
lora-phy = { version = "2" }
|
||||
lorawan-device = { version = "0.11.0", default-features = false, features = ["async"], optional = true }
|
||||
|
@ -67,24 +67,20 @@ where
|
||||
self.board_type = board_type;
|
||||
}
|
||||
async fn set_nss_low(&mut self) -> Result<(), RadioError> {
|
||||
let pwr = pac::PWR;
|
||||
pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::LOW));
|
||||
pac::PWR.subghzspicr().modify(|w| w.set_nss(false));
|
||||
Ok(())
|
||||
}
|
||||
async fn set_nss_high(&mut self) -> Result<(), RadioError> {
|
||||
let pwr = pac::PWR;
|
||||
pwr.subghzspicr().modify(|w| w.set_nss(pac::pwr::vals::Nss::HIGH));
|
||||
pac::PWR.subghzspicr().modify(|w| w.set_nss(true));
|
||||
Ok(())
|
||||
}
|
||||
async fn reset(&mut self, _delay: &mut impl DelayUs) -> Result<(), RadioError> {
|
||||
let rcc = pac::RCC;
|
||||
rcc.csr().modify(|w| w.set_rfrst(true));
|
||||
rcc.csr().modify(|w| w.set_rfrst(false));
|
||||
pac::RCC.csr().modify(|w| w.set_rfrst(true));
|
||||
pac::RCC.csr().modify(|w| w.set_rfrst(false));
|
||||
Ok(())
|
||||
}
|
||||
async fn wait_on_busy(&mut self) -> Result<(), RadioError> {
|
||||
let pwr = pac::PWR;
|
||||
while pwr.sr2().read().rfbusys() == pac::pwr::vals::Rfbusys::BUSY {}
|
||||
while pac::PWR.sr2().read().rfbusys() {}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#![no_std]
|
||||
#![feature(async_fn_in_trait, impl_trait_projections)]
|
||||
#![feature(async_fn_in_trait)]
|
||||
//! embassy-lora holds LoRa-specific functionality.
|
||||
|
||||
pub(crate) mod fmt;
|
||||
@ -34,6 +34,6 @@ impl lorawan_device::async_device::radio::Timer for LoraTimer {
|
||||
}
|
||||
|
||||
async fn delay_ms(&mut self, millis: u64) {
|
||||
Timer::after(Duration::from_millis(millis)).await
|
||||
Timer::after_millis(millis).await
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" }
|
||||
embedded-hal-async = { version = "=1.0.0-rc.1" }
|
||||
embedded-hal-bus = { version = "=0.1.0-rc.1", features = ["async"] }
|
||||
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
|
||||
embassy-time = { version = "0.1.3" }
|
||||
embassy-time = { version = "0.1.5", path = "../embassy-time" }
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
bitfield = "0.14.0"
|
||||
|
||||
|
@ -20,7 +20,7 @@ pub use crc32::ETH_FCS;
|
||||
use crc8::crc8;
|
||||
use embassy_futures::select::{select, Either};
|
||||
use embassy_net_driver_channel as ch;
|
||||
use embassy_time::{Duration, Timer};
|
||||
use embassy_time::Timer;
|
||||
use embedded_hal_1::digital::OutputPin;
|
||||
use embedded_hal_async::digital::Wait;
|
||||
use embedded_hal_async::spi::{Error, Operation, SpiDevice};
|
||||
@ -609,12 +609,12 @@ pub async fn new<const N_RX: usize, const N_TX: usize, SPI: SpiDevice, INT: Wait
|
||||
reset.set_low().unwrap();
|
||||
|
||||
// Wait t1: 20-43mS
|
||||
Timer::after(Duration::from_millis(30)).await;
|
||||
Timer::after_millis(30).await;
|
||||
|
||||
reset.set_high().unwrap();
|
||||
|
||||
// Wait t3: 50mS
|
||||
Timer::after(Duration::from_millis(50)).await;
|
||||
Timer::after_millis(50).await;
|
||||
|
||||
// Create device
|
||||
let mut mac = ADIN1110::new(spi_dev, spi_crc, append_fcs_on_tx);
|
||||
|
@ -11,7 +11,7 @@ edition = "2021"
|
||||
embedded-hal = { version = "1.0.0-rc.1" }
|
||||
embedded-hal-async = { version = "=1.0.0-rc.1" }
|
||||
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.5", path = "../embassy-time" }
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
|
||||
defmt = { version = "0.3", optional = true }
|
||||
|
@ -194,10 +194,15 @@ where
|
||||
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
|
||||
/// NOTE: The returned packet *must* be `read` or `ignore`-d, otherwise this method will always
|
||||
/// 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 {
|
||||
// Errata #6: we can't rely on PKTIF so we check PKTCNT
|
||||
return None;
|
||||
@ -241,7 +246,7 @@ where
|
||||
|
||||
self.next_packet = next_packet;
|
||||
|
||||
Some(&mut buf[..len as usize])
|
||||
Some(len as usize)
|
||||
}
|
||||
|
||||
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<'_>)> {
|
||||
let rx_buf = unsafe { &mut RX_BUF };
|
||||
let tx_buf = unsafe { &mut TX_BUF };
|
||||
if let Some(pkt) = self.receive(rx_buf) {
|
||||
let n = pkt.len();
|
||||
Some((RxToken { buf: &mut pkt[..n] }, TxToken { buf: tx_buf, eth: self }))
|
||||
if let Some(n) = self.receive(rx_buf) {
|
||||
Some((RxToken { buf: &mut rx_buf[..n] }, TxToken { buf: tx_buf, eth: self }))
|
||||
} else {
|
||||
cx.waker().wake_by_ref();
|
||||
None
|
||||
|
@ -7,7 +7,7 @@ edition = "2021"
|
||||
defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.14", optional = true }
|
||||
|
||||
embassy-time = { version = "0.1.3", path = "../embassy-time" }
|
||||
embassy-time = { version = "0.1.5", path = "../embassy-time" }
|
||||
embassy-sync = { version = "0.3.0", path = "../embassy-sync"}
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
|
||||
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"}
|
||||
|
@ -169,9 +169,9 @@ where
|
||||
pub async fn run(mut self) -> ! {
|
||||
debug!("resetting...");
|
||||
self.reset.set_low().unwrap();
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
Timer::after_millis(100).await;
|
||||
self.reset.set_high().unwrap();
|
||||
Timer::after(Duration::from_millis(1000)).await;
|
||||
Timer::after_millis(1000).await;
|
||||
|
||||
let mut tx_buf = [0u8; MAX_SPI_BUFFER_SIZE];
|
||||
let mut rx_buf = [0u8; MAX_SPI_BUFFER_SIZE];
|
||||
|
@ -15,7 +15,7 @@ log = ["dep:log", "ppproto/log"]
|
||||
defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.14", optional = true }
|
||||
|
||||
embedded-io-async = { version = "0.5.0" }
|
||||
embedded-io-async = { version = "0.6.0" }
|
||||
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
ppproto = { version = "0.1.2"}
|
||||
|
@ -11,7 +11,7 @@ use core::mem::MaybeUninit;
|
||||
use embassy_futures::select::{select, Either};
|
||||
use embassy_net_driver_channel as ch;
|
||||
use embassy_net_driver_channel::driver::LinkState;
|
||||
use embedded_io_async::{BufRead, Write, WriteAllError};
|
||||
use embedded_io_async::{BufRead, Write};
|
||||
use ppproto::pppos::{BufferFullError, PPPoS, PPPoSAction};
|
||||
pub use ppproto::{Config, Ipv4Status};
|
||||
|
||||
@ -49,23 +49,12 @@ pub enum RunError<E> {
|
||||
Read(E),
|
||||
/// Writing to the serial port failed.
|
||||
Write(E),
|
||||
/// Writing to the serial port wrote zero bytes, indicating it can't accept more data.
|
||||
WriteZero,
|
||||
/// Writing to the serial got EOF.
|
||||
Eof,
|
||||
/// PPP protocol was terminated by the peer
|
||||
Terminated,
|
||||
}
|
||||
|
||||
impl<E> From<WriteAllError<E>> for RunError<E> {
|
||||
fn from(value: WriteAllError<E>) -> Self {
|
||||
match value {
|
||||
WriteAllError::Other(e) => Self::Write(e),
|
||||
WriteAllError::WriteZero => Self::WriteZero,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> Runner<'d> {
|
||||
/// You must call this in a background task for the driver to operate.
|
||||
///
|
||||
@ -125,7 +114,7 @@ impl<'d> Runner<'d> {
|
||||
buf[..pkt.len()].copy_from_slice(pkt);
|
||||
rx_chan.rx_done(pkt.len());
|
||||
}
|
||||
PPPoSAction::Transmit(n) => rw.write_all(&tx_buf[..n]).await?,
|
||||
PPPoSAction::Transmit(n) => rw.write_all(&tx_buf[..n]).await.map_err(RunError::Write)?,
|
||||
}
|
||||
|
||||
let status = ppp.status();
|
||||
@ -148,7 +137,7 @@ impl<'d> Runner<'d> {
|
||||
}
|
||||
Either::Second(pkt) => {
|
||||
match ppp.send(pkt, &mut tx_buf) {
|
||||
Ok(n) => rw.write_all(&tx_buf[..n]).await?,
|
||||
Ok(n) => rw.write_all(&tx_buf[..n]).await.map_err(RunError::Write)?,
|
||||
Err(BufferFullError) => unreachable!(),
|
||||
}
|
||||
tx_chan.tx_done();
|
||||
|
@ -11,7 +11,7 @@ edition = "2021"
|
||||
embedded-hal = { version = "1.0.0-rc.1" }
|
||||
embedded-hal-async = { version = "=1.0.0-rc.1" }
|
||||
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
|
||||
embassy-time = { version = "0.1.3", path = "../embassy-time" }
|
||||
embassy-time = { version = "0.1.5", path = "../embassy-time" }
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
defmt = { version = "0.3", optional = true }
|
||||
|
||||
|
@ -8,7 +8,7 @@ mod device;
|
||||
use embassy_futures::select::{select, Either};
|
||||
use embassy_net_driver_channel as ch;
|
||||
use embassy_net_driver_channel::driver::LinkState;
|
||||
use embassy_time::{Duration, Timer};
|
||||
use embassy_time::Timer;
|
||||
use embedded_hal::digital::OutputPin;
|
||||
use embedded_hal_async::digital::Wait;
|
||||
use embedded_hal_async::spi::SpiDevice;
|
||||
@ -95,12 +95,12 @@ pub async fn new<'a, const N_RX: usize, const N_TX: usize, C: Chip, SPI: SpiDevi
|
||||
// Reset the chip.
|
||||
reset.set_low().ok();
|
||||
// Ensure the reset is registered.
|
||||
Timer::after(Duration::from_millis(1)).await;
|
||||
Timer::after_millis(1).await;
|
||||
reset.set_high().ok();
|
||||
|
||||
// Wait for PLL lock. Some chips are slower than others.
|
||||
// Slowest is w5100s which is 100ms, so let's just wait that.
|
||||
Timer::after(Duration::from_millis(100)).await;
|
||||
Timer::after_millis(100).await;
|
||||
|
||||
let mac = WiznetDevice::new(spi_dev, mac_addr).await.unwrap();
|
||||
|
||||
|
@ -33,6 +33,7 @@ udp = ["smoltcp/socket-udp"]
|
||||
tcp = ["smoltcp/socket-tcp"]
|
||||
dns = ["smoltcp/socket-dns", "smoltcp/proto-dns"]
|
||||
dhcpv4 = ["proto-ipv4", "medium-ethernet", "smoltcp/socket-dhcpv4"]
|
||||
dhcpv4-hostname = ["dhcpv4"]
|
||||
proto-ipv4 = ["smoltcp/proto-ipv4"]
|
||||
proto-ipv6 = ["smoltcp/proto-ipv6"]
|
||||
medium-ethernet = ["smoltcp/medium-ethernet"]
|
||||
@ -51,9 +52,9 @@ smoltcp = { version = "0.10.0", default-features = false, features = [
|
||||
] }
|
||||
|
||||
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.5", path = "../embassy-time" }
|
||||
embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
|
||||
embedded-io-async = { version = "0.5.0", optional = true }
|
||||
embedded-io-async = { version = "0.6.0", optional = true }
|
||||
|
||||
managed = { version = "0.8.0", default-features = false, features = [ "map" ] }
|
||||
heapless = { version = "0.7.5", default-features = false }
|
||||
@ -62,5 +63,4 @@ generic-array = { version = "0.14.4", default-features = false }
|
||||
stable_deref_trait = { version = "1.2.0", default-features = false }
|
||||
futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] }
|
||||
atomic-pool = "1.0"
|
||||
embedded-nal-async = { version = "0.5.0", optional = true }
|
||||
atomic-polyfill = { version = "1.0" }
|
||||
embedded-nal-async = { version = "0.6.0", optional = true }
|
||||
|
@ -1,5 +1,5 @@
|
||||
#![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)]
|
||||
#![doc = include_str!("../README.md")]
|
||||
|
||||
@ -39,7 +39,7 @@ use smoltcp::socket::dhcpv4::{self, RetryConfig};
|
||||
pub use smoltcp::wire::EthernetAddress;
|
||||
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154", feature = "medium-ip"))]
|
||||
pub use smoltcp::wire::HardwareAddress;
|
||||
#[cfg(feature = "udp")]
|
||||
#[cfg(any(feature = "udp", feature = "tcp"))]
|
||||
pub use smoltcp::wire::IpListenEndpoint;
|
||||
#[cfg(feature = "medium-ieee802154")]
|
||||
pub use smoltcp::wire::{Ieee802154Address, Ieee802154Frame};
|
||||
@ -56,12 +56,22 @@ const LOCAL_PORT_MIN: u16 = 1025;
|
||||
const LOCAL_PORT_MAX: u16 = 65535;
|
||||
#[cfg(feature = "dns")]
|
||||
const MAX_QUERIES: usize = 4;
|
||||
#[cfg(feature = "dhcpv4-hostname")]
|
||||
const MAX_HOSTNAME_LEN: usize = 32;
|
||||
|
||||
/// Memory resources needed for a network stack.
|
||||
pub struct StackResources<const SOCK: usize> {
|
||||
sockets: [SocketStorage<'static>; SOCK],
|
||||
#[cfg(feature = "dns")]
|
||||
queries: [Option<dns::DnsQuery>; MAX_QUERIES],
|
||||
#[cfg(feature = "dhcpv4-hostname")]
|
||||
hostname: core::cell::UnsafeCell<HostnameResources>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "dhcpv4-hostname")]
|
||||
struct HostnameResources {
|
||||
option: smoltcp::wire::DhcpOption<'static>,
|
||||
data: [u8; MAX_HOSTNAME_LEN],
|
||||
}
|
||||
|
||||
impl<const SOCK: usize> StackResources<SOCK> {
|
||||
@ -73,6 +83,11 @@ impl<const SOCK: usize> StackResources<SOCK> {
|
||||
sockets: [SocketStorage::EMPTY; SOCK],
|
||||
#[cfg(feature = "dns")]
|
||||
queries: [INIT; MAX_QUERIES],
|
||||
#[cfg(feature = "dhcpv4-hostname")]
|
||||
hostname: core::cell::UnsafeCell::new(HostnameResources {
|
||||
option: smoltcp::wire::DhcpOption { kind: 0, data: &[] },
|
||||
data: [0; MAX_HOSTNAME_LEN],
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -104,6 +119,7 @@ pub struct StaticConfigV6 {
|
||||
/// DHCP configuration.
|
||||
#[cfg(feature = "dhcpv4")]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[non_exhaustive]
|
||||
pub struct DhcpConfig {
|
||||
/// Maximum lease duration.
|
||||
///
|
||||
@ -120,6 +136,9 @@ pub struct DhcpConfig {
|
||||
pub server_port: u16,
|
||||
/// Client port. This is almost always 68. Do not change unless you know what you're doing.
|
||||
pub client_port: u16,
|
||||
/// Our hostname. This will be sent to the DHCP server as Option 12.
|
||||
#[cfg(feature = "dhcpv4-hostname")]
|
||||
pub hostname: Option<heapless::String<MAX_HOSTNAME_LEN>>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "dhcpv4")]
|
||||
@ -131,6 +150,8 @@ impl Default for DhcpConfig {
|
||||
ignore_naks: Default::default(),
|
||||
server_port: smoltcp::wire::DHCP_SERVER_PORT,
|
||||
client_port: smoltcp::wire::DHCP_CLIENT_PORT,
|
||||
#[cfg(feature = "dhcpv4-hostname")]
|
||||
hostname: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -232,6 +253,8 @@ struct Inner<D: Driver> {
|
||||
dns_socket: SocketHandle,
|
||||
#[cfg(feature = "dns")]
|
||||
dns_waker: WakerRegistration,
|
||||
#[cfg(feature = "dhcpv4-hostname")]
|
||||
hostname: &'static mut core::cell::UnsafeCell<HostnameResources>,
|
||||
}
|
||||
|
||||
pub(crate) struct SocketStack {
|
||||
@ -258,7 +281,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.
|
||||
pub fn new<const SOCK: usize>(
|
||||
mut device: D,
|
||||
@ -307,6 +330,8 @@ impl<D: Driver + 'static> Stack<D> {
|
||||
)),
|
||||
#[cfg(feature = "dns")]
|
||||
dns_waker: WakerRegistration::new(),
|
||||
#[cfg(feature = "dhcpv4-hostname")]
|
||||
hostname: &mut resources.hostname,
|
||||
};
|
||||
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
@ -484,7 +509,10 @@ impl<D: Driver + 'static> Stack<D> {
|
||||
self.with_mut(|s, i| {
|
||||
let socket = s.sockets.get_mut::<dns::Socket>(i.dns_socket);
|
||||
match socket.start_query(s.iface.context(), name, qtype) {
|
||||
Ok(handle) => Poll::Ready(Ok(handle)),
|
||||
Ok(handle) => {
|
||||
s.waker.wake();
|
||||
Poll::Ready(Ok(handle))
|
||||
}
|
||||
Err(dns::StartQueryError::NoFreeSlot) => {
|
||||
i.dns_waker.register(cx.waker());
|
||||
Poll::Pending
|
||||
@ -555,7 +583,7 @@ impl<D: Driver + 'static> Stack<D> {
|
||||
}
|
||||
|
||||
#[cfg(feature = "igmp")]
|
||||
impl<D: Driver + 'static> Stack<D> {
|
||||
impl<D: Driver> Stack<D> {
|
||||
/// Join a multicast group.
|
||||
pub async fn join_multicast_group<T>(&self, addr: T) -> Result<bool, MulticastError>
|
||||
where
|
||||
@ -645,7 +673,7 @@ impl SocketStack {
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Driver + 'static> Inner<D> {
|
||||
impl<D: Driver> Inner<D> {
|
||||
#[cfg(feature = "proto-ipv4")]
|
||||
pub fn set_config_v4(&mut self, _s: &mut SocketStack, config: ConfigV4) {
|
||||
// Handle static config.
|
||||
@ -673,6 +701,25 @@ impl<D: Driver + 'static> Inner<D> {
|
||||
socket.set_max_lease_duration(c.max_lease_duration.map(crate::time::duration_to_smoltcp));
|
||||
socket.set_ports(c.server_port, c.client_port);
|
||||
socket.set_retry_config(c.retry_config);
|
||||
|
||||
socket.set_outgoing_options(&[]);
|
||||
#[cfg(feature = "dhcpv4-hostname")]
|
||||
if let Some(h) = c.hostname {
|
||||
// safety: we just did set_outgoing_options([]) so we know the socket is no longer holding a reference.
|
||||
let hostname = unsafe { &mut *self.hostname.get() };
|
||||
|
||||
// create data
|
||||
// safety: we know the buffer lives forever, new borrows the StackResources for 'static.
|
||||
// also we won't modify it until next call to this function.
|
||||
hostname.data[..h.len()].copy_from_slice(h.as_bytes());
|
||||
let data: &[u8] = &hostname.data[..h.len()];
|
||||
let data: &'static [u8] = unsafe { core::mem::transmute(data) };
|
||||
|
||||
// set the option.
|
||||
hostname.option = smoltcp::wire::DhcpOption { data, kind: 12 };
|
||||
socket.set_outgoing_options(core::slice::from_ref(&hostname.option));
|
||||
}
|
||||
|
||||
socket.reset();
|
||||
}
|
||||
_ => {
|
||||
|
@ -579,11 +579,10 @@ mod embedded_io_impls {
|
||||
/// TCP client compatible with `embedded-nal-async` traits.
|
||||
#[cfg(feature = "nightly")]
|
||||
pub mod client {
|
||||
use core::cell::UnsafeCell;
|
||||
use core::cell::{Cell, UnsafeCell};
|
||||
use core::mem::MaybeUninit;
|
||||
use core::ptr::NonNull;
|
||||
|
||||
use atomic_polyfill::{AtomicBool, Ordering};
|
||||
use embedded_nal_async::IpAddr;
|
||||
|
||||
use super::*;
|
||||
@ -702,15 +701,13 @@ pub mod client {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<const N: usize, const TX_SZ: usize, const RX_SZ: usize> Sync for TcpClientState<N, TX_SZ, RX_SZ> {}
|
||||
|
||||
struct Pool<T, const N: usize> {
|
||||
used: [AtomicBool; N],
|
||||
used: [Cell<bool>; N],
|
||||
data: [UnsafeCell<MaybeUninit<T>>; N],
|
||||
}
|
||||
|
||||
impl<T, const N: usize> Pool<T, N> {
|
||||
const VALUE: AtomicBool = AtomicBool::new(false);
|
||||
const VALUE: Cell<bool> = Cell::new(false);
|
||||
const UNINIT: UnsafeCell<MaybeUninit<T>> = UnsafeCell::new(MaybeUninit::uninit());
|
||||
|
||||
const fn new() -> Self {
|
||||
@ -724,7 +721,9 @@ pub mod client {
|
||||
impl<T, const N: usize> Pool<T, N> {
|
||||
fn alloc(&self) -> Option<NonNull<T>> {
|
||||
for n in 0..N {
|
||||
if self.used[n].swap(true, Ordering::SeqCst) == false {
|
||||
// this can't race because Pool is not Sync.
|
||||
if !self.used[n].get() {
|
||||
self.used[n].set(true);
|
||||
let p = self.data[n].get() as *mut T;
|
||||
return Some(unsafe { NonNull::new_unchecked(p) });
|
||||
}
|
||||
@ -738,7 +737,7 @@ pub mod client {
|
||||
let n = p.as_ptr().offset_from(origin);
|
||||
assert!(n >= 0);
|
||||
assert!((n as usize) < N);
|
||||
self.used[n as usize].store(false, Ordering::SeqCst);
|
||||
self.used[n as usize].set(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ nrf52805 = ["nrf52805-pac", "_nrf52"]
|
||||
nrf52810 = ["nrf52810-pac", "_nrf52"]
|
||||
nrf52811 = ["nrf52811-pac", "_nrf52"]
|
||||
nrf52820 = ["nrf52820-pac", "_nrf52"]
|
||||
nrf52832 = ["nrf52832-pac", "_nrf52"]
|
||||
nrf52832 = ["nrf52832-pac", "_nrf52", "_nrf52832_anomaly_109"]
|
||||
nrf52833 = ["nrf52833-pac", "_nrf52", "_gpio-p1"]
|
||||
nrf52840 = ["nrf52840-pac", "_nrf52", "_gpio-p1"]
|
||||
nrf5340-app-s = ["_nrf5340-app", "_s"]
|
||||
@ -90,8 +90,11 @@ _ppi = []
|
||||
_dppi = []
|
||||
_gpio-p1 = []
|
||||
|
||||
# Errata workarounds
|
||||
_nrf52832_anomaly_109 = []
|
||||
|
||||
[dependencies]
|
||||
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
|
||||
embassy-time = { version = "0.1.5", path = "../embassy-time", optional = true }
|
||||
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-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||
@ -100,8 +103,8 @@ embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optiona
|
||||
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
|
||||
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1", optional = true}
|
||||
embedded-hal-async = { version = "=1.0.0-rc.1", optional = true}
|
||||
embedded-io = { version = "0.5.0" }
|
||||
embedded-io-async = { version = "0.5.0", optional = true }
|
||||
embedded-io = { version = "0.6.0" }
|
||||
embedded-io-async = { version = "0.6.0", optional = true }
|
||||
|
||||
defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.14", optional = true }
|
||||
|
@ -6,10 +6,13 @@ pub mod pac {
|
||||
// To avoid cfg spam, we remove _ns or _s suffixes here.
|
||||
|
||||
pub use nrf5340_app_pac::NVIC_PRIO_BITS;
|
||||
|
||||
|
||||
#[cfg(feature="rt")]
|
||||
#[doc(no_inline)]
|
||||
pub use nrf5340_app_pac::interrupt;
|
||||
|
||||
#[doc(no_inline)]
|
||||
pub use nrf5340_app_pac::{
|
||||
interrupt,
|
||||
Interrupt,
|
||||
Peripherals,
|
||||
|
||||
@ -60,156 +63,167 @@ pub mod pac {
|
||||
wdt0_ns as wdt0,
|
||||
};
|
||||
|
||||
#[cfg(feature = "nrf5340-app-ns")]
|
||||
#[doc(no_inline)]
|
||||
pub use nrf5340_app_pac::{
|
||||
CLOCK_NS as CLOCK,
|
||||
COMP_NS as COMP,
|
||||
CTRLAP_NS as CTRLAP,
|
||||
DCNF_NS as DCNF,
|
||||
DPPIC_NS as DPPIC,
|
||||
EGU0_NS as EGU0,
|
||||
EGU1_NS as EGU1,
|
||||
EGU2_NS as EGU2,
|
||||
EGU3_NS as EGU3,
|
||||
EGU4_NS as EGU4,
|
||||
EGU5_NS as EGU5,
|
||||
FPU_NS as FPU,
|
||||
GPIOTE1_NS as GPIOTE1,
|
||||
I2S0_NS as I2S0,
|
||||
IPC_NS as IPC,
|
||||
KMU_NS as KMU,
|
||||
LPCOMP_NS as LPCOMP,
|
||||
MUTEX_NS as MUTEX,
|
||||
NFCT_NS as NFCT,
|
||||
NVMC_NS as NVMC,
|
||||
OSCILLATORS_NS as OSCILLATORS,
|
||||
P0_NS as P0,
|
||||
P1_NS as P1,
|
||||
PDM0_NS as PDM0,
|
||||
POWER_NS as POWER,
|
||||
PWM0_NS as PWM0,
|
||||
PWM1_NS as PWM1,
|
||||
PWM2_NS as PWM2,
|
||||
PWM3_NS as PWM3,
|
||||
QDEC0_NS as QDEC0,
|
||||
QDEC1_NS as QDEC1,
|
||||
QSPI_NS as QSPI,
|
||||
REGULATORS_NS as REGULATORS,
|
||||
RESET_NS as RESET,
|
||||
RTC0_NS as RTC0,
|
||||
RTC1_NS as RTC1,
|
||||
SAADC_NS as SAADC,
|
||||
SPIM0_NS as SPIM0,
|
||||
SPIM1_NS as SPIM1,
|
||||
SPIM2_NS as SPIM2,
|
||||
SPIM3_NS as SPIM3,
|
||||
SPIM4_NS as SPIM4,
|
||||
SPIS0_NS as SPIS0,
|
||||
SPIS1_NS as SPIS1,
|
||||
SPIS2_NS as SPIS2,
|
||||
SPIS3_NS as SPIS3,
|
||||
TIMER0_NS as TIMER0,
|
||||
TIMER1_NS as TIMER1,
|
||||
TIMER2_NS as TIMER2,
|
||||
TWIM0_NS as TWIM0,
|
||||
TWIM1_NS as TWIM1,
|
||||
TWIM2_NS as TWIM2,
|
||||
TWIM3_NS as TWIM3,
|
||||
TWIS0_NS as TWIS0,
|
||||
TWIS1_NS as TWIS1,
|
||||
TWIS2_NS as TWIS2,
|
||||
TWIS3_NS as TWIS3,
|
||||
UARTE0_NS as UARTE0,
|
||||
UARTE1_NS as UARTE1,
|
||||
UARTE2_NS as UARTE2,
|
||||
UARTE3_NS as UARTE3,
|
||||
USBD_NS as USBD,
|
||||
USBREGULATOR_NS as USBREGULATOR,
|
||||
VMC_NS as VMC,
|
||||
WDT0_NS as WDT0,
|
||||
WDT1_NS as WDT1,
|
||||
};
|
||||
/// Non-Secure mode (NS) peripherals
|
||||
pub mod ns {
|
||||
#[cfg(feature = "nrf5340-app-ns")]
|
||||
#[doc(no_inline)]
|
||||
pub use nrf5340_app_pac::{
|
||||
CLOCK_NS as CLOCK,
|
||||
COMP_NS as COMP,
|
||||
CTRLAP_NS as CTRLAP,
|
||||
DCNF_NS as DCNF,
|
||||
DPPIC_NS as DPPIC,
|
||||
EGU0_NS as EGU0,
|
||||
EGU1_NS as EGU1,
|
||||
EGU2_NS as EGU2,
|
||||
EGU3_NS as EGU3,
|
||||
EGU4_NS as EGU4,
|
||||
EGU5_NS as EGU5,
|
||||
FPU_NS as FPU,
|
||||
GPIOTE1_NS as GPIOTE1,
|
||||
I2S0_NS as I2S0,
|
||||
IPC_NS as IPC,
|
||||
KMU_NS as KMU,
|
||||
LPCOMP_NS as LPCOMP,
|
||||
MUTEX_NS as MUTEX,
|
||||
NFCT_NS as NFCT,
|
||||
NVMC_NS as NVMC,
|
||||
OSCILLATORS_NS as OSCILLATORS,
|
||||
P0_NS as P0,
|
||||
P1_NS as P1,
|
||||
PDM0_NS as PDM0,
|
||||
POWER_NS as POWER,
|
||||
PWM0_NS as PWM0,
|
||||
PWM1_NS as PWM1,
|
||||
PWM2_NS as PWM2,
|
||||
PWM3_NS as PWM3,
|
||||
QDEC0_NS as QDEC0,
|
||||
QDEC1_NS as QDEC1,
|
||||
QSPI_NS as QSPI,
|
||||
REGULATORS_NS as REGULATORS,
|
||||
RESET_NS as RESET,
|
||||
RTC0_NS as RTC0,
|
||||
RTC1_NS as RTC1,
|
||||
SAADC_NS as SAADC,
|
||||
SPIM0_NS as SPIM0,
|
||||
SPIM1_NS as SPIM1,
|
||||
SPIM2_NS as SPIM2,
|
||||
SPIM3_NS as SPIM3,
|
||||
SPIM4_NS as SPIM4,
|
||||
SPIS0_NS as SPIS0,
|
||||
SPIS1_NS as SPIS1,
|
||||
SPIS2_NS as SPIS2,
|
||||
SPIS3_NS as SPIS3,
|
||||
TIMER0_NS as TIMER0,
|
||||
TIMER1_NS as TIMER1,
|
||||
TIMER2_NS as TIMER2,
|
||||
TWIM0_NS as TWIM0,
|
||||
TWIM1_NS as TWIM1,
|
||||
TWIM2_NS as TWIM2,
|
||||
TWIM3_NS as TWIM3,
|
||||
TWIS0_NS as TWIS0,
|
||||
TWIS1_NS as TWIS1,
|
||||
TWIS2_NS as TWIS2,
|
||||
TWIS3_NS as TWIS3,
|
||||
UARTE0_NS as UARTE0,
|
||||
UARTE1_NS as UARTE1,
|
||||
UARTE2_NS as UARTE2,
|
||||
UARTE3_NS as UARTE3,
|
||||
USBD_NS as USBD,
|
||||
USBREGULATOR_NS as USBREGULATOR,
|
||||
VMC_NS as VMC,
|
||||
WDT0_NS as WDT0,
|
||||
WDT1_NS as WDT1,
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "nrf5340-app-s")]
|
||||
#[doc(no_inline)]
|
||||
pub use nrf5340_app_pac::{
|
||||
CACHEDATA_S as CACHEDATA,
|
||||
CACHEINFO_S as CACHEINFO,
|
||||
CACHE_S as CACHE,
|
||||
CLOCK_S as CLOCK,
|
||||
COMP_S as COMP,
|
||||
CRYPTOCELL_S as CRYPTOCELL,
|
||||
CTI_S as CTI,
|
||||
CTRLAP_S as CTRLAP,
|
||||
DCNF_S as DCNF,
|
||||
DPPIC_S as DPPIC,
|
||||
EGU0_S as EGU0,
|
||||
EGU1_S as EGU1,
|
||||
EGU2_S as EGU2,
|
||||
EGU3_S as EGU3,
|
||||
EGU4_S as EGU4,
|
||||
EGU5_S as EGU5,
|
||||
FICR_S as FICR,
|
||||
FPU_S as FPU,
|
||||
GPIOTE0_S as GPIOTE0,
|
||||
I2S0_S as I2S0,
|
||||
IPC_S as IPC,
|
||||
KMU_S as KMU,
|
||||
LPCOMP_S as LPCOMP,
|
||||
MUTEX_S as MUTEX,
|
||||
NFCT_S as NFCT,
|
||||
NVMC_S as NVMC,
|
||||
OSCILLATORS_S as OSCILLATORS,
|
||||
P0_S as P0,
|
||||
P1_S as P1,
|
||||
PDM0_S as PDM0,
|
||||
POWER_S as POWER,
|
||||
PWM0_S as PWM0,
|
||||
PWM1_S as PWM1,
|
||||
PWM2_S as PWM2,
|
||||
PWM3_S as PWM3,
|
||||
QDEC0_S as QDEC0,
|
||||
QDEC1_S as QDEC1,
|
||||
QSPI_S as QSPI,
|
||||
REGULATORS_S as REGULATORS,
|
||||
RESET_S as RESET,
|
||||
RTC0_S as RTC0,
|
||||
RTC1_S as RTC1,
|
||||
SAADC_S as SAADC,
|
||||
SPIM0_S as SPIM0,
|
||||
SPIM1_S as SPIM1,
|
||||
SPIM2_S as SPIM2,
|
||||
SPIM3_S as SPIM3,
|
||||
SPIM4_S as SPIM4,
|
||||
SPIS0_S as SPIS0,
|
||||
SPIS1_S as SPIS1,
|
||||
SPIS2_S as SPIS2,
|
||||
SPIS3_S as SPIS3,
|
||||
SPU_S as SPU,
|
||||
TAD_S as TAD,
|
||||
TIMER0_S as TIMER0,
|
||||
TIMER1_S as TIMER1,
|
||||
TIMER2_S as TIMER2,
|
||||
TWIM0_S as TWIM0,
|
||||
TWIM1_S as TWIM1,
|
||||
TWIM2_S as TWIM2,
|
||||
TWIM3_S as TWIM3,
|
||||
TWIS0_S as TWIS0,
|
||||
TWIS1_S as TWIS1,
|
||||
TWIS2_S as TWIS2,
|
||||
TWIS3_S as TWIS3,
|
||||
UARTE0_S as UARTE0,
|
||||
UARTE1_S as UARTE1,
|
||||
UARTE2_S as UARTE2,
|
||||
UARTE3_S as UARTE3,
|
||||
UICR_S as UICR,
|
||||
USBD_S as USBD,
|
||||
USBREGULATOR_S as USBREGULATOR,
|
||||
VMC_S as VMC,
|
||||
WDT0_S as WDT0,
|
||||
WDT1_S as WDT1,
|
||||
};
|
||||
/// Secure mode (S) peripherals
|
||||
pub mod s {
|
||||
#[cfg(feature = "nrf5340-app-s")]
|
||||
#[doc(no_inline)]
|
||||
pub use nrf5340_app_pac::{
|
||||
CACHEDATA_S as CACHEDATA,
|
||||
CACHEINFO_S as CACHEINFO,
|
||||
CACHE_S as CACHE,
|
||||
CLOCK_S as CLOCK,
|
||||
COMP_S as COMP,
|
||||
CRYPTOCELL_S as CRYPTOCELL,
|
||||
CTI_S as CTI,
|
||||
CTRLAP_S as CTRLAP,
|
||||
DCNF_S as DCNF,
|
||||
DPPIC_S as DPPIC,
|
||||
EGU0_S as EGU0,
|
||||
EGU1_S as EGU1,
|
||||
EGU2_S as EGU2,
|
||||
EGU3_S as EGU3,
|
||||
EGU4_S as EGU4,
|
||||
EGU5_S as EGU5,
|
||||
FICR_S as FICR,
|
||||
FPU_S as FPU,
|
||||
GPIOTE0_S as GPIOTE0,
|
||||
I2S0_S as I2S0,
|
||||
IPC_S as IPC,
|
||||
KMU_S as KMU,
|
||||
LPCOMP_S as LPCOMP,
|
||||
MUTEX_S as MUTEX,
|
||||
NFCT_S as NFCT,
|
||||
NVMC_S as NVMC,
|
||||
OSCILLATORS_S as OSCILLATORS,
|
||||
P0_S as P0,
|
||||
P1_S as P1,
|
||||
PDM0_S as PDM0,
|
||||
POWER_S as POWER,
|
||||
PWM0_S as PWM0,
|
||||
PWM1_S as PWM1,
|
||||
PWM2_S as PWM2,
|
||||
PWM3_S as PWM3,
|
||||
QDEC0_S as QDEC0,
|
||||
QDEC1_S as QDEC1,
|
||||
QSPI_S as QSPI,
|
||||
REGULATORS_S as REGULATORS,
|
||||
RESET_S as RESET,
|
||||
RTC0_S as RTC0,
|
||||
RTC1_S as RTC1,
|
||||
SAADC_S as SAADC,
|
||||
SPIM0_S as SPIM0,
|
||||
SPIM1_S as SPIM1,
|
||||
SPIM2_S as SPIM2,
|
||||
SPIM3_S as SPIM3,
|
||||
SPIM4_S as SPIM4,
|
||||
SPIS0_S as SPIS0,
|
||||
SPIS1_S as SPIS1,
|
||||
SPIS2_S as SPIS2,
|
||||
SPIS3_S as SPIS3,
|
||||
SPU_S as SPU,
|
||||
TAD_S as TAD,
|
||||
TIMER0_S as TIMER0,
|
||||
TIMER1_S as TIMER1,
|
||||
TIMER2_S as TIMER2,
|
||||
TWIM0_S as TWIM0,
|
||||
TWIM1_S as TWIM1,
|
||||
TWIM2_S as TWIM2,
|
||||
TWIM3_S as TWIM3,
|
||||
TWIS0_S as TWIS0,
|
||||
TWIS1_S as TWIS1,
|
||||
TWIS2_S as TWIS2,
|
||||
TWIS3_S as TWIS3,
|
||||
UARTE0_S as UARTE0,
|
||||
UARTE1_S as UARTE1,
|
||||
UARTE2_S as UARTE2,
|
||||
UARTE3_S as UARTE3,
|
||||
UICR_S as UICR,
|
||||
USBD_S as USBD,
|
||||
USBREGULATOR_S as USBREGULATOR,
|
||||
VMC_S as VMC,
|
||||
WDT0_S as WDT0,
|
||||
WDT1_S as WDT1,
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "_ns")]
|
||||
pub use ns::*;
|
||||
#[cfg(feature = "_s")]
|
||||
pub use s::*;
|
||||
}
|
||||
|
||||
/// The maximum buffer size that the EasyDMA can send/recv in one operation.
|
||||
|
@ -7,9 +7,12 @@ pub mod pac {
|
||||
|
||||
pub use nrf5340_net_pac::NVIC_PRIO_BITS;
|
||||
|
||||
#[cfg(feature="rt")]
|
||||
#[doc(no_inline)]
|
||||
pub use nrf5340_net_pac::interrupt;
|
||||
|
||||
#[doc(no_inline)]
|
||||
pub use nrf5340_net_pac::{
|
||||
interrupt,
|
||||
Interrupt,
|
||||
Peripherals,
|
||||
|
||||
|
@ -7,9 +7,12 @@ pub mod pac {
|
||||
|
||||
pub use nrf9160_pac::NVIC_PRIO_BITS;
|
||||
|
||||
#[cfg(feature="rt")]
|
||||
#[doc(no_inline)]
|
||||
pub use nrf9160_pac::interrupt;
|
||||
|
||||
#[doc(no_inline)]
|
||||
pub use nrf9160_pac::{
|
||||
interrupt,
|
||||
Interrupt,
|
||||
|
||||
cc_host_rgf_s as cc_host_rgf,
|
||||
@ -45,122 +48,131 @@ pub mod pac {
|
||||
wdt_ns as wdt,
|
||||
};
|
||||
|
||||
#[cfg(feature = "nrf9160-ns")]
|
||||
#[doc(no_inline)]
|
||||
pub use nrf9160_pac::{
|
||||
CLOCK_NS as CLOCK,
|
||||
DPPIC_NS as DPPIC,
|
||||
EGU0_NS as EGU0,
|
||||
EGU1_NS as EGU1,
|
||||
EGU2_NS as EGU2,
|
||||
EGU3_NS as EGU3,
|
||||
EGU4_NS as EGU4,
|
||||
EGU5_NS as EGU5,
|
||||
FPU_NS as FPU,
|
||||
GPIOTE1_NS as GPIOTE1,
|
||||
I2S_NS as I2S,
|
||||
IPC_NS as IPC,
|
||||
KMU_NS as KMU,
|
||||
NVMC_NS as NVMC,
|
||||
P0_NS as P0,
|
||||
PDM_NS as PDM,
|
||||
POWER_NS as POWER,
|
||||
PWM0_NS as PWM0,
|
||||
PWM1_NS as PWM1,
|
||||
PWM2_NS as PWM2,
|
||||
PWM3_NS as PWM3,
|
||||
REGULATORS_NS as REGULATORS,
|
||||
RTC0_NS as RTC0,
|
||||
RTC1_NS as RTC1,
|
||||
SAADC_NS as SAADC,
|
||||
SPIM0_NS as SPIM0,
|
||||
SPIM1_NS as SPIM1,
|
||||
SPIM2_NS as SPIM2,
|
||||
SPIM3_NS as SPIM3,
|
||||
SPIS0_NS as SPIS0,
|
||||
SPIS1_NS as SPIS1,
|
||||
SPIS2_NS as SPIS2,
|
||||
SPIS3_NS as SPIS3,
|
||||
TIMER0_NS as TIMER0,
|
||||
TIMER1_NS as TIMER1,
|
||||
TIMER2_NS as TIMER2,
|
||||
TWIM0_NS as TWIM0,
|
||||
TWIM1_NS as TWIM1,
|
||||
TWIM2_NS as TWIM2,
|
||||
TWIM3_NS as TWIM3,
|
||||
TWIS0_NS as TWIS0,
|
||||
TWIS1_NS as TWIS1,
|
||||
TWIS2_NS as TWIS2,
|
||||
TWIS3_NS as TWIS3,
|
||||
UARTE0_NS as UARTE0,
|
||||
UARTE1_NS as UARTE1,
|
||||
UARTE2_NS as UARTE2,
|
||||
UARTE3_NS as UARTE3,
|
||||
VMC_NS as VMC,
|
||||
WDT_NS as WDT,
|
||||
};
|
||||
/// Non-Secure mode (NS) peripherals
|
||||
pub mod ns {
|
||||
#[doc(no_inline)]
|
||||
pub use nrf9160_pac::{
|
||||
CLOCK_NS as CLOCK,
|
||||
DPPIC_NS as DPPIC,
|
||||
EGU0_NS as EGU0,
|
||||
EGU1_NS as EGU1,
|
||||
EGU2_NS as EGU2,
|
||||
EGU3_NS as EGU3,
|
||||
EGU4_NS as EGU4,
|
||||
EGU5_NS as EGU5,
|
||||
FPU_NS as FPU,
|
||||
GPIOTE1_NS as GPIOTE1,
|
||||
I2S_NS as I2S,
|
||||
IPC_NS as IPC,
|
||||
KMU_NS as KMU,
|
||||
NVMC_NS as NVMC,
|
||||
P0_NS as P0,
|
||||
PDM_NS as PDM,
|
||||
POWER_NS as POWER,
|
||||
PWM0_NS as PWM0,
|
||||
PWM1_NS as PWM1,
|
||||
PWM2_NS as PWM2,
|
||||
PWM3_NS as PWM3,
|
||||
REGULATORS_NS as REGULATORS,
|
||||
RTC0_NS as RTC0,
|
||||
RTC1_NS as RTC1,
|
||||
SAADC_NS as SAADC,
|
||||
SPIM0_NS as SPIM0,
|
||||
SPIM1_NS as SPIM1,
|
||||
SPIM2_NS as SPIM2,
|
||||
SPIM3_NS as SPIM3,
|
||||
SPIS0_NS as SPIS0,
|
||||
SPIS1_NS as SPIS1,
|
||||
SPIS2_NS as SPIS2,
|
||||
SPIS3_NS as SPIS3,
|
||||
TIMER0_NS as TIMER0,
|
||||
TIMER1_NS as TIMER1,
|
||||
TIMER2_NS as TIMER2,
|
||||
TWIM0_NS as TWIM0,
|
||||
TWIM1_NS as TWIM1,
|
||||
TWIM2_NS as TWIM2,
|
||||
TWIM3_NS as TWIM3,
|
||||
TWIS0_NS as TWIS0,
|
||||
TWIS1_NS as TWIS1,
|
||||
TWIS2_NS as TWIS2,
|
||||
TWIS3_NS as TWIS3,
|
||||
UARTE0_NS as UARTE0,
|
||||
UARTE1_NS as UARTE1,
|
||||
UARTE2_NS as UARTE2,
|
||||
UARTE3_NS as UARTE3,
|
||||
VMC_NS as VMC,
|
||||
WDT_NS as WDT,
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "nrf9160-s")]
|
||||
#[doc(no_inline)]
|
||||
pub use nrf9160_pac::{
|
||||
CC_HOST_RGF_S as CC_HOST_RGF,
|
||||
CLOCK_S as CLOCK,
|
||||
CRYPTOCELL_S as CRYPTOCELL,
|
||||
CTRL_AP_PERI_S as CTRL_AP_PERI,
|
||||
DPPIC_S as DPPIC,
|
||||
EGU0_S as EGU0,
|
||||
EGU1_S as EGU1,
|
||||
EGU2_S as EGU2,
|
||||
EGU3_S as EGU3,
|
||||
EGU4_S as EGU4,
|
||||
EGU5_S as EGU5,
|
||||
FICR_S as FICR,
|
||||
FPU_S as FPU,
|
||||
GPIOTE0_S as GPIOTE0,
|
||||
I2S_S as I2S,
|
||||
IPC_S as IPC,
|
||||
KMU_S as KMU,
|
||||
NVMC_S as NVMC,
|
||||
P0_S as P0,
|
||||
PDM_S as PDM,
|
||||
POWER_S as POWER,
|
||||
PWM0_S as PWM0,
|
||||
PWM1_S as PWM1,
|
||||
PWM2_S as PWM2,
|
||||
PWM3_S as PWM3,
|
||||
REGULATORS_S as REGULATORS,
|
||||
RTC0_S as RTC0,
|
||||
RTC1_S as RTC1,
|
||||
SAADC_S as SAADC,
|
||||
SPIM0_S as SPIM0,
|
||||
SPIM1_S as SPIM1,
|
||||
SPIM2_S as SPIM2,
|
||||
SPIM3_S as SPIM3,
|
||||
SPIS0_S as SPIS0,
|
||||
SPIS1_S as SPIS1,
|
||||
SPIS2_S as SPIS2,
|
||||
SPIS3_S as SPIS3,
|
||||
SPU_S as SPU,
|
||||
TAD_S as TAD,
|
||||
TIMER0_S as TIMER0,
|
||||
TIMER1_S as TIMER1,
|
||||
TIMER2_S as TIMER2,
|
||||
TWIM0_S as TWIM0,
|
||||
TWIM1_S as TWIM1,
|
||||
TWIM2_S as TWIM2,
|
||||
TWIM3_S as TWIM3,
|
||||
TWIS0_S as TWIS0,
|
||||
TWIS1_S as TWIS1,
|
||||
TWIS2_S as TWIS2,
|
||||
TWIS3_S as TWIS3,
|
||||
UARTE0_S as UARTE0,
|
||||
UARTE1_S as UARTE1,
|
||||
UARTE2_S as UARTE2,
|
||||
UARTE3_S as UARTE3,
|
||||
UICR_S as UICR,
|
||||
VMC_S as VMC,
|
||||
WDT_S as WDT,
|
||||
};
|
||||
/// Secure mode (S) peripherals
|
||||
pub mod s {
|
||||
#[doc(no_inline)]
|
||||
pub use nrf9160_pac::{
|
||||
CC_HOST_RGF_S as CC_HOST_RGF,
|
||||
CLOCK_S as CLOCK,
|
||||
CRYPTOCELL_S as CRYPTOCELL,
|
||||
CTRL_AP_PERI_S as CTRL_AP_PERI,
|
||||
DPPIC_S as DPPIC,
|
||||
EGU0_S as EGU0,
|
||||
EGU1_S as EGU1,
|
||||
EGU2_S as EGU2,
|
||||
EGU3_S as EGU3,
|
||||
EGU4_S as EGU4,
|
||||
EGU5_S as EGU5,
|
||||
FICR_S as FICR,
|
||||
FPU_S as FPU,
|
||||
GPIOTE0_S as GPIOTE0,
|
||||
I2S_S as I2S,
|
||||
IPC_S as IPC,
|
||||
KMU_S as KMU,
|
||||
NVMC_S as NVMC,
|
||||
P0_S as P0,
|
||||
PDM_S as PDM,
|
||||
POWER_S as POWER,
|
||||
PWM0_S as PWM0,
|
||||
PWM1_S as PWM1,
|
||||
PWM2_S as PWM2,
|
||||
PWM3_S as PWM3,
|
||||
REGULATORS_S as REGULATORS,
|
||||
RTC0_S as RTC0,
|
||||
RTC1_S as RTC1,
|
||||
SAADC_S as SAADC,
|
||||
SPIM0_S as SPIM0,
|
||||
SPIM1_S as SPIM1,
|
||||
SPIM2_S as SPIM2,
|
||||
SPIM3_S as SPIM3,
|
||||
SPIS0_S as SPIS0,
|
||||
SPIS1_S as SPIS1,
|
||||
SPIS2_S as SPIS2,
|
||||
SPIS3_S as SPIS3,
|
||||
SPU_S as SPU,
|
||||
TAD_S as TAD,
|
||||
TIMER0_S as TIMER0,
|
||||
TIMER1_S as TIMER1,
|
||||
TIMER2_S as TIMER2,
|
||||
TWIM0_S as TWIM0,
|
||||
TWIM1_S as TWIM1,
|
||||
TWIM2_S as TWIM2,
|
||||
TWIM3_S as TWIM3,
|
||||
TWIS0_S as TWIS0,
|
||||
TWIS1_S as TWIS1,
|
||||
TWIS2_S as TWIS2,
|
||||
TWIS3_S as TWIS3,
|
||||
UARTE0_S as UARTE0,
|
||||
UARTE1_S as UARTE1,
|
||||
UARTE2_S as UARTE2,
|
||||
UARTE3_S as UARTE3,
|
||||
UICR_S as UICR,
|
||||
VMC_S as VMC,
|
||||
WDT_S as WDT,
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "_ns")]
|
||||
pub use ns::*;
|
||||
#[cfg(feature = "_s")]
|
||||
pub use s::*;
|
||||
}
|
||||
|
||||
/// The maximum buffer size that the EasyDMA can send/recv in one operation.
|
||||
|
@ -1,5 +1,5 @@
|
||||
#![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")]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
@ -102,6 +102,7 @@ mod chip;
|
||||
#[macro_export]
|
||||
macro_rules! bind_interrupts {
|
||||
($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
|
||||
#[derive(Copy, Clone)]
|
||||
$vis struct $name;
|
||||
|
||||
$(
|
||||
|
@ -68,30 +68,14 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
||||
let r = T::regs();
|
||||
let s = T::state();
|
||||
|
||||
#[cfg(feature = "nrf52832")]
|
||||
// NRF32 Anomaly 109 workaround... NRF52832
|
||||
if r.intenset.read().started().is_enabled() && r.events_started.read().bits() != 0 {
|
||||
// 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...
|
||||
#[cfg(feature = "_nrf52832_anomaly_109")]
|
||||
if r.events_started.read().bits() != 0 {
|
||||
s.waker.wake();
|
||||
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 {
|
||||
s.end_waker.wake();
|
||||
s.waker.wake();
|
||||
r.intenclr.write(|w| w.end().clear());
|
||||
}
|
||||
}
|
||||
@ -192,7 +176,7 @@ impl<'d, T: Instance> Spim<'d, T> {
|
||||
let mut spim = Self { _p: spim };
|
||||
|
||||
// Apply runtime peripheral configuration
|
||||
Self::set_config(&mut spim, &config);
|
||||
Self::set_config(&mut spim, &config).unwrap();
|
||||
|
||||
// Disable all events interrupts
|
||||
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.maxcnt.write(|w| unsafe { w.maxcnt().bits(rx_len as _) });
|
||||
|
||||
// ANOMALY 109 workaround
|
||||
#[cfg(feature = "nrf52832")]
|
||||
#[cfg(feature = "_nrf52832_anomaly_109")]
|
||||
{
|
||||
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> {
|
||||
self.prepare(rx, tx)?;
|
||||
|
||||
#[cfg(feature = "_nrf52832_anomaly_109")]
|
||||
while let Poll::Pending = self.nrf52832_dma_workaround_status() {}
|
||||
|
||||
// Wait for 'end' event.
|
||||
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> {
|
||||
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.
|
||||
poll_fn(|cx| {
|
||||
T::state().end_waker.register(cx.waker());
|
||||
T::state().waker.register(cx.waker());
|
||||
if T::regs().events_end.read().bits() != 0 {
|
||||
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> {
|
||||
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> {
|
||||
@ -395,7 +417,7 @@ impl<'d, T: Instance> Drop for Spim<'d, T> {
|
||||
}
|
||||
|
||||
pub(crate) mod sealed {
|
||||
#[cfg(feature = "nrf52832")]
|
||||
#[cfg(feature = "_nrf52832_anomaly_109")]
|
||||
use core::sync::atomic::AtomicU8;
|
||||
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
@ -403,20 +425,20 @@ pub(crate) mod sealed {
|
||||
use super::*;
|
||||
|
||||
pub struct State {
|
||||
pub end_waker: AtomicWaker,
|
||||
#[cfg(feature = "nrf52832")]
|
||||
pub waker: AtomicWaker,
|
||||
#[cfg(feature = "_nrf52832_anomaly_109")]
|
||||
pub rx: AtomicU8,
|
||||
#[cfg(feature = "nrf52832")]
|
||||
#[cfg(feature = "_nrf52832_anomaly_109")]
|
||||
pub tx: AtomicU8,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
end_waker: AtomicWaker::new(),
|
||||
#[cfg(feature = "nrf52832")]
|
||||
waker: AtomicWaker::new(),
|
||||
#[cfg(feature = "_nrf52832_anomaly_109")]
|
||||
rx: AtomicU8::new(0),
|
||||
#[cfg(feature = "nrf52832")]
|
||||
#[cfg(feature = "_nrf52832_anomaly_109")]
|
||||
tx: AtomicU8::new(0),
|
||||
}
|
||||
}
|
||||
@ -544,7 +566,8 @@ mod eha {
|
||||
|
||||
impl<'d, T: Instance> SetConfig for Spim<'d, T> {
|
||||
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();
|
||||
// Configure mode.
|
||||
let mode = config.mode;
|
||||
@ -582,5 +605,7 @@ impl<'d, T: Instance> SetConfig for Spim<'d, T> {
|
||||
// Set over-read character
|
||||
let orc = config.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 };
|
||||
|
||||
// Apply runtime peripheral configuration
|
||||
Self::set_config(&mut spis, &config);
|
||||
Self::set_config(&mut spis, &config).unwrap();
|
||||
|
||||
// Disable all events interrupts.
|
||||
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> {
|
||||
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();
|
||||
// Configure 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.
|
||||
let auto_acquire = config.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 };
|
||||
|
||||
// Apply runtime peripheral configuration
|
||||
Self::set_config(&mut twim, &config);
|
||||
Self::set_config(&mut twim, &config).unwrap();
|
||||
|
||||
// Disable all events interrupts
|
||||
r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) });
|
||||
@ -890,9 +890,12 @@ mod eha {
|
||||
|
||||
impl<'d, T: Instance> SetConfig for Twim<'d, T> {
|
||||
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();
|
||||
r.frequency
|
||||
.write(|w| unsafe { w.frequency().bits(config.frequency as u32) });
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ unstable-traits = ["embedded-hal-1", "embedded-hal-nb"]
|
||||
|
||||
[dependencies]
|
||||
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.5", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] }
|
||||
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-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||
@ -75,8 +75,8 @@ cortex-m = "0.7.6"
|
||||
critical-section = "1.1"
|
||||
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
|
||||
chrono = { version = "0.4", default-features = false, optional = true }
|
||||
embedded-io = { version = "0.5.0" }
|
||||
embedded-io-async = { version = "0.5.0", optional = true }
|
||||
embedded-io = { version = "0.6.0" }
|
||||
embedded-io-async = { version = "0.6.0", optional = true }
|
||||
embedded-storage = { version = "0.3" }
|
||||
embedded-storage-async = { version = "0.4.0", optional = true }
|
||||
rand_core = "0.6.4"
|
||||
@ -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-nb = { version = "=1.0.0-rc.1", optional = true}
|
||||
|
||||
paste = "1.0"
|
||||
pio-proc = {version= "0.2" }
|
||||
pio = {version= "0.2.1" }
|
||||
rp2040-boot2 = "0.3"
|
||||
|
83
embassy-rp/src/bootsel.rs
Normal file
83
embassy-rp/src/bootsel.rs
Normal file
@ -0,0 +1,83 @@
|
||||
//! Boot Select button
|
||||
//!
|
||||
//! The RP2040 rom supports a BOOTSEL button that is used to enter the USB bootloader
|
||||
//! if held during reset. To avoid wasting GPIO pins, the button is multiplexed onto
|
||||
//! the CS pin of the QSPI flash, but that makes it somewhat expensive and complicated
|
||||
//! to utilize outside of the rom's bootloader.
|
||||
//!
|
||||
//! This module provides functionality to poll BOOTSEL from an embassy application.
|
||||
|
||||
use crate::flash::in_ram;
|
||||
|
||||
impl crate::peripherals::BOOTSEL {
|
||||
/// Polls the BOOTSEL button. Returns true if the button is pressed.
|
||||
///
|
||||
/// Polling isn't cheap, as this function waits for core 1 to finish it's current
|
||||
/// task and for any DMAs from flash to complete
|
||||
pub fn is_pressed(&mut self) -> bool {
|
||||
let mut cs_status = Default::default();
|
||||
|
||||
unsafe { in_ram(|| cs_status = ram_helpers::read_cs_status()) }.expect("Must be called from Core 0");
|
||||
|
||||
// bootsel is active low, so invert
|
||||
!cs_status.infrompad()
|
||||
}
|
||||
}
|
||||
|
||||
mod ram_helpers {
|
||||
use rp_pac::io::regs::GpioStatus;
|
||||
|
||||
/// Temporally reconfigures the CS gpio and returns the GpioStatus.
|
||||
|
||||
/// This function runs from RAM so it can disable flash XIP.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure flash is idle and will remain idle.
|
||||
/// This function must live in ram. It uses inline asm to avoid any
|
||||
/// potential calls to ABI functions that might be in flash.
|
||||
#[inline(never)]
|
||||
#[link_section = ".data.ram_func"]
|
||||
#[cfg(target_arch = "arm")]
|
||||
pub unsafe fn read_cs_status() -> GpioStatus {
|
||||
let result: u32;
|
||||
|
||||
// Magic value, used as both OEOVER::DISABLE and delay loop counter
|
||||
let magic = 0x2000;
|
||||
|
||||
core::arch::asm!(
|
||||
".equiv GPIO_STATUS, 0x0",
|
||||
".equiv GPIO_CTRL, 0x4",
|
||||
|
||||
"ldr {orig_ctrl}, [{cs_gpio}, $GPIO_CTRL]",
|
||||
|
||||
// The BOOTSEL pulls the flash's CS line low though a 1K resistor.
|
||||
// this is weak enough to avoid disrupting normal operation.
|
||||
// But, if we disable CS's output drive and allow it to float...
|
||||
"str {val}, [{cs_gpio}, $GPIO_CTRL]",
|
||||
|
||||
// ...then wait for the state to settle...
|
||||
"1:", // ~4000 cycle delay loop
|
||||
"subs {val}, #8",
|
||||
"bne 1b",
|
||||
|
||||
// ...we can read the current state of bootsel
|
||||
"ldr {val}, [{cs_gpio}, $GPIO_STATUS]",
|
||||
|
||||
// Finally, restore CS to normal operation so XIP can continue
|
||||
"str {orig_ctrl}, [{cs_gpio}, $GPIO_CTRL]",
|
||||
|
||||
cs_gpio = in(reg) rp_pac::IO_QSPI.gpio(1).as_ptr(),
|
||||
orig_ctrl = out(reg) _,
|
||||
val = inout(reg) magic => result,
|
||||
options(nostack),
|
||||
);
|
||||
|
||||
core::mem::transmute(result)
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "arm"))]
|
||||
pub unsafe fn read_cs_status() -> GpioStatus {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
@ -131,7 +131,7 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI
|
||||
|
||||
let len = to - from;
|
||||
|
||||
unsafe { self.in_ram(|| ram_helpers::flash_range_erase(from, len))? };
|
||||
unsafe { in_ram(|| ram_helpers::flash_range_erase(from, len))? };
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -156,7 +156,7 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI
|
||||
|
||||
let unaligned_offset = offset as usize - start;
|
||||
|
||||
unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf))? }
|
||||
unsafe { in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf))? }
|
||||
}
|
||||
|
||||
let remaining_len = bytes.len() - start_padding;
|
||||
@ -174,12 +174,12 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI
|
||||
if bytes.as_ptr() as usize >= 0x2000_0000 {
|
||||
let aligned_data = &bytes[start_padding..end_padding];
|
||||
|
||||
unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, aligned_data))? }
|
||||
unsafe { in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, aligned_data))? }
|
||||
} else {
|
||||
for chunk in bytes[start_padding..end_padding].chunks_exact(PAGE_SIZE) {
|
||||
let mut ram_buf = [0xFF_u8; PAGE_SIZE];
|
||||
ram_buf.copy_from_slice(chunk);
|
||||
unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, &ram_buf))? }
|
||||
unsafe { in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, &ram_buf))? }
|
||||
aligned_offset += PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
@ -194,47 +194,15 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI
|
||||
|
||||
let unaligned_offset = end_offset - (PAGE_SIZE - rem_offset);
|
||||
|
||||
unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf))? }
|
||||
unsafe { in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf))? }
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Make sure to uphold the contract points with rp2040-flash.
|
||||
/// - interrupts must be disabled
|
||||
/// - DMA must not access flash memory
|
||||
unsafe fn in_ram(&mut self, operation: impl FnOnce()) -> Result<(), Error> {
|
||||
// Make sure we're running on CORE0
|
||||
let core_id: u32 = pac::SIO.cpuid().read();
|
||||
if core_id != 0 {
|
||||
return Err(Error::InvalidCore);
|
||||
}
|
||||
|
||||
// Make sure CORE1 is paused during the entire duration of the RAM function
|
||||
crate::multicore::pause_core1();
|
||||
|
||||
critical_section::with(|_| {
|
||||
// Wait for all DMA channels in flash to finish before ram operation
|
||||
const SRAM_LOWER: u32 = 0x2000_0000;
|
||||
for n in 0..crate::dma::CHANNEL_COUNT {
|
||||
let ch = crate::pac::DMA.ch(n);
|
||||
while ch.read_addr().read() < SRAM_LOWER && ch.ctrl_trig().read().busy() {}
|
||||
}
|
||||
// Wait for completion of any background reads
|
||||
while pac::XIP_CTRL.stream_ctr().read().0 > 0 {}
|
||||
|
||||
// Run our flash operation in RAM
|
||||
operation();
|
||||
});
|
||||
|
||||
// Resume CORE1 execution
|
||||
crate::multicore::resume_core1();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Read SPI flash unique ID
|
||||
pub fn blocking_unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> {
|
||||
unsafe { self.in_ram(|| ram_helpers::flash_unique_id(uid))? };
|
||||
unsafe { in_ram(|| ram_helpers::flash_unique_id(uid))? };
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -242,7 +210,7 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI
|
||||
pub fn blocking_jedec_id(&mut self) -> Result<u32, Error> {
|
||||
let mut jedec = None;
|
||||
unsafe {
|
||||
self.in_ram(|| {
|
||||
in_ram(|| {
|
||||
jedec.replace(ram_helpers::flash_jedec_id());
|
||||
})?;
|
||||
};
|
||||
@ -871,6 +839,38 @@ mod ram_helpers {
|
||||
}
|
||||
}
|
||||
|
||||
/// Make sure to uphold the contract points with rp2040-flash.
|
||||
/// - interrupts must be disabled
|
||||
/// - DMA must not access flash memory
|
||||
pub(crate) unsafe fn in_ram(operation: impl FnOnce()) -> Result<(), Error> {
|
||||
// Make sure we're running on CORE0
|
||||
let core_id: u32 = pac::SIO.cpuid().read();
|
||||
if core_id != 0 {
|
||||
return Err(Error::InvalidCore);
|
||||
}
|
||||
|
||||
// Make sure CORE1 is paused during the entire duration of the RAM function
|
||||
crate::multicore::pause_core1();
|
||||
|
||||
critical_section::with(|_| {
|
||||
// Wait for all DMA channels in flash to finish before ram operation
|
||||
const SRAM_LOWER: u32 = 0x2000_0000;
|
||||
for n in 0..crate::dma::CHANNEL_COUNT {
|
||||
let ch = crate::pac::DMA.ch(n);
|
||||
while ch.read_addr().read() < SRAM_LOWER && ch.ctrl_trig().read().busy() {}
|
||||
}
|
||||
// Wait for completion of any background reads
|
||||
while pac::XIP_CTRL.stream_ctr().read().0 > 0 {}
|
||||
|
||||
// Run our flash operation in RAM
|
||||
operation();
|
||||
});
|
||||
|
||||
// Resume CORE1 execution
|
||||
crate::multicore::resume_core1();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
mod sealed {
|
||||
pub trait Instance {}
|
||||
pub trait Mode {}
|
||||
|
@ -97,6 +97,12 @@ impl<'d, T: Pin> Input<'d, T> {
|
||||
Self { pin }
|
||||
}
|
||||
|
||||
/// Set the pin's Schmitt trigger.
|
||||
#[inline]
|
||||
pub fn set_schmitt(&mut self, enable: bool) {
|
||||
self.pin.set_schmitt(enable)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_high(&self) -> bool {
|
||||
self.pin.is_high()
|
||||
@ -216,7 +222,6 @@ fn IO_IRQ_QSPI() {
|
||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||
struct InputFuture<'a, T: Pin> {
|
||||
pin: PeripheralRef<'a, T>,
|
||||
level: InterruptTrigger,
|
||||
}
|
||||
|
||||
impl<'d, T: Pin> InputFuture<'d, T> {
|
||||
@ -243,7 +248,6 @@ impl<'d, T: Pin> InputFuture<'d, T> {
|
||||
.inte((pin.pin() / 8) as usize)
|
||||
.write_set(|w| match level {
|
||||
InterruptTrigger::LevelHigh => {
|
||||
trace!("InputFuture::new enable LevelHigh for pin {}", pin.pin());
|
||||
w.set_level_high(pin_group, true);
|
||||
}
|
||||
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_low(pin_group)
|
||||
{
|
||||
trace!(
|
||||
"{:?} for pin {} was cleared, return Poll::Ready",
|
||||
self.level,
|
||||
self.pin.pin()
|
||||
);
|
||||
return Poll::Ready(());
|
||||
}
|
||||
trace!("InputFuture::poll return Poll::Pending");
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
@ -326,6 +324,18 @@ impl<'d, T: Pin> Output<'d, T> {
|
||||
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.
|
||||
#[inline]
|
||||
pub fn set_high(&mut self) {
|
||||
@ -386,6 +396,18 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
|
||||
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.
|
||||
#[inline]
|
||||
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.
|
||||
///
|
||||
/// The pull setting is left unchanged.
|
||||
|
@ -6,13 +6,12 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use pac::i2c;
|
||||
|
||||
use crate::gpio::sealed::Pin;
|
||||
use crate::gpio::AnyPin;
|
||||
use crate::interrupt::typelevel::{Binding, Interrupt};
|
||||
use crate::{interrupt, pac, peripherals, Peripheral};
|
||||
|
||||
/// I2C error abort reason
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum AbortReason {
|
||||
/// A bus operation was not acknowledged, e.g. due to the addressed device
|
||||
@ -27,7 +26,7 @@ pub enum AbortReason {
|
||||
}
|
||||
|
||||
/// I2C error
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum Error {
|
||||
/// I2C abort with error
|
||||
@ -295,13 +294,24 @@ impl<'d, T: Instance> I2c<'d, T, Async> {
|
||||
|
||||
pub async fn read_async(&mut self, addr: u16, buffer: &mut [u8]) -> Result<(), Error> {
|
||||
Self::setup(addr)?;
|
||||
self.read_async_internal(buffer, false, true).await
|
||||
self.read_async_internal(buffer, true, true).await
|
||||
}
|
||||
|
||||
pub async fn write_async(&mut self, addr: u16, bytes: impl IntoIterator<Item = u8>) -> Result<(), Error> {
|
||||
Self::setup(addr)?;
|
||||
self.write_async_internal(bytes, true).await
|
||||
}
|
||||
|
||||
pub async fn write_read_async(
|
||||
&mut self,
|
||||
addr: u16,
|
||||
bytes: impl IntoIterator<Item = u8>,
|
||||
buffer: &mut [u8],
|
||||
) -> Result<(), Error> {
|
||||
Self::setup(addr)?;
|
||||
self.write_async_internal(bytes, false).await?;
|
||||
self.read_async_internal(buffer, true, true).await
|
||||
}
|
||||
}
|
||||
|
||||
pub struct InterruptHandler<T: Instance> {
|
||||
@ -318,6 +328,22 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_up_i2c_pin<'d, P, T>(pin: &P)
|
||||
where
|
||||
P: core::ops::Deref<Target = T>,
|
||||
T: crate::gpio::Pin,
|
||||
{
|
||||
pin.gpio().ctrl().write(|w| w.set_funcsel(3));
|
||||
pin.pad_ctrl().write(|w| {
|
||||
w.set_schmitt(true);
|
||||
w.set_slewfast(false);
|
||||
w.set_ie(true);
|
||||
w.set_od(false);
|
||||
w.set_pue(true);
|
||||
w.set_pde(false);
|
||||
});
|
||||
}
|
||||
|
||||
impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
|
||||
fn new_inner(
|
||||
_peri: impl Peripheral<P = T> + 'd,
|
||||
@ -355,23 +381,8 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
|
||||
p.ic_rx_tl().write(|w| w.set_rx_tl(0));
|
||||
|
||||
// Configure SCL & SDA pins
|
||||
scl.gpio().ctrl().write(|w| w.set_funcsel(3));
|
||||
sda.gpio().ctrl().write(|w| w.set_funcsel(3));
|
||||
|
||||
scl.pad_ctrl().write(|w| {
|
||||
w.set_schmitt(true);
|
||||
w.set_ie(true);
|
||||
w.set_od(false);
|
||||
w.set_pue(true);
|
||||
w.set_pde(false);
|
||||
});
|
||||
sda.pad_ctrl().write(|w| {
|
||||
w.set_schmitt(true);
|
||||
w.set_ie(true);
|
||||
w.set_od(false);
|
||||
w.set_pue(true);
|
||||
w.set_pde(false);
|
||||
});
|
||||
set_up_i2c_pin(&scl);
|
||||
set_up_i2c_pin(&sda);
|
||||
|
||||
// Configure baudrate
|
||||
|
||||
@ -713,7 +724,7 @@ mod nightly {
|
||||
|
||||
Self::setup(addr)?;
|
||||
self.write_async_internal(write.iter().cloned(), false).await?;
|
||||
self.read_async_internal(read, false, true).await
|
||||
self.read_async_internal(read, true, true).await
|
||||
}
|
||||
|
||||
async fn transaction(&mut self, address: A, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> {
|
||||
|
@ -5,12 +5,14 @@ use core::task::Poll;
|
||||
use embassy_hal_internal::into_ref;
|
||||
use pac::i2c;
|
||||
|
||||
use crate::i2c::{i2c_reserved_addr, AbortReason, Instance, InterruptHandler, SclPin, SdaPin, FIFO_SIZE};
|
||||
use crate::i2c::{
|
||||
i2c_reserved_addr, set_up_i2c_pin, AbortReason, Instance, InterruptHandler, SclPin, SdaPin, FIFO_SIZE,
|
||||
};
|
||||
use crate::interrupt::typelevel::{Binding, Interrupt};
|
||||
use crate::{pac, Peripheral};
|
||||
|
||||
/// I2C error
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
#[non_exhaustive]
|
||||
pub enum Error {
|
||||
@ -100,23 +102,8 @@ impl<'d, T: Instance> I2cSlave<'d, T> {
|
||||
p.ic_rx_tl().write(|w| w.set_rx_tl(0));
|
||||
|
||||
// Configure SCL & SDA pins
|
||||
scl.gpio().ctrl().write(|w| w.set_funcsel(3));
|
||||
sda.gpio().ctrl().write(|w| w.set_funcsel(3));
|
||||
|
||||
scl.pad_ctrl().write(|w| {
|
||||
w.set_schmitt(true);
|
||||
w.set_ie(true);
|
||||
w.set_od(false);
|
||||
w.set_pue(true);
|
||||
w.set_pde(false);
|
||||
});
|
||||
sda.pad_ctrl().write(|w| {
|
||||
w.set_schmitt(true);
|
||||
w.set_ie(true);
|
||||
w.set_od(false);
|
||||
w.set_pue(true);
|
||||
w.set_pde(false);
|
||||
});
|
||||
set_up_i2c_pin(&scl);
|
||||
set_up_i2c_pin(&sda);
|
||||
|
||||
// Clear interrupts
|
||||
p.ic_clr_intr().read();
|
||||
|
@ -1,5 +1,5 @@
|
||||
#![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.
|
||||
pub(crate) mod fmt;
|
||||
@ -10,6 +10,7 @@ mod critical_section_impl;
|
||||
mod intrinsics;
|
||||
|
||||
pub mod adc;
|
||||
pub mod bootsel;
|
||||
pub mod clocks;
|
||||
pub mod dma;
|
||||
pub mod flash;
|
||||
@ -90,7 +91,8 @@ embassy_hal_internal::interrupt_mod!(
|
||||
#[macro_export]
|
||||
macro_rules! bind_interrupts {
|
||||
($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => {
|
||||
$vis struct $name;
|
||||
#[derive(Copy, Clone)]
|
||||
$vis struct $name;
|
||||
|
||||
$(
|
||||
#[allow(non_snake_case)]
|
||||
@ -192,6 +194,7 @@ embassy_hal_internal::peripherals! {
|
||||
PIO1,
|
||||
|
||||
WATCHDOG,
|
||||
BOOTSEL,
|
||||
}
|
||||
|
||||
macro_rules! select_bootloader {
|
||||
|
@ -1079,18 +1079,43 @@ impl_pio!(PIO1, 1, PIO1, PIO1_0, PIO1_IRQ_0);
|
||||
pub trait PioPin: sealed::PioPin + gpio::Pin {}
|
||||
|
||||
macro_rules! impl_pio_pin {
|
||||
($( $num:tt )*) => {
|
||||
($( $pin:ident, )*) => {
|
||||
$(
|
||||
paste::paste!{
|
||||
impl sealed::PioPin for peripherals::[< PIN_ $num >] {}
|
||||
impl PioPin for peripherals::[< PIN_ $num >] {}
|
||||
}
|
||||
impl sealed::PioPin for peripherals::$pin {}
|
||||
impl PioPin for peripherals::$pin {}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
impl_pio_pin! {
|
||||
0 1 2 3 4 5 6 7 8 9
|
||||
10 11 12 13 14 15 16 17 18 19
|
||||
20 21 22 23 24 25 26 27 28 29
|
||||
PIN_0,
|
||||
PIN_1,
|
||||
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> {
|
||||
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 (presc, postdiv) = calc_prescs(config.frequency);
|
||||
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_scr(postdiv);
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use core::task::Poll;
|
||||
use atomic_polyfill::{AtomicU8, Ordering};
|
||||
use embassy_hal_internal::atomic_ring_buffer::RingBuffer;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use embassy_time::{Duration, Timer};
|
||||
use embassy_time::Timer;
|
||||
|
||||
use super::*;
|
||||
use crate::clocks::clk_peri_freq;
|
||||
@ -435,7 +435,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
|
||||
Self::flush().await.unwrap();
|
||||
while self.busy() {}
|
||||
regs.uartlcr_h().write_set(|w| w.set_brk(true));
|
||||
Timer::after(Duration::from_micros(wait_usecs)).await;
|
||||
Timer::after_micros(wait_usecs).await;
|
||||
regs.uartlcr_h().write_clear(|w| w.set_brk(true));
|
||||
}
|
||||
}
|
||||
@ -490,8 +490,6 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterr
|
||||
w.set_oeic(ris.oeris());
|
||||
});
|
||||
|
||||
trace!("on_interrupt ris={:#X}", ris.0);
|
||||
|
||||
// Errors
|
||||
if ris.feris() {
|
||||
warn!("Framing error");
|
||||
|
@ -6,7 +6,7 @@ use atomic_polyfill::{AtomicU16, Ordering};
|
||||
use embassy_futures::select::{select, Either};
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use embassy_time::{Duration, Timer};
|
||||
use embassy_time::Timer;
|
||||
use pac::uart::regs::Uartris;
|
||||
|
||||
use crate::clocks::clk_peri_freq;
|
||||
@ -187,7 +187,7 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
|
||||
self.blocking_flush().unwrap();
|
||||
while self.busy() {}
|
||||
regs.uartlcr_h().write_set(|w| w.set_brk(true));
|
||||
Timer::after(Duration::from_micros(wait_usecs)).await;
|
||||
Timer::after_micros(wait_usecs).await;
|
||||
regs.uartlcr_h().write_clear(|w| w.set_brk(true));
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ features = ["stm32wb55rg"]
|
||||
[dependencies]
|
||||
embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" }
|
||||
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.5", path = "../embassy-time", optional = true }
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
embassy-hal-internal = { version = "0.1.0", path = "../embassy-hal-internal" }
|
||||
embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||
|
@ -1,4 +1,3 @@
|
||||
use core::marker::PhantomData;
|
||||
use core::ptr;
|
||||
|
||||
use embassy_stm32::ipcc::Ipcc;
|
||||
@ -13,7 +12,7 @@ use crate::unsafe_linked_list::LinkedListNode;
|
||||
use crate::{channels, evt};
|
||||
|
||||
pub struct Ble {
|
||||
phantom: PhantomData<Ble>,
|
||||
_private: (),
|
||||
}
|
||||
|
||||
impl Ble {
|
||||
@ -29,7 +28,7 @@ impl Ble {
|
||||
});
|
||||
}
|
||||
|
||||
Self { phantom: PhantomData }
|
||||
Self { _private: () }
|
||||
}
|
||||
/// `HW_IPCC_BLE_EvtNot`
|
||||
pub async fn tl_read(&self) -> EvtBox<Self> {
|
||||
|
@ -1,5 +1,4 @@
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::ptr;
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
use core::task::Poll;
|
||||
@ -21,12 +20,12 @@ static MAC_WAKER: AtomicWaker = AtomicWaker::new();
|
||||
static MAC_EVT_OUT: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
pub struct Mac {
|
||||
phantom: PhantomData<Mac>,
|
||||
_private: (),
|
||||
}
|
||||
|
||||
impl Mac {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self { phantom: PhantomData }
|
||||
Self { _private: () }
|
||||
}
|
||||
|
||||
/// `HW_IPCC_MAC_802_15_4_EvtNot`
|
||||
|
@ -1,6 +1,5 @@
|
||||
//! Memory manager routines
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::mem::MaybeUninit;
|
||||
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());
|
||||
|
||||
pub struct MemoryManager {
|
||||
phantom: PhantomData<MemoryManager>,
|
||||
_private: (),
|
||||
}
|
||||
|
||||
impl MemoryManager {
|
||||
@ -44,7 +43,7 @@ impl MemoryManager {
|
||||
});
|
||||
}
|
||||
|
||||
Self { phantom: PhantomData }
|
||||
Self { _private: () }
|
||||
}
|
||||
|
||||
pub async fn run_queue(&self) {
|
||||
|
@ -1,4 +1,3 @@
|
||||
use core::marker::PhantomData;
|
||||
use core::ptr;
|
||||
|
||||
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};
|
||||
|
||||
pub struct Sys {
|
||||
phantom: PhantomData<Sys>,
|
||||
_private: (),
|
||||
}
|
||||
|
||||
impl Sys {
|
||||
@ -27,7 +26,7 @@ impl Sys {
|
||||
});
|
||||
}
|
||||
|
||||
Self { phantom: PhantomData }
|
||||
Self { _private: () }
|
||||
}
|
||||
|
||||
/// Returns CPU2 wireless firmware information (if present).
|
||||
|
@ -21,18 +21,19 @@ flavors = [
|
||||
{ regex_feature = "stm32g4.*", target = "thumbv7em-none-eabi" },
|
||||
{ regex_feature = "stm32h5.*", target = "thumbv8m.main-none-eabihf" },
|
||||
{ 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 = "stm32l4.*", target = "thumbv7em-none-eabi" },
|
||||
{ regex_feature = "stm32l5.*", target = "thumbv8m.main-none-eabihf" },
|
||||
{ regex_feature = "stm32u5.*", target = "thumbv8m.main-none-eabihf" },
|
||||
{ regex_feature = "stm32wb.*", target = "thumbv7em-none-eabi" },
|
||||
{ regex_feature = "stm32wba.*", target = "thumbv8m.main-none-eabihf" },
|
||||
{ regex_feature = "stm32wl.*", target = "thumbv7em-none-eabi" },
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
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.5", path = "../embassy-time", optional = true }
|
||||
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-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||
@ -57,16 +58,14 @@ rand_core = "0.6.3"
|
||||
sdio-host = "0.5.0"
|
||||
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
|
||||
critical-section = "1.1"
|
||||
atomic-polyfill = "1.0.1"
|
||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4e6a74f69c4bc5d2d4872ba50d805e75bfe55cad" }
|
||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9330e31117668350a62572fdcd2598ec17d08042" }
|
||||
vcell = "0.1.3"
|
||||
bxcan = "0.7.0"
|
||||
nb = "1.0.0"
|
||||
stm32-fmc = "0.3.0"
|
||||
seq-macro = "0.3.0"
|
||||
cfg-if = "1.0.0"
|
||||
embedded-io = { version = "0.5.0" }
|
||||
embedded-io-async = { version = "0.5.0", optional = true }
|
||||
embedded-io = { version = "0.6.0" }
|
||||
embedded-io-async = { version = "0.6.0", optional = true }
|
||||
chrono = { version = "^0.4", default-features = false, optional = true}
|
||||
bit_field = "0.10.2"
|
||||
document-features = "0.2.7"
|
||||
@ -77,7 +76,8 @@ critical-section = { version = "1.1", features = ["std"] }
|
||||
[build-dependencies]
|
||||
proc-macro2 = "1.0.36"
|
||||
quote = "1.0.15"
|
||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-4e6a74f69c4bc5d2d4872ba50d805e75bfe55cad", default-features = false, features = ["metadata"]}
|
||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-9330e31117668350a62572fdcd2598ec17d08042", default-features = false, features = ["metadata"]}
|
||||
|
||||
|
||||
[features]
|
||||
default = ["rt"]
|
||||
@ -133,6 +133,22 @@ time-driver-tim12 = ["_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
|
||||
#! Select your chip by specifying the model as a feature, e.g. `stm32c011d6`.
|
||||
#! Check the `Cargo.toml` for the latest list of supported chips.
|
||||
@ -1454,6 +1470,10 @@ stm32wb55vc = [ "stm32-metapac/stm32wb55vc" ]
|
||||
stm32wb55ve = [ "stm32-metapac/stm32wb55ve" ]
|
||||
stm32wb55vg = [ "stm32-metapac/stm32wb55vg" ]
|
||||
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-cm0p = [ "stm32-metapac/stm32wl54cc-cm0p" ]
|
||||
stm32wl54jc-cm4 = [ "stm32-metapac/stm32wl54jc-cm4" ]
|
||||
|
@ -5,9 +5,36 @@ use std::{env, fs};
|
||||
|
||||
use proc_macro2::{Ident, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
use stm32_metapac::metadata::{MemoryRegionKind, METADATA};
|
||||
use stm32_metapac::metadata::ir::{BlockItemInner, Enum, FieldSet};
|
||||
use stm32_metapac::metadata::{MemoryRegionKind, PeripheralRccRegister, METADATA};
|
||||
|
||||
fn main() {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
|
||||
if target.starts_with("thumbv6m-") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv6m");
|
||||
} else if target.starts_with("thumbv7m-") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv7m");
|
||||
} else if target.starts_with("thumbv7em-") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv7m");
|
||||
println!("cargo:rustc-cfg=armv7em"); // (not currently used)
|
||||
} else if target.starts_with("thumbv8m.base") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv8m");
|
||||
println!("cargo:rustc-cfg=armv8m_base");
|
||||
} else if target.starts_with("thumbv8m.main") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv8m");
|
||||
println!("cargo:rustc-cfg=armv8m_main");
|
||||
}
|
||||
|
||||
if target.ends_with("-eabihf") {
|
||||
println!("cargo:rustc-cfg=has_fpu");
|
||||
}
|
||||
|
||||
let chip_name = match env::vars()
|
||||
.map(|(a, _)| a)
|
||||
.filter(|x| x.starts_with("CARGO_FEATURE_STM32"))
|
||||
@ -50,12 +77,14 @@ fn main() {
|
||||
// We *shouldn't* have singletons for these, but the HAL currently requires
|
||||
// singletons, for using with RccPeripheral to enable/disable clocks to them.
|
||||
"rcc" => {
|
||||
if r.version.starts_with("h5") || r.version.starts_with("h7") || r.version.starts_with("f4") {
|
||||
singletons.push("MCO1".to_string());
|
||||
singletons.push("MCO2".to_string());
|
||||
}
|
||||
if r.version.starts_with("l4") {
|
||||
singletons.push("MCO".to_string());
|
||||
for pin in p.pins {
|
||||
if pin.signal.starts_with("MCO") {
|
||||
let name = pin.signal.replace('_', "").to_string();
|
||||
if !singletons.contains(&name) {
|
||||
println!("cargo:rustc-cfg={}", name.to_ascii_lowercase());
|
||||
singletons.push(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
singletons.push(p.name.to_string());
|
||||
}
|
||||
@ -81,6 +110,60 @@ fn main() {
|
||||
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.
|
||||
|
||||
@ -305,6 +388,47 @@ fn main() {
|
||||
});
|
||||
}
|
||||
|
||||
// ========
|
||||
// Extract the rcc registers
|
||||
let rcc_registers = METADATA
|
||||
.peripherals
|
||||
.iter()
|
||||
.filter_map(|p| p.registers.as_ref())
|
||||
.find(|r| r.kind == "rcc")
|
||||
.unwrap();
|
||||
|
||||
// ========
|
||||
// Generate rcc fieldset and enum maps
|
||||
let rcc_enum_map: HashMap<&str, HashMap<&str, &Enum>> = {
|
||||
let rcc_blocks = rcc_registers.ir.blocks.iter().find(|b| b.name == "Rcc").unwrap().items;
|
||||
let rcc_fieldsets: HashMap<&str, &FieldSet> = rcc_registers.ir.fieldsets.iter().map(|f| (f.name, f)).collect();
|
||||
let rcc_enums: HashMap<&str, &Enum> = rcc_registers.ir.enums.iter().map(|e| (e.name, e)).collect();
|
||||
|
||||
rcc_blocks
|
||||
.iter()
|
||||
.filter_map(|b| match &b.inner {
|
||||
BlockItemInner::Register(register) => register.fieldset.map(|f| (b.name, f)),
|
||||
_ => None,
|
||||
})
|
||||
.filter_map(|(b, f)| {
|
||||
rcc_fieldsets.get(f).map(|f| {
|
||||
(
|
||||
b,
|
||||
f.fields
|
||||
.iter()
|
||||
.filter_map(|f| {
|
||||
let enumm = f.enumm?;
|
||||
let enumm = rcc_enums.get(enumm)?;
|
||||
|
||||
Some((f.name, *enumm))
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
|
||||
// ========
|
||||
// Generate RccPeripheral impls
|
||||
|
||||
@ -324,10 +448,8 @@ fn main() {
|
||||
let rst_reg = format_ident!("{}", rst.register.to_ascii_lowercase());
|
||||
let set_rst_field = format_ident!("set_{}", rst.field.to_ascii_lowercase());
|
||||
quote! {
|
||||
critical_section::with(|_| {
|
||||
crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true));
|
||||
crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false));
|
||||
});
|
||||
crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true));
|
||||
crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false));
|
||||
}
|
||||
}
|
||||
None => TokenStream::new(),
|
||||
@ -344,7 +466,13 @@ fn main() {
|
||||
|
||||
let ptype = if let Some(reg) = &p.registers { reg.kind } else { "" };
|
||||
let pname = format_ident!("{}", p.name);
|
||||
let clk = format_ident!("{}", rcc.clock.to_ascii_lowercase());
|
||||
let clk = format_ident!(
|
||||
"{}",
|
||||
rcc.clock
|
||||
.to_ascii_lowercase()
|
||||
.replace("ahb", "hclk")
|
||||
.replace("apb", "pclk")
|
||||
);
|
||||
let en_reg = format_ident!("{}", en.register.to_ascii_lowercase());
|
||||
let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase());
|
||||
|
||||
@ -372,31 +500,82 @@ fn main() {
|
||||
(TokenStream::new(), TokenStream::new())
|
||||
};
|
||||
|
||||
let mux_for = |mux: Option<&'static PeripheralRccRegister>| {
|
||||
let checked_rccs = HashSet::from(["h5", "h50", "h7", "h7ab", "h7rm0433", "g4"]);
|
||||
|
||||
// restrict mux implementation to supported versions
|
||||
if !checked_rccs.contains(rcc_registers.version) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mux = mux?;
|
||||
let fieldset = rcc_enum_map.get(mux.register)?;
|
||||
let enumm = fieldset.get(mux.field)?;
|
||||
|
||||
Some((mux, *enumm))
|
||||
};
|
||||
|
||||
let clock_frequency = match mux_for(rcc.mux.as_ref()) {
|
||||
Some((mux, rcc_enumm)) => {
|
||||
let fieldset_name = format_ident!("{}", mux.register);
|
||||
let field_name = format_ident!("{}", mux.field);
|
||||
let enum_name = format_ident!("{}", rcc_enumm.name);
|
||||
|
||||
let match_arms: TokenStream = rcc_enumm
|
||||
.variants
|
||||
.iter()
|
||||
.filter(|v| v.name != "DISABLE")
|
||||
.map(|v| {
|
||||
let variant_name = format_ident!("{}", v.name);
|
||||
let clock_name = format_ident!("{}", v.name.to_ascii_lowercase());
|
||||
|
||||
if v.name.starts_with("HCLK") || v.name.starts_with("PCLK") || v.name == "SYS" {
|
||||
quote! {
|
||||
#enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name },
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
#enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name.unwrap() },
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
quote! {
|
||||
use crate::pac::rcc::vals::#enum_name;
|
||||
|
||||
#[allow(unreachable_patterns)]
|
||||
match crate::pac::RCC.#fieldset_name().read().#field_name() {
|
||||
#match_arms
|
||||
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
None => quote! {
|
||||
unsafe { crate::rcc::get_freqs().#clk }
|
||||
},
|
||||
};
|
||||
|
||||
g.extend(quote! {
|
||||
impl crate::rcc::sealed::RccPeripheral for peripherals::#pname {
|
||||
fn frequency() -> crate::time::Hertz {
|
||||
unsafe { crate::rcc::get_freqs().#clk }
|
||||
#clock_frequency
|
||||
}
|
||||
fn enable() {
|
||||
critical_section::with(|_| {
|
||||
#before_enable
|
||||
#[cfg(feature = "low-power")]
|
||||
crate::rcc::clock_refcount_add();
|
||||
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true));
|
||||
#after_enable
|
||||
})
|
||||
}
|
||||
fn disable() {
|
||||
critical_section::with(|_| {
|
||||
#before_disable
|
||||
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false));
|
||||
#[cfg(feature = "low-power")]
|
||||
crate::rcc::clock_refcount_sub();
|
||||
})
|
||||
}
|
||||
fn reset() {
|
||||
fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) {
|
||||
#before_enable
|
||||
#[cfg(feature = "low-power")]
|
||||
crate::rcc::clock_refcount_add(_cs);
|
||||
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true));
|
||||
#after_enable
|
||||
#rst
|
||||
}
|
||||
fn disable_with_cs(_cs: critical_section::CriticalSection) {
|
||||
#before_disable
|
||||
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false));
|
||||
#[cfg(feature = "low-power")]
|
||||
crate::rcc::clock_refcount_sub(_cs);
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::rcc::RccPeripheral for peripherals::#pname {}
|
||||
@ -404,12 +583,14 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let mut refcount_mod = TokenStream::new();
|
||||
for refcount_static in refcount_statics {
|
||||
refcount_mod.extend(quote! {
|
||||
pub(crate) static mut #refcount_static: u8 = 0;
|
||||
});
|
||||
}
|
||||
let refcount_mod: TokenStream = refcount_statics
|
||||
.iter()
|
||||
.map(|refcount_static| {
|
||||
quote! {
|
||||
pub(crate) static mut #refcount_static: u8 = 0;
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
g.extend(quote! {
|
||||
mod refcount_statics {
|
||||
@ -463,6 +644,15 @@ fn main() {
|
||||
(("lpuart", "RTS"), quote!(crate::usart::RtsPin)),
|
||||
(("lpuart", "CK"), quote!(crate::usart::CkPin)),
|
||||
(("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", "MOSI"), quote!(crate::spi::MosiPin)),
|
||||
(("spi", "MISO"), quote!(crate::spi::MisoPin)),
|
||||
@ -656,12 +846,17 @@ fn main() {
|
||||
(("sdmmc", "D6"), quote!(crate::sdmmc::D6Pin)),
|
||||
(("sdmmc", "D6"), quote!(crate::sdmmc::D7Pin)),
|
||||
(("sdmmc", "D8"), quote!(crate::sdmmc::D8Pin)),
|
||||
(("quadspi", "BK1_IO0"), quote!(crate::qspi::D0Pin)),
|
||||
(("quadspi", "BK1_IO1"), quote!(crate::qspi::D1Pin)),
|
||||
(("quadspi", "BK1_IO2"), quote!(crate::qspi::D2Pin)),
|
||||
(("quadspi", "BK1_IO3"), quote!(crate::qspi::D3Pin)),
|
||||
(("quadspi", "BK1_IO0"), quote!(crate::qspi::BK1D0Pin)),
|
||||
(("quadspi", "BK1_IO1"), quote!(crate::qspi::BK1D1Pin)),
|
||||
(("quadspi", "BK1_IO2"), quote!(crate::qspi::BK1D2Pin)),
|
||||
(("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", "BK1_NCS"), quote!(crate::qspi::NSSPin)),
|
||||
].into();
|
||||
|
||||
for p in METADATA.peripherals {
|
||||
@ -670,29 +865,21 @@ fn main() {
|
||||
let key = (regs.kind, pin.signal);
|
||||
if let Some(tr) = signals.get(&key) {
|
||||
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);
|
||||
|
||||
// MCO is special
|
||||
if pin.signal.starts_with("MCO_") {
|
||||
// Supported in H7 only for now
|
||||
if regs.version.starts_with("h5")
|
||||
|| regs.version.starts_with("h7")
|
||||
|| regs.version.starts_with("f4")
|
||||
{
|
||||
peri = format_ident!("{}", pin.signal.replace('_', ""));
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if pin.signal == "MCO" {
|
||||
// Supported in H7 only for now
|
||||
if regs.version.starts_with("l4") {
|
||||
peri = format_ident!("MCO");
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
if pin.signal.starts_with("MCO") {
|
||||
peri = format_ident!("{}", pin.signal.replace('_', ""));
|
||||
}
|
||||
|
||||
g.extend(quote! {
|
||||
@ -707,7 +894,13 @@ fn main() {
|
||||
}
|
||||
|
||||
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
|
||||
let ch: Option<u8> = if pin.signal.starts_with("INP") {
|
||||
@ -727,6 +920,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
|
||||
if regs.kind == "dac" {
|
||||
let peri = format_ident!("{}", p.name);
|
||||
@ -750,6 +957,8 @@ fn main() {
|
||||
(("usart", "TX"), quote!(crate::usart::TxDma)),
|
||||
(("lpuart", "RX"), quote!(crate::usart::RxDma)),
|
||||
(("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", "TX"), quote!(crate::spi::TxDma)),
|
||||
(("i2c", "RX"), quote!(crate::i2c::RxDma)),
|
||||
@ -809,6 +1018,97 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
// ========
|
||||
// Generate Div/Mul impls for RCC prescalers/dividers/multipliers.
|
||||
for e in rcc_registers.ir.enums {
|
||||
fn is_rcc_name(e: &str) -> bool {
|
||||
match e {
|
||||
"Pllp" | "Pllq" | "Pllr" | "Pllm" | "Plln" => true,
|
||||
"Timpre" | "Pllrclkpre" => false,
|
||||
e if e.ends_with("pre") || e.ends_with("pres") || e.ends_with("div") || e.ends_with("mul") => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct Frac {
|
||||
num: u32,
|
||||
denom: u32,
|
||||
}
|
||||
|
||||
impl Frac {
|
||||
fn simplify(self) -> Self {
|
||||
let d = gcd(self.num, self.denom);
|
||||
Self {
|
||||
num: self.num / d,
|
||||
denom: self.denom / d,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gcd(a: u32, b: u32) -> u32 {
|
||||
if b == 0 {
|
||||
return a;
|
||||
}
|
||||
gcd(b, a % b)
|
||||
}
|
||||
|
||||
fn parse_num(n: &str) -> Result<Frac, ()> {
|
||||
for prefix in ["DIV", "MUL"] {
|
||||
if let Some(n) = n.strip_prefix(prefix) {
|
||||
let exponent = n.find('_').map(|e| n.len() - 1 - e).unwrap_or(0) as u32;
|
||||
let mantissa = n.replace('_', "").parse().map_err(|_| ())?;
|
||||
let f = Frac {
|
||||
num: mantissa,
|
||||
denom: 10u32.pow(exponent),
|
||||
};
|
||||
return Ok(f.simplify());
|
||||
}
|
||||
}
|
||||
Err(())
|
||||
}
|
||||
|
||||
if is_rcc_name(e.name) {
|
||||
let enum_name = format_ident!("{}", e.name);
|
||||
let mut muls = Vec::new();
|
||||
let mut divs = Vec::new();
|
||||
for v in e.variants {
|
||||
let Ok(val) = parse_num(v.name) else {
|
||||
panic!("could not parse mul/div. enum={} variant={}", e.name, v.name)
|
||||
};
|
||||
let variant_name = format_ident!("{}", v.name);
|
||||
let variant = quote!(crate::pac::rcc::vals::#enum_name::#variant_name);
|
||||
let num = val.num;
|
||||
let denom = val.denom;
|
||||
muls.push(quote!(#variant => self * #num / #denom,));
|
||||
divs.push(quote!(#variant => self * #denom / #num,));
|
||||
}
|
||||
|
||||
g.extend(quote! {
|
||||
impl core::ops::Div<crate::pac::rcc::vals::#enum_name> for crate::time::Hertz {
|
||||
type Output = crate::time::Hertz;
|
||||
fn div(self, rhs: crate::pac::rcc::vals::#enum_name) -> Self::Output {
|
||||
match rhs {
|
||||
#(#divs)*
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl core::ops::Mul<crate::pac::rcc::vals::#enum_name> for crate::time::Hertz {
|
||||
type Output = crate::time::Hertz;
|
||||
fn mul(self, rhs: crate::pac::rcc::vals::#enum_name) -> Self::Output {
|
||||
match rhs {
|
||||
#(#muls)*
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ========
|
||||
// Write foreach_foo! macrotables
|
||||
|
||||
@ -817,6 +1117,17 @@ fn main() {
|
||||
let mut peripherals_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 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
|
||||
.memory
|
||||
@ -844,16 +1155,45 @@ fn main() {
|
||||
|
||||
for pin_num in 0u32..16 {
|
||||
let pin_name = format!("P{}{}", port_letter, pin_num);
|
||||
|
||||
pins_table.push(vec![
|
||||
pin_name,
|
||||
pin_name.clone(),
|
||||
p.name.to_string(),
|
||||
port_num.to_string(),
|
||||
pin_num.to_string(),
|
||||
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 {
|
||||
let row = vec![
|
||||
p.name.to_string(),
|
||||
@ -932,6 +1272,7 @@ fn main() {
|
||||
make_table(&mut m, "foreach_peripheral", &peripherals_table);
|
||||
make_table(&mut m, "foreach_pin", &pins_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_file = out_dir.join("_macros.rs").to_string_lossy().to_string();
|
||||
@ -973,13 +1314,24 @@ fn main() {
|
||||
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
|
||||
|
||||
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
|
||||
if &chip_name[..8] == "stm32wba" {
|
||||
println!("cargo:rustc-cfg={}", &chip_name[..8]); // stm32wba
|
||||
println!("cargo:rustc-cfg={}", &chip_name[..10]); // stm32wba52
|
||||
} 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.
|
||||
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 embedded_hal_02::blocking::delay::DelayUs;
|
||||
|
||||
use crate::adc::{Adc, AdcPin, Instance, SampleTime};
|
||||
use crate::rcc::get_freqs;
|
||||
use crate::time::Hertz;
|
||||
use crate::Peripheral;
|
||||
use crate::{interrupt, Peripheral};
|
||||
|
||||
pub const VDDA_CALIB_MV: u32 = 3300;
|
||||
pub const ADC_MAX: u32 = (1 << 12) - 1;
|
||||
// No calibration data for F103, voltage should be 1.2v
|
||||
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;
|
||||
impl<T: Instance> AdcPin<T> for Vref {}
|
||||
impl<T: Instance> super::sealed::AdcPin<T> for Vref {
|
||||
@ -30,8 +51,7 @@ impl<T: Instance> super::sealed::AdcPin<T> for Temperature {
|
||||
impl<'d, T: Instance> Adc<'d, T> {
|
||||
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
|
||||
into_ref!(adc);
|
||||
T::enable();
|
||||
T::reset();
|
||||
T::enable_and_reset();
|
||||
T::regs().cr2().modify(|reg| reg.set_adon(true));
|
||||
|
||||
// 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’)
|
||||
@ -95,18 +115,28 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
}
|
||||
|
||||
/// Perform a single conversion.
|
||||
fn convert(&mut self) -> u16 {
|
||||
async fn convert(&mut self) -> u16 {
|
||||
T::regs().cr2().modify(|reg| {
|
||||
reg.set_adon(true);
|
||||
reg.set_swstart(true);
|
||||
});
|
||||
while T::regs().cr2().read().swstart() {}
|
||||
while !T::regs().sr().read().eoc() {}
|
||||
T::regs().cr1().modify(|w| w.set_eocie(true));
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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);
|
||||
T::regs().cr1().modify(|reg| {
|
||||
reg.set_scan(false);
|
||||
@ -123,7 +153,7 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
|
||||
// Configure the channel to sample
|
||||
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) {
|
||||
@ -135,3 +165,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 embedded_hal_02::blocking::delay::DelayUs;
|
||||
|
||||
use crate::adc::{Adc, AdcPin, Instance, SampleTime};
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::time::Hertz;
|
||||
use crate::Peripheral;
|
||||
use crate::{interrupt, Peripheral};
|
||||
|
||||
pub const VDDA_CALIB_MV: u32 = 3300;
|
||||
pub const ADC_MAX: u32 = (1 << 12) - 1;
|
||||
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;
|
||||
impl<T: Instance> 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;
|
||||
impl<T: Instance> AdcPin<T> for Temperature {}
|
||||
impl<T: Instance> super::sealed::AdcPin<T> for Temperature {
|
||||
@ -26,13 +55,16 @@ impl<T: Instance> super::sealed::AdcPin<T> for Temperature {
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
into_ref!(adc);
|
||||
|
||||
T::enable();
|
||||
T::reset();
|
||||
T::enable_and_reset();
|
||||
|
||||
// Enable the adc regulator
|
||||
T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE));
|
||||
@ -50,7 +82,7 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
while T::regs().cr().read().adcal() {}
|
||||
|
||||
// Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223)
|
||||
delay.delay_us(6 * 1_000_000 / Self::freq().0);
|
||||
delay.delay_us(1 + (6 * 1_000_000 / Self::freq().0));
|
||||
|
||||
// Enable the adc
|
||||
T::regs().cr().modify(|w| w.set_aden(true));
|
||||
@ -58,6 +90,11 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
// Wait until the adc is ready
|
||||
while !T::regs().isr().read().adrdy() {}
|
||||
|
||||
T::Interrupt::unpend();
|
||||
unsafe {
|
||||
T::Interrupt::enable();
|
||||
}
|
||||
|
||||
Self {
|
||||
adc,
|
||||
sample_time: Default::default(),
|
||||
@ -97,30 +134,61 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
}
|
||||
|
||||
/// Perform a single conversion.
|
||||
fn convert(&mut self) -> u16 {
|
||||
async fn convert(&mut self) -> u16 {
|
||||
T::regs().isr().write(|_| {});
|
||||
T::regs().ier().modify(|w| w.set_eocie(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().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);
|
||||
|
||||
// Configure the channel to sample
|
||||
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) {
|
||||
let sample_time = sample_time.into();
|
||||
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 {
|
||||
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 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;
|
||||
#[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_g0)))]
|
||||
fn common_regs() -> crate::pac::adccommon::AdcCommon;
|
||||
#[cfg(adc_f3)]
|
||||
fn frequency() -> crate::time::Hertz;
|
||||
#[cfg(any(adc_f1, adc_f3, adc_v1))]
|
||||
fn state() -> &'static State;
|
||||
}
|
||||
|
||||
pub trait AdcPin<T: Instance> {
|
||||
#[cfg(any(adc_v1, adc_v2))]
|
||||
fn set_as_analog(&mut self) {}
|
||||
|
||||
fn channel(&self) -> u8;
|
||||
}
|
||||
|
||||
@ -48,137 +74,45 @@ pub(crate) mod sealed {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v4, adc_f3)))]
|
||||
#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_g0)))]
|
||||
pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {}
|
||||
#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v4, adc_f3))]
|
||||
#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_g0))]
|
||||
pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {}
|
||||
|
||||
pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {}
|
||||
pub trait InternalChannel<T>: sealed::InternalChannel<T> {}
|
||||
|
||||
#[cfg(not(any(stm32h7, adc_f3, adc_v4)))]
|
||||
foreach_peripheral!(
|
||||
(adc, $inst:ident) => {
|
||||
foreach_adc!(
|
||||
($inst:ident, $common_inst:ident, $clock: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, adc_f3_v2, adc_g0)))]
|
||||
fn common_regs() -> crate::pac::adccommon::AdcCommon {
|
||||
foreach_peripheral!{
|
||||
(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) => {
|
||||
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)))]
|
||||
#[allow(unreachable_code)]
|
||||
fn common_regs() -> crate::pac::adccommon::AdcCommon {
|
||||
foreach_peripheral!{
|
||||
(adccommon, ADC3_COMMON) => {
|
||||
return crate::pac::ADC3_COMMON
|
||||
};
|
||||
// Fall back to ADC_COMMON if ADC3_COMMON does not exist
|
||||
(adccommon, ADC_COMMON) => {
|
||||
return crate::pac::ADC_COMMON
|
||||
};
|
||||
}
|
||||
return crate::pac::$common_inst
|
||||
}
|
||||
|
||||
#[cfg(adc_f3)]
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::adc::Instance for peripherals::ADC3 {}
|
||||
};
|
||||
(adc, ADC4) => {
|
||||
impl crate::adc::sealed::Instance for peripherals::ADC4 {
|
||||
fn regs() -> crate::pac::adc::Adc {
|
||||
crate::pac::ADC4
|
||||
}
|
||||
#[cfg(not(any(adc_f1, adc_v1)))]
|
||||
#[allow(unreachable_code)]
|
||||
fn common_regs() -> crate::pac::adccommon::AdcCommon {
|
||||
foreach_peripheral!{
|
||||
(adccommon, ADC3_COMMON) => {
|
||||
return crate::pac::ADC3_COMMON
|
||||
};
|
||||
// Fall back to ADC_COMMON if ADC3_COMMON does not exist
|
||||
(adccommon, ADC_COMMON) => {
|
||||
return crate::pac::ADC_COMMON
|
||||
};
|
||||
foreach_interrupt!(
|
||||
($inst,adc,ADC,GLOBAL,$irq:ident) => {
|
||||
impl sealed::InterruptableInstance for peripherals::$inst {
|
||||
type Interrupt = crate::interrupt::typelevel::$irq;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(adc_f3)]
|
||||
fn frequency() -> crate::time::Hertz {
|
||||
unsafe { crate::rcc::get_freqs() }.adc34.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::adc::Instance for peripherals::ADC4 {}
|
||||
};
|
||||
(adc, ADC5) => {
|
||||
impl crate::adc::sealed::Instance for peripherals::ADC5 {
|
||||
fn regs() -> crate::pac::adc::Adc {
|
||||
crate::pac::ADC5
|
||||
}
|
||||
#[cfg(not(any(adc_f1, adc_v1)))]
|
||||
#[allow(unreachable_code)]
|
||||
fn common_regs() -> crate::pac::adccommon::AdcCommon {
|
||||
foreach_peripheral!{
|
||||
(adccommon, ADC3_COMMON) => {
|
||||
return crate::pac::ADC3_COMMON
|
||||
};
|
||||
// Fall back to ADC_COMMON if ADC3_COMMON does not exist
|
||||
(adccommon, ADC_COMMON) => {
|
||||
return crate::pac::ADC_COMMON
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(adc_f3)]
|
||||
fn frequency() -> crate::time::Hertz {
|
||||
unsafe { crate::rcc::get_freqs() }.adc34.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::adc::Instance for peripherals::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 {}
|
||||
};
|
||||
@ -189,6 +123,11 @@ macro_rules! impl_adc_pin {
|
||||
impl crate::adc::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 {
|
||||
$ch
|
||||
}
|
||||
|
@ -1,42 +1,67 @@
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_hal_internal::into_ref;
|
||||
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::Peripheral;
|
||||
use crate::{interrupt, Peripheral};
|
||||
|
||||
pub const VDDA_CALIB_MV: u32 = 3300;
|
||||
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;
|
||||
impl InternalChannel<ADC> for Vbat {}
|
||||
impl super::sealed::InternalChannel<ADC> for Vbat {
|
||||
impl AdcPin<ADC> for Vbat {}
|
||||
impl super::sealed::AdcPin<ADC> for Vbat {
|
||||
fn channel(&self) -> u8 {
|
||||
18
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Vref;
|
||||
impl InternalChannel<ADC> for Vref {}
|
||||
impl super::sealed::InternalChannel<ADC> for Vref {
|
||||
impl AdcPin<ADC> for Vref {}
|
||||
impl super::sealed::AdcPin<ADC> for Vref {
|
||||
fn channel(&self) -> u8 {
|
||||
17
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Temperature;
|
||||
impl InternalChannel<ADC> for Temperature {}
|
||||
impl super::sealed::InternalChannel<ADC> for Temperature {
|
||||
impl AdcPin<ADC> for Temperature {}
|
||||
impl super::sealed::AdcPin<ADC> for Temperature {
|
||||
fn channel(&self) -> u8 {
|
||||
16
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
T::enable();
|
||||
T::reset();
|
||||
T::enable_and_reset();
|
||||
|
||||
// Delay 1μs when using HSI14 as the ADC clock.
|
||||
//
|
||||
@ -44,12 +69,32 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
// tstab = 14 * 1/fadc
|
||||
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,
|
||||
sample_time: Default::default(),
|
||||
};
|
||||
s.calibrate();
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enable_vbat(&self, _delay: &mut impl DelayUs<u32>) -> Vbat {
|
||||
@ -80,21 +125,6 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
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) {
|
||||
self.sample_time = sample_time;
|
||||
}
|
||||
@ -103,57 +133,50 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
T::regs().cfgr1().modify(|reg| reg.set_res(resolution.into()));
|
||||
}
|
||||
|
||||
pub fn read<P>(&mut self, pin: &mut P) -> u16
|
||||
where
|
||||
P: AdcPin<T> + crate::gpio::sealed::Pin,
|
||||
{
|
||||
pub async fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
|
||||
let channel = pin.channel();
|
||||
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 {
|
||||
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));
|
||||
}
|
||||
|
||||
async fn convert(&mut self) -> u16 {
|
||||
T::regs().isr().modify(|reg| {
|
||||
reg.set_eoc(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().ier().modify(|w| w.set_eocie(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
|
||||
T::regs().cr().modify(|reg| reg.set_adstp(true));
|
||||
while T::regs().cr().read().adstp() {
|
||||
// spin
|
||||
}
|
||||
T::regs().cr().modify(|reg| reg.set_addis(true));
|
||||
while T::regs().cr().read().aden() {
|
||||
// spin
|
||||
}
|
||||
poll_fn(|cx| {
|
||||
T::state().waker.register(cx.waker());
|
||||
|
||||
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 embedded_hal_02::blocking::delay::DelayUs;
|
||||
|
||||
use super::InternalChannel;
|
||||
use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime};
|
||||
use crate::peripherals::ADC1;
|
||||
use crate::time::Hertz;
|
||||
@ -16,8 +15,8 @@ pub const VREF_CALIB_MV: u32 = 3300;
|
||||
pub const ADC_POWERUP_TIME_US: u32 = 3;
|
||||
|
||||
pub struct VrefInt;
|
||||
impl InternalChannel<ADC1> for VrefInt {}
|
||||
impl super::sealed::InternalChannel<ADC1> for VrefInt {
|
||||
impl AdcPin<ADC1> for VrefInt {}
|
||||
impl super::sealed::AdcPin<ADC1> for VrefInt {
|
||||
fn channel(&self) -> u8 {
|
||||
17
|
||||
}
|
||||
@ -31,8 +30,8 @@ impl VrefInt {
|
||||
}
|
||||
|
||||
pub struct Temperature;
|
||||
impl InternalChannel<ADC1> for Temperature {}
|
||||
impl super::sealed::InternalChannel<ADC1> for Temperature {
|
||||
impl AdcPin<ADC1> for Temperature {}
|
||||
impl super::sealed::AdcPin<ADC1> for Temperature {
|
||||
fn channel(&self) -> u8 {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(stm32f40, stm32f41))] {
|
||||
@ -52,8 +51,8 @@ impl Temperature {
|
||||
}
|
||||
|
||||
pub struct Vbat;
|
||||
impl InternalChannel<ADC1> for Vbat {}
|
||||
impl super::sealed::InternalChannel<ADC1> for Vbat {
|
||||
impl AdcPin<ADC1> for Vbat {}
|
||||
impl super::sealed::AdcPin<ADC1> for Vbat {
|
||||
fn channel(&self) -> u8 {
|
||||
18
|
||||
}
|
||||
@ -96,8 +95,7 @@ where
|
||||
{
|
||||
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
|
||||
into_ref!(adc);
|
||||
T::enable();
|
||||
T::reset();
|
||||
T::enable_and_reset();
|
||||
|
||||
let presc = Prescaler::from_pclk2(T::frequency());
|
||||
T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre()));
|
||||
@ -125,7 +123,7 @@ where
|
||||
/// [Adc::read_internal()] to perform conversion.
|
||||
pub fn enable_vrefint(&self) -> VrefInt {
|
||||
T::common_regs().ccr().modify(|reg| {
|
||||
reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED);
|
||||
reg.set_tsvrefe(true);
|
||||
});
|
||||
|
||||
VrefInt {}
|
||||
@ -138,7 +136,7 @@ where
|
||||
/// temperature sensor will return vbat value.
|
||||
pub fn enable_temperature(&self) -> Temperature {
|
||||
T::common_regs().ccr().modify(|reg| {
|
||||
reg.set_tsvrefe(crate::pac::adccommon::vals::Tsvrefe::ENABLED);
|
||||
reg.set_tsvrefe(true);
|
||||
});
|
||||
|
||||
Temperature {}
|
||||
@ -148,7 +146,7 @@ where
|
||||
/// [Adc::read_internal()] to perform conversion.
|
||||
pub fn enable_vbat(&self) -> Vbat {
|
||||
T::common_regs().ccr().modify(|reg| {
|
||||
reg.set_vbate(crate::pac::adccommon::vals::Vbate::ENABLED);
|
||||
reg.set_vbate(true);
|
||||
});
|
||||
|
||||
Vbat {}
|
||||
@ -176,22 +174,11 @@ where
|
||||
T::regs().dr().read().0 as u16
|
||||
}
|
||||
|
||||
pub fn read<P>(&mut self, pin: &mut P) -> u16
|
||||
where
|
||||
P: AdcPin<T>,
|
||||
P: crate::gpio::sealed::Pin,
|
||||
{
|
||||
pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
|
||||
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
|
||||
let channel = pin.channel();
|
||||
|
||||
// Select channel
|
||||
T::regs().sqr3().write(|reg| reg.set_sq(0, channel));
|
||||
@ -199,9 +186,7 @@ where
|
||||
// Configure channel
|
||||
Self::set_channel_sample_time(channel, self.sample_time);
|
||||
|
||||
let val = self.convert();
|
||||
|
||||
val
|
||||
self.convert()
|
||||
}
|
||||
|
||||
fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
|
||||
@ -216,6 +201,10 @@ where
|
||||
|
||||
impl<'d, T: Instance> Drop for Adc<'d, T> {
|
||||
fn drop(&mut self) {
|
||||
T::regs().cr2().modify(|reg| {
|
||||
reg.set_adon(false);
|
||||
});
|
||||
|
||||
T::disable();
|
||||
}
|
||||
}
|
||||
|
@ -9,19 +9,6 @@ pub const VREF_DEFAULT_MV: u32 = 3300;
|
||||
/// VREF voltage used for factory calibration of VREFINTCAL register.
|
||||
pub const VREF_CALIB_MV: u32 = 3000;
|
||||
|
||||
/// Sadly we cannot use `RccPeripheral::enable` since devices are quite inconsistent ADC clock
|
||||
/// configuration.
|
||||
fn enable() {
|
||||
critical_section::with(|_| {
|
||||
#[cfg(any(stm32h7, stm32wl))]
|
||||
crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true));
|
||||
#[cfg(stm32g0)]
|
||||
crate::pac::RCC.apbenr2().modify(|w| w.set_adcen(true));
|
||||
#[cfg(any(stm32l4, stm32l5, stm32wb))]
|
||||
crate::pac::RCC.ahb2enr().modify(|w| w.set_adcen(true));
|
||||
});
|
||||
}
|
||||
|
||||
pub struct VrefInt;
|
||||
impl<T: Instance> AdcPin<T> for VrefInt {}
|
||||
impl<T: Instance> super::sealed::AdcPin<T> for VrefInt {
|
||||
@ -61,7 +48,7 @@ impl<T: Instance> super::sealed::AdcPin<T> for Vbat {
|
||||
impl<'d, T: Instance> Adc<'d, T> {
|
||||
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
|
||||
into_ref!(adc);
|
||||
enable();
|
||||
T::enable_and_reset();
|
||||
T::regs().cr().modify(|reg| {
|
||||
#[cfg(not(adc_g0))]
|
||||
reg.set_deeppwd(false);
|
||||
|
@ -127,8 +127,7 @@ impl Prescaler {
|
||||
impl<'d, T: Instance> Adc<'d, T> {
|
||||
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u16>) -> Self {
|
||||
embassy_hal_internal::into_ref!(adc);
|
||||
T::enable();
|
||||
T::reset();
|
||||
T::enable_and_reset();
|
||||
|
||||
let prescaler = Prescaler::from_ker_ck(T::frequency());
|
||||
|
||||
|
@ -136,8 +136,7 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
rx.set_as_af(rx.af_num(), AFType::Input);
|
||||
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
||||
|
||||
T::enable();
|
||||
T::reset();
|
||||
T::enable_and_reset();
|
||||
|
||||
{
|
||||
use crate::pac::can::vals::{Errie, Fmpie, Tmeie};
|
||||
|
@ -16,9 +16,7 @@ impl<'d> Crc<'d> {
|
||||
|
||||
// Note: enable and reset come from RccPeripheral.
|
||||
// enable CRC clock in RCC.
|
||||
CRC::enable();
|
||||
// Reset CRC to default values.
|
||||
CRC::reset();
|
||||
CRC::enable_and_reset();
|
||||
// Peripheral the peripheral
|
||||
let mut instance = Self { _peri: peripheral };
|
||||
instance.reset();
|
||||
|
@ -69,16 +69,13 @@ impl<'d> Crc<'d> {
|
||||
/// Instantiates the CRC32 peripheral and initializes it to default values.
|
||||
pub fn new(peripheral: impl Peripheral<P = CRC> + 'd, config: Config) -> Self {
|
||||
// Note: enable and reset come from RccPeripheral.
|
||||
// enable CRC clock in RCC.
|
||||
CRC::enable();
|
||||
// Reset CRC to default values.
|
||||
CRC::reset();
|
||||
// reset to default values and enable CRC clock in RCC.
|
||||
CRC::enable_and_reset();
|
||||
into_ref!(peripheral);
|
||||
let mut instance = Self {
|
||||
_peripheral: peripheral,
|
||||
_config: config,
|
||||
};
|
||||
CRC::reset();
|
||||
instance.reconfigure();
|
||||
instance.reset();
|
||||
instance
|
||||
|
@ -11,7 +11,7 @@ use crate::{peripherals, Peripheral};
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
/// Curstom Errors
|
||||
/// Custom Errors
|
||||
pub enum Error {
|
||||
UnconfiguredChannel,
|
||||
InvalidValue,
|
||||
@ -255,8 +255,7 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
|
||||
) -> Self {
|
||||
pin.set_as_analog();
|
||||
into_ref!(peri, dma);
|
||||
T::enable();
|
||||
T::reset();
|
||||
T::enable_and_reset();
|
||||
|
||||
let mut dac = Self { _peri: peri, dma };
|
||||
|
||||
@ -366,8 +365,7 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
|
||||
) -> Self {
|
||||
pin.set_as_analog();
|
||||
into_ref!(_peri, dma);
|
||||
T::enable();
|
||||
T::reset();
|
||||
T::enable_and_reset();
|
||||
|
||||
let mut dac = Self {
|
||||
phantom: PhantomData,
|
||||
@ -483,8 +481,7 @@ impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> {
|
||||
pin_ch1.set_as_analog();
|
||||
pin_ch2.set_as_analog();
|
||||
into_ref!(peri, dma_ch1, dma_ch2);
|
||||
T::enable();
|
||||
T::reset();
|
||||
T::enable_and_reset();
|
||||
|
||||
let mut dac_ch1 = DacCh1 {
|
||||
_peri: peri,
|
||||
@ -563,35 +560,26 @@ pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
|
||||
|
||||
foreach_peripheral!(
|
||||
(dac, $inst:ident) => {
|
||||
// H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented
|
||||
#[cfg(rcc_h7)]
|
||||
impl crate::rcc::sealed::RccPeripheral for peripherals::$inst {
|
||||
fn frequency() -> crate::time::Hertz {
|
||||
critical_section::with(|_| unsafe { crate::rcc::get_freqs().apb1 })
|
||||
}
|
||||
// H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented
|
||||
#[cfg(any(rcc_h7, rcc_h7rm0433))]
|
||||
impl crate::rcc::sealed::RccPeripheral for peripherals::$inst {
|
||||
fn frequency() -> crate::time::Hertz {
|
||||
critical_section::with(|_| unsafe { crate::rcc::get_freqs().pclk1 })
|
||||
}
|
||||
|
||||
fn reset() {
|
||||
critical_section::with(|_| {
|
||||
crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true));
|
||||
crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false));
|
||||
})
|
||||
}
|
||||
fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) {
|
||||
crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true));
|
||||
crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false));
|
||||
crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true));
|
||||
}
|
||||
|
||||
fn enable() {
|
||||
critical_section::with(|_| {
|
||||
crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true));
|
||||
})
|
||||
}
|
||||
fn disable_with_cs(_cs: critical_section::CriticalSection) {
|
||||
crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false))
|
||||
}
|
||||
}
|
||||
|
||||
fn disable() {
|
||||
critical_section::with(|_| {
|
||||
crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(rcc_h7)]
|
||||
impl crate::rcc::RccPeripheral for peripherals::$inst {}
|
||||
#[cfg(any(rcc_h7, rcc_h7rm0433))]
|
||||
impl crate::rcc::RccPeripheral for peripherals::$inst {}
|
||||
|
||||
impl crate::dac::sealed::Instance for peripherals::$inst {
|
||||
fn regs() -> &'static crate::pac::dac::Dac {
|
||||
|
@ -330,8 +330,7 @@ where
|
||||
use_embedded_synchronization: bool,
|
||||
edm: u8,
|
||||
) -> Self {
|
||||
T::reset();
|
||||
T::enable();
|
||||
T::enable_and_reset();
|
||||
|
||||
peri.regs().cr().modify(|r| {
|
||||
r.set_cm(true); // disable continuous mode (snapshot mode)
|
||||
|
@ -2,10 +2,9 @@
|
||||
|
||||
use core::future::Future;
|
||||
use core::pin::Pin;
|
||||
use core::sync::atomic::{fence, Ordering};
|
||||
use core::sync::atomic::{fence, AtomicUsize, Ordering};
|
||||
use core::task::{Context, Poll, Waker};
|
||||
|
||||
use atomic_polyfill::AtomicUsize;
|
||||
use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
@ -78,10 +77,10 @@ impl State {
|
||||
static STATE: State = State::new();
|
||||
|
||||
/// safety: must be called only once
|
||||
pub(crate) unsafe fn init(irq_priority: Priority) {
|
||||
pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: Priority) {
|
||||
foreach_interrupt! {
|
||||
($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => {
|
||||
crate::interrupt::typelevel::$irq::set_priority(irq_priority);
|
||||
crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, irq_priority);
|
||||
crate::interrupt::typelevel::$irq::enable();
|
||||
};
|
||||
}
|
||||
@ -127,7 +126,13 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::bdma::Dma, channel_num: usize, index
|
||||
} else if isr.tcif(channel_num) && cr.read().tcie() {
|
||||
// Acknowledge transfer complete interrupt
|
||||
dma.ifcr().write(|w| w.set_tcif(channel_num, true));
|
||||
#[cfg(not(armv6m))]
|
||||
STATE.complete_count[index].fetch_add(1, Ordering::Release);
|
||||
#[cfg(armv6m)]
|
||||
critical_section::with(|_| {
|
||||
let x = STATE.complete_count[index].load(Ordering::Relaxed);
|
||||
STATE.complete_count[index].store(x + 1, Ordering::Release);
|
||||
})
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
@ -391,7 +396,14 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
|
||||
}
|
||||
|
||||
fn reset_complete_count(&mut self) -> usize {
|
||||
STATE.complete_count[self.0.index()].swap(0, Ordering::AcqRel)
|
||||
#[cfg(not(armv6m))]
|
||||
return STATE.complete_count[self.0.index()].swap(0, Ordering::AcqRel);
|
||||
#[cfg(armv6m)]
|
||||
return critical_section::with(|_| {
|
||||
let x = STATE.complete_count[self.0.index()].load(Ordering::Acquire);
|
||||
STATE.complete_count[self.0.index()].store(0, Ordering::Release);
|
||||
x
|
||||
});
|
||||
}
|
||||
|
||||
fn set_waker(&mut self, waker: &Waker) {
|
||||
|
@ -154,10 +154,10 @@ impl State {
|
||||
static STATE: State = State::new();
|
||||
|
||||
/// safety: must be called only once
|
||||
pub(crate) unsafe fn init(irq_priority: Priority) {
|
||||
pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: Priority) {
|
||||
foreach_interrupt! {
|
||||
($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => {
|
||||
interrupt::typelevel::$irq::set_priority(irq_priority);
|
||||
interrupt::typelevel::$irq::set_priority_with_cs(cs, irq_priority);
|
||||
interrupt::typelevel::$irq::enable();
|
||||
};
|
||||
}
|
||||
|
@ -47,6 +47,6 @@ foreach_dma_channel! {
|
||||
}
|
||||
|
||||
/// safety: must be called only once
|
||||
pub(crate) unsafe fn init() {
|
||||
pub(crate) unsafe fn init(_cs: critical_section::CriticalSection) {
|
||||
crate::_generated::init_dmamux();
|
||||
}
|
||||
|
@ -53,10 +53,10 @@ impl State {
|
||||
static STATE: State = State::new();
|
||||
|
||||
/// safety: must be called only once
|
||||
pub(crate) unsafe fn init(irq_priority: Priority) {
|
||||
pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: Priority) {
|
||||
foreach_interrupt! {
|
||||
($peri:ident, gpdma, $block:ident, $signal_name:ident, $irq:ident) => {
|
||||
crate::interrupt::typelevel::$irq::set_priority(irq_priority);
|
||||
crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, irq_priority);
|
||||
crate::interrupt::typelevel::$irq::enable();
|
||||
};
|
||||
}
|
||||
|
@ -56,16 +56,17 @@ pub(crate) fn slice_ptr_parts_mut<T>(slice: *mut [T]) -> (usize, usize) {
|
||||
|
||||
// safety: must be called only once at startup
|
||||
pub(crate) unsafe fn init(
|
||||
cs: critical_section::CriticalSection,
|
||||
#[cfg(bdma)] bdma_priority: Priority,
|
||||
#[cfg(dma)] dma_priority: Priority,
|
||||
#[cfg(gpdma)] gpdma_priority: Priority,
|
||||
) {
|
||||
#[cfg(bdma)]
|
||||
bdma::init(bdma_priority);
|
||||
bdma::init(cs, bdma_priority);
|
||||
#[cfg(dma)]
|
||||
dma::init(dma_priority);
|
||||
dma::init(cs, dma_priority);
|
||||
#[cfg(gpdma)]
|
||||
gpdma::init(gpdma_priority);
|
||||
gpdma::init(cs, gpdma_priority);
|
||||
#[cfg(dmamux)]
|
||||
dmamux::init();
|
||||
dmamux::init(cs);
|
||||
}
|
||||
|
@ -41,39 +41,40 @@ mod phy_consts {
|
||||
}
|
||||
use self::phy_consts::*;
|
||||
|
||||
/// Generic SMI Ethernet PHY
|
||||
/// Generic SMI Ethernet PHY implementation
|
||||
pub struct GenericSMI {
|
||||
phy_addr: u8,
|
||||
#[cfg(feature = "time")]
|
||||
poll_interval: Duration,
|
||||
#[cfg(not(feature = "time"))]
|
||||
_private: (),
|
||||
}
|
||||
|
||||
impl GenericSMI {
|
||||
pub fn new() -> Self {
|
||||
/// Construct the PHY. It assumes the address `phy_addr` in the SMI communication
|
||||
pub fn new(phy_addr: u8) -> Self {
|
||||
Self {
|
||||
phy_addr,
|
||||
#[cfg(feature = "time")]
|
||||
poll_interval: Duration::from_millis(500),
|
||||
#[cfg(not(feature = "time"))]
|
||||
_private: (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl PHY for GenericSMI {
|
||||
/// Reset PHY and wait for it to come out of reset.
|
||||
fn phy_reset<S: StationManagement>(&mut self, sm: &mut S) {
|
||||
sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_RESET);
|
||||
while sm.smi_read(PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {}
|
||||
sm.smi_write(self.phy_addr, PHY_REG_BCR, PHY_REG_BCR_RESET);
|
||||
while sm.smi_read(self.phy_addr, PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {}
|
||||
}
|
||||
|
||||
/// PHY initialisation.
|
||||
fn phy_init<S: StationManagement>(&mut self, sm: &mut S) {
|
||||
// Clear WU CSR
|
||||
self.smi_write_ext(sm, PHY_REG_WUCSR, 0);
|
||||
|
||||
// Enable auto-negotiation
|
||||
sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_AN | PHY_REG_BCR_ANRST | PHY_REG_BCR_100M);
|
||||
sm.smi_write(
|
||||
self.phy_addr,
|
||||
PHY_REG_BCR,
|
||||
PHY_REG_BCR_AN | PHY_REG_BCR_ANRST | PHY_REG_BCR_100M,
|
||||
);
|
||||
}
|
||||
|
||||
fn poll_link<S: StationManagement>(&mut self, sm: &mut S, cx: &mut Context) -> bool {
|
||||
@ -83,7 +84,7 @@ unsafe impl PHY for GenericSMI {
|
||||
#[cfg(feature = "time")]
|
||||
let _ = Timer::after(self.poll_interval).poll_unpin(cx);
|
||||
|
||||
let bsr = sm.smi_read(PHY_REG_BSR);
|
||||
let bsr = sm.smi_read(self.phy_addr, PHY_REG_BSR);
|
||||
|
||||
// No link without autonegotiate
|
||||
if bsr & PHY_REG_BSR_ANDONE == 0 {
|
||||
@ -108,9 +109,9 @@ impl GenericSMI {
|
||||
|
||||
// Writes a value to an extended PHY register in MMD address space
|
||||
fn smi_write_ext<S: StationManagement>(&mut self, sm: &mut S, reg_addr: u16, reg_data: u16) {
|
||||
sm.smi_write(PHY_REG_CTL, 0x0003); // set address
|
||||
sm.smi_write(PHY_REG_ADDAR, reg_addr);
|
||||
sm.smi_write(PHY_REG_CTL, 0x4003); // set data
|
||||
sm.smi_write(PHY_REG_ADDAR, reg_data);
|
||||
sm.smi_write(self.phy_addr, PHY_REG_CTL, 0x0003); // set address
|
||||
sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_addr);
|
||||
sm.smi_write(self.phy_addr, PHY_REG_CTL, 0x4003); // set data
|
||||
sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_data);
|
||||
}
|
||||
}
|
||||
|
@ -134,9 +134,9 @@ impl<'a, 'd> embassy_net_driver::TxToken for TxToken<'a, 'd> {
|
||||
/// The methods cannot move out of self
|
||||
pub unsafe trait StationManagement {
|
||||
/// Read a register over SMI.
|
||||
fn smi_read(&mut self, reg: u8) -> u16;
|
||||
fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16;
|
||||
/// Write a register over SMI.
|
||||
fn smi_write(&mut self, reg: u8, val: u16);
|
||||
fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16);
|
||||
}
|
||||
|
||||
/// Traits for an Ethernet PHY
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user