Merge pull request #6 from embassy-rs/main

Update to embassy main
This commit is contained in:
Tyler 2023-10-14 17:22:19 -06:00 committed by GitHub
commit 7c6c3425c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
235 changed files with 4310 additions and 4628 deletions

115
ci.sh
View File

@ -1,9 +1,12 @@
#!/bin/bash #!/bin/bash
set -euo pipefail set -eo pipefail
export RUSTFLAGS=-Dwarnings export RUSTFLAGS=-Dwarnings
export DEFMT_LOG=trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info 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') 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-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,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 \
--- 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-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-ieee802154 \
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,medium-ieee802154 \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,medium-ieee802154 \
@ -66,49 +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 \
--- 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,intrinsics \
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,qspi-as-gpio \ --- 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,unstable-traits,time \
--- 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,exti,time-driver-any,time \
--- 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,time \
--- 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,time-driver-any,unstable-traits,time \
--- 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,time \
--- 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,exti,unstable-traits,time \
--- 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,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 \ --- 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 \ --- 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 \ --- 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 \ --- 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 \
--- 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,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 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,stm32f401ve,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,stm32f405zg,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,stm32f407zg,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,stm32f401ve,defmt,exti,time-driver-any,unstable-traits,time \
--- 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,stm32f405zg,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 \ --- 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,stm32h735zg,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f410tb,defmt,exti,time-driver-any,unstable-traits,time \
--- 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,stm32f411ce,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 \ --- 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,stm32l476vg,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,time \
--- 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,stm32f415zg,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 \ --- 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 thumbv6m-none-eabi --features nightly,stm32l072cz,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f423zh,defmt,exti,time-driver-any,unstable-traits,time \
--- 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 thumbv7em-none-eabi --features nightly,stm32f427zi,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 \ --- 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 thumbv7m-none-eabi --features nightly,stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits \ --- 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 thumbv7m-none-eabi --features nightly,stm32f398ve,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f439zi,defmt,exti,time-driver-any,unstable-traits,time \
--- 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 thumbv7em-none-eabi --features nightly,stm32f446ze,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 \ --- 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 thumbv7m-none-eabi --features nightly,stm32f217zg,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f479zi,defmt,exti,time-driver-any,unstable-traits,embedded-sdmmc,time \
--- 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 thumbv7em-none-eabi --features nightly,stm32f730i8,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 \ --- 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,stm32wle5jb,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h735zg,defmt,exti,time-driver-any,unstable-traits,time \
--- 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 thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,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 \ --- 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 thumbv7m-none-eabi --features nightly,stm32f103re,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,time \
--- 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 thumbv7em-none-eabi --features nightly,stm32l422cb,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 \ --- 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 thumbv7m-none-eabi --features nightly,stm32h562ag,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,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 ''\
--- 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 'log' \
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \
@ -178,12 +200,19 @@ cargo batch \
--- 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 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 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 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/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/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 --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \
$BUILD_EXTRA $BUILD_EXTRA
rm out/tests/nrf52840-dk/wifi_esp_hosted_perf
rm out/tests/stm32wb55rg/wpan_mac
rm out/tests/stm32wb55rg/wpan_ble
rm out/tests/stm32f207zg/eth
if [[ -z "${TELEPROBE_TOKEN-}" ]]; then if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
echo No teleprobe token found, skipping running HIL tests echo No teleprobe token found, skipping running HIL tests

View File

@ -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 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 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 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 stm32g473cc,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 \ --- 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 stm32f411ce,defmt,time-driver-any \ --- 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 stm32f411ce,defmt,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,time \
--- 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 stm32wl55cc-cm4,defmt,exti,time-driver-any,unstable-traits,time \
--- 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 stm32l4r9zi,defmt,exti,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 \ --- 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 stm32h755zi-cm7,defmt,time-driver-any,unstable-traits \ --- 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 stm32l476vg,defmt,time-driver-any \ --- 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 stm32l476vg,defmt,time-driver-any,unstable-traits \ --- 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 thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any \ --- 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 thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any,unstable-traits \ --- 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 thumbv7m-none-eabi --features stm32l151cb-a,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,time \
--- 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 stm32l476vg,defmt,time-driver-any,time \
--- 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 stm32l476vg,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,unstable-traits \ --- 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 thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any \ --- 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 thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,time-driver-any,time \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any \ --- 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 stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \ --- 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 stm32l476vg,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,time \
--- 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 thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,time \
--- 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 thumbv7em-none-eabi --features stm32f429zi,log,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,unstable-traits \ --- 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 thumbv7m-none-eabi --features stm32l151cb-a,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,time \
--- 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 thumbv7em-none-eabi --features stm32l476vg,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 \ --- 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 thumbv7m-none-eabi --features stm32f217zg,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,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/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 \ --- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --no-default-features --out-dir out/examples/stm32l0 --bin raw_spawn \

View File

@ -11,11 +11,10 @@ log = ["dep:log"]
firmware-logs = [] firmware-logs = []
[dependencies] [dependencies]
embassy-time = { version = "0.1.3", path = "../embassy-time"} embassy-time = { version = "0.1.4", path = "../embassy-time"}
embassy-sync = { version = "0.3.0", path = "../embassy-sync"} embassy-sync = { version = "0.3.0", path = "../embassy-sync"}
embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"} embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"}
atomic-polyfill = "0.1.5"
defmt = { version = "0.3", optional = true } defmt = { version = "0.3", optional = true }
log = { version = "0.4.17", optional = true } log = { version = "0.4.17", optional = true }

View File

@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
embassy-executor = { version = "0.3.0", path = "../../../../../embassy-executor", features = ["defmt", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] } 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"] } embassy-nrf = { version = "0.1.0", path = "../../../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "nightly"] }
defmt = "0.3" defmt = "0.3"

View File

@ -1,6 +1,6 @@
* xref:getting_started.adoc[Getting started] * xref:getting_started.adoc[Getting started]
** xref:basic_application.adoc[Basic application] ** xref:basic_application.adoc[Basic application]
** xref:layer_by_layer.adoc[Layer by Layer] * xref:layer_by_layer.adoc[Bare metal to async]
* xref:runtime.adoc[Executor] * xref:runtime.adoc[Executor]
* xref:hal.adoc[HAL] * xref:hal.adoc[HAL]
** xref:nrf.adoc[nRF] ** xref:nrf.adoc[nRF]

View File

@ -3,7 +3,7 @@
So you want to try Embassy, great! To get started, there are a few tools you need to install: So you want to try Embassy, great! To get started, there are a few tools you need to install:
* link:https://rustup.rs/[rustup] - the Rust toolchain is needed to compile Rust code. * link:https://rustup.rs/[rustup] - the Rust toolchain is needed to compile Rust code.
* link:https://crates.io/crates/probe-run[probe-run] - to flash the firmware on your device. If you already have other tools like `OpenOCD` setup, you can use that as well. * link:https://crates.io/crates/probe-rs[probe-rs] - to flash the firmware on your device. If you already have other tools like `OpenOCD` setup, you can use that as well.
If you don't have any supported board, don't worry: you can also run embassy on your PC using the `std` examples. If you don't have any supported board, don't worry: you can also run embassy on your PC using the `std` examples.
@ -30,6 +30,10 @@ Embassy supports many microcontroller families, but the easiest ways to get star
* link:https://www.raspberrypi.com/products/raspberry-pi-pico/[Raspberry Pi Pico] * link:https://www.raspberrypi.com/products/raspberry-pi-pico/[Raspberry Pi Pico]
=== ESP32
* link:https://github.com/esp-rs/esp-rust-board[ESP32C3]
== Running an example == Running an example
First you need to clone the [github repository]; First you need to clone the [github repository];
@ -38,7 +42,6 @@ First you need to clone the [github repository];
---- ----
git clone https://github.com/embassy-rs/embassy.git git clone https://github.com/embassy-rs/embassy.git
cd embassy cd embassy
git submodule update --init
---- ----
You can run an example by opening a terminal and entering the following commands: You can run an example by opening a terminal and entering the following commands:

View File

@ -7,4 +7,6 @@ Embassy provides HALs for several microcontroller families:
* `embassy-rp` for the Raspberry Pi RP2040 microcontrollers * `embassy-rp` for the Raspberry Pi RP2040 microcontrollers
These HALs implement async/await functionality for most peripherals while also implementing the These HALs implement async/await functionality for most peripherals while also implementing the
async traits in `embedded-hal-async`. You can also use these HALs with another executor. async traits in `embedded-hal` and `embedded-hal-async`. You can also use these HALs with another executor.
For the ESP32 series, there is an link:https://github.com/esp-rs/esp-hal[esp-hal] which you can use.

View File

@ -17,13 +17,26 @@ The Embassy project consists of several crates that you can use together or inde
* **Hardware Abstraction Layers** - HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. The Embassy project maintains HALs for select hardware, but you can still use HALs from other projects with Embassy. * **Hardware Abstraction Layers** - HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. The Embassy project maintains HALs for select hardware, but you can still use HALs from other projects with Embassy.
** link:https://docs.embassy.dev/embassy-stm32/[embassy-stm32], for all STM32 microcontroller families. ** link:https://docs.embassy.dev/embassy-stm32/[embassy-stm32], for all STM32 microcontroller families.
** link:https://docs.embassy.dev/embassy-nrf/[embassy-nrf], for the Nordic Semiconductor nRF52, nRF53, nRF91 series. ** link:https://docs.embassy.dev/embassy-nrf/[embassy-nrf], for the Nordic Semiconductor nRF52, nRF53, nRF91 series.
** link:https://docs.embassy.dev/embassy-rp/[embassy-rp], for the Raspberry Pi RP2040 microcontroller.
** link:https://github.com/esp-rs[esp-rs], for the Espressif Systems ESP32 series of chips.
+
NOTE: A common question is if one can use the Embassy HALs standalone. Yes, it is possible! There are no dependency on the executor within the HALs. You can even use them without async,
as they implement both the link:https://github.com/rust-embedded/embedded-hal[Embedded HAL] blocking and async traits.
* **Networking** - The link:https://docs.embassy.dev/embassy-net/[embassy-net] network stack implements extensive networking functionality, including Ethernet, IP, TCP, UDP, ICMP and DHCP. Async drastically simplifies managing timeouts and serving multiple connections concurrently. * **Networking** - The link:https://docs.embassy.dev/embassy-net/[embassy-net] network stack implements extensive networking functionality, including Ethernet, IP, TCP, UDP, ICMP and DHCP. Async drastically simplifies managing timeouts and serving multiple connections concurrently. Several drivers for WiFi and Ethernet chips can be found.
* **Bluetooth** - The link:https://github.com/embassy-rs/nrf-softdevice[nrf-softdevice] crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers. * **Bluetooth** - The link:https://github.com/embassy-rs/nrf-softdevice[nrf-softdevice] crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers.
* **LoRa** - link:https://docs.embassy.dev/embassy-lora/[embassy-lora] supports LoRa networking on STM32WL wireless microcontrollers and Semtech SX127x transceivers. * **LoRa** - link:https://github.com/embassy-rs/lora-phy[lora-phy] and link:https://docs.embassy.dev/embassy-lora/[embassy-lora] supports LoRa networking on a wide range of LoRa radios, fully integrated with a Rust link:https://github.com/ivajloip/rust-lorawan[LoRaWAN] implementation.
* **USB** - link:https://docs.embassy.dev/embassy-usb/[embassy-usb] implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own. * **USB** - link:https://docs.embassy.dev/embassy-usb/[embassy-usb] implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own.
* **Bootloader and DFU** - link:https://github.com/embassy-rs/embassy/tree/master/embassy-boot[embassy-boot] is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks. * **Bootloader and DFU** - link:https://github.com/embassy-rs/embassy/tree/master/embassy-boot[embassy-boot] is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks.
== Resources
For more reading material on async Rust and Embassy:
* link:https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown[Comparsion of FreeRTOS and Embassy]
* link:https://dev.to/apollolabsbin/series/20707[Tutorials]
* link:https://blog.drogue.io/firmware-updates-part-1/[Firmware Updates with Embassy]

View File

@ -1,4 +1,4 @@
= Embassy layer by layer = From bare metal to async Rust
If you're new to Embassy, it can be overwhelming to grasp all the terminology and concepts. This guide aims to clarify the different layers in Embassy, which problem each layer solves for the application writer. If you're new to Embassy, it can be overwhelming to grasp all the terminology and concepts. This guide aims to clarify the different layers in Embassy, which problem each layer solves for the application writer.
@ -8,8 +8,7 @@ The application we'll write is a simple 'push button, blink led' application, wh
== PAC version == PAC version
The PAC is the lowest API for accessing peripherals and registers, if you don't count reading/writing directly to memory addresses. It provides distinct types The PAC is the lowest API for accessing peripherals and registers, if you don't count reading/writing directly to memory addresses. It provides distinct types to make accessing peripheral registers easier, but it does not prevent you from writing unsafe code.
to make accessing peripheral registers easier, but it does not prevent you from writing unsafe code.
Writing an application using the PAC directly is therefore not recommended, but if the functionality you want to use is not exposed in the upper layers, that's what you need to use. Writing an application using the PAC directly is therefore not recommended, but if the functionality you want to use is not exposed in the upper layers, that's what you need to use.

View File

@ -8,7 +8,7 @@ The nRF timer driver operates at 32768 Hz by default.
== Peripherals == Peripherals
The following peripherals have a HAL implementation at present: The following peripherals have a HAL implementation at present
* PWM * PWM
* SPIM * SPIM
@ -23,3 +23,7 @@ The following peripherals have a HAL implementation at present:
* UARTE * UARTE
* TWIM * TWIM
* SAADC * SAADC
== Bluetooth
For bluetooth, you can use the link:https://github.com/embassy-rs/nrf-softdevice[nrf-softdevice] crate.

View File

@ -10,7 +10,7 @@ The Embassy executor is an async/await executor designed for embedded usage alon
* No busy-loop polling: CPU sleeps when there's no work to do, using interrupts or `WFE/SEV`. * No busy-loop polling: CPU sleeps when there's no work to do, using interrupts or `WFE/SEV`.
* Efficient polling: a wake will only poll the woken task, not all of them. * Efficient polling: a wake will only poll the woken task, not all of them.
* Fair: a task can't monopolize CPU time even if it's constantly being woken. All other tasks get a chance to run before a given task gets polled for the second time. * Fair: a task can't monopolize CPU time even if it's constantly being woken. All other tasks get a chance to run before a given task gets polled for the second time.
* Creating multiple executor instances is supported, to run tasks with multiple priority levels. This allows higher-priority tasks to preempt lower-priority tasks. * Creating multiple executor instances is supported, to run tasks at different priority levels. This allows higher-priority tasks to preempt lower-priority tasks.
== Executor == Executor

View File

@ -21,7 +21,7 @@ default = ["time"]
[dependencies] [dependencies]
embassy-futures = { version = "0.1.0", path = "../embassy-futures", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures", optional = true }
embassy-sync = { version = "0.3.0", path = "../embassy-sync" } embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true } embassy-time = { version = "0.1.4", path = "../embassy-time", optional = true }
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [ embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [
"unproven", "unproven",
] } ] }

View File

@ -11,7 +11,7 @@ pub use asynch::Partition;
pub use blocking::BlockingPartition; pub use blocking::BlockingPartition;
/// Partition error /// Partition error
#[derive(Debug)] #[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error<T> { pub enum Error<T> {
/// The requested flash area is outside the partition /// The requested flash area is outside the partition

View File

@ -1,5 +1,5 @@
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections, try_blocks))] #![cfg_attr(feature = "nightly", feature(async_fn_in_trait, try_blocks))]
#![warn(missing_docs)] #![warn(missing_docs)]
//! Utilities to use `embedded-hal` traits with Embassy. //! Utilities to use `embedded-hal` traits with Embassy.

View File

@ -59,7 +59,7 @@ rtos-trace = { version = "0.1.2", optional = true }
futures-util = { version = "0.3.17", default-features = false } futures-util = { version = "0.3.17", default-features = false }
embassy-macros = { version = "0.2.1", path = "../embassy-macros" } 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.4", path = "../embassy-time", optional = true}
atomic-polyfill = "1.0.1" atomic-polyfill = "1.0.1"
critical-section = "1.1" critical-section = "1.1"
static_cell = "1.1" static_cell = "1.1"

View File

@ -1,4 +1,4 @@
# embassy-macros # embassy-hal-internal
An [Embassy](https://embassy.dev) project. An [Embassy](https://embassy.dev) project.

View File

@ -4,6 +4,7 @@ use core::sync::atomic::{compiler_fence, Ordering};
use cortex_m::interrupt::InterruptNumber; use cortex_m::interrupt::InterruptNumber;
use cortex_m::peripheral::NVIC; use cortex_m::peripheral::NVIC;
use critical_section::CriticalSection;
/// Generate a standard `mod interrupt` for a HAL. /// Generate a standard `mod interrupt` for a HAL.
#[macro_export] #[macro_export]
@ -91,6 +92,12 @@ macro_rules! interrupt_mod {
fn set_priority(prio: crate::interrupt::Priority) { fn set_priority(prio: crate::interrupt::Priority) {
Self::IRQ.set_priority(prio) 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. /// Set the interrupt priority.
#[inline] #[inline]
fn set_priority(self, prio: Priority) { fn set_priority(self, prio: Priority) {
critical_section::with(|_| unsafe { unsafe {
let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(()); 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());
}
} }
} }

View File

@ -10,7 +10,6 @@ pub mod drop;
mod macros; mod macros;
mod peripheral; mod peripheral;
pub mod ratio; pub mod ratio;
pub mod ring_buffer;
pub use peripheral::{Peripheral, PeripheralRef}; pub use peripheral::{Peripheral, PeripheralRef};
#[cfg(feature = "cortex-m")] #[cfg(feature = "cortex-m")]

View File

@ -48,17 +48,23 @@ macro_rules! peripherals_struct {
///Returns all the peripherals *once* ///Returns all the peripherals *once*
#[inline] #[inline]
pub(crate) fn take() -> Self { 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] #[no_mangle]
static mut _EMBASSY_DEVICE_PERIPHERALS: bool = false; static mut _EMBASSY_DEVICE_PERIPHERALS: bool = false;
critical_section::with(|_| unsafe { // safety: OK because we're inside a CS.
unsafe {
if _EMBASSY_DEVICE_PERIPHERALS { if _EMBASSY_DEVICE_PERIPHERALS {
panic!("init called more than once!") panic!("init called more than once!")
} }
_EMBASSY_DEVICE_PERIPHERALS = true; _EMBASSY_DEVICE_PERIPHERALS = true;
Self::steal() Self::steal()
}) }
} }
} }

View File

@ -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());
}
}

View File

@ -20,7 +20,7 @@ defmt = ["dep:defmt", "lorawan-device/defmt"]
defmt = { version = "0.3", optional = true } defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true } log = { version = "0.4.14", optional = true }
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true } embassy-time = { version = "0.1.4", path = "../embassy-time", optional = true }
embassy-sync = { version = "0.3.0", path = "../embassy-sync" } embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true } embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true }
embedded-hal-async = { version = "=1.0.0-rc.1" } embedded-hal-async = { version = "=1.0.0-rc.1" }

View File

@ -1,5 +1,5 @@
#![no_std] #![no_std]
#![feature(async_fn_in_trait, impl_trait_projections)] #![feature(async_fn_in_trait)]
//! embassy-lora holds LoRa-specific functionality. //! embassy-lora holds LoRa-specific functionality.
pub(crate) mod fmt; pub(crate) mod fmt;

View File

@ -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-async = { version = "=1.0.0-rc.1" }
embedded-hal-bus = { version = "=0.1.0-rc.1", features = ["async"] } 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-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
embassy-time = { version = "0.1.3" } embassy-time = { version = "0.1.4", path = "../embassy-time" }
embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
bitfield = "0.14.0" bitfield = "0.14.0"

View File

@ -11,7 +11,7 @@ edition = "2021"
embedded-hal = { version = "1.0.0-rc.1" } embedded-hal = { version = "1.0.0-rc.1" }
embedded-hal-async = { 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-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
embassy-time = { version = "0.1.3", path = "../embassy-time" } embassy-time = { version = "0.1.4", path = "../embassy-time" }
embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
defmt = { version = "0.3", optional = true } defmt = { version = "0.3", optional = true }

View File

@ -7,7 +7,7 @@ edition = "2021"
defmt = { version = "0.3", optional = true } defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true } log = { version = "0.4.14", optional = true }
embassy-time = { version = "0.1.3", path = "../embassy-time" } embassy-time = { version = "0.1.4", path = "../embassy-time" }
embassy-sync = { version = "0.3.0", path = "../embassy-sync"} embassy-sync = { version = "0.3.0", path = "../embassy-sync"}
embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"} embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"}

View File

@ -15,7 +15,7 @@ log = ["dep:log", "ppproto/log"]
defmt = { version = "0.3", optional = true } defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true } log = { version = "0.4.14", optional = true }
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-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
ppproto = { version = "0.1.2"} ppproto = { version = "0.1.2"}

View File

@ -11,7 +11,7 @@ use core::mem::MaybeUninit;
use embassy_futures::select::{select, Either}; use embassy_futures::select::{select, Either};
use embassy_net_driver_channel as ch; use embassy_net_driver_channel as ch;
use embassy_net_driver_channel::driver::LinkState; 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}; use ppproto::pppos::{BufferFullError, PPPoS, PPPoSAction};
pub use ppproto::{Config, Ipv4Status}; pub use ppproto::{Config, Ipv4Status};
@ -49,23 +49,12 @@ pub enum RunError<E> {
Read(E), Read(E),
/// Writing to the serial port failed. /// Writing to the serial port failed.
Write(E), Write(E),
/// Writing to the serial port wrote zero bytes, indicating it can't accept more data.
WriteZero,
/// Writing to the serial got EOF. /// Writing to the serial got EOF.
Eof, Eof,
/// PPP protocol was terminated by the peer /// PPP protocol was terminated by the peer
Terminated, 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> { impl<'d> Runner<'d> {
/// You must call this in a background task for the driver to operate. /// You must call this in a background task for the driver to operate.
/// ///
@ -125,7 +114,7 @@ impl<'d> Runner<'d> {
buf[..pkt.len()].copy_from_slice(pkt); buf[..pkt.len()].copy_from_slice(pkt);
rx_chan.rx_done(pkt.len()); 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(); let status = ppp.status();
@ -148,7 +137,7 @@ impl<'d> Runner<'d> {
} }
Either::Second(pkt) => { Either::Second(pkt) => {
match ppp.send(pkt, &mut tx_buf) { 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!(), Err(BufferFullError) => unreachable!(),
} }
tx_chan.tx_done(); tx_chan.tx_done();

View File

@ -11,7 +11,7 @@ edition = "2021"
embedded-hal = { version = "1.0.0-rc.1" } embedded-hal = { version = "1.0.0-rc.1" }
embedded-hal-async = { 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-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.4", path = "../embassy-time" }
embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
defmt = { version = "0.3", optional = true } defmt = { version = "0.3", optional = true }

View File

@ -33,6 +33,7 @@ udp = ["smoltcp/socket-udp"]
tcp = ["smoltcp/socket-tcp"] tcp = ["smoltcp/socket-tcp"]
dns = ["smoltcp/socket-dns", "smoltcp/proto-dns"] dns = ["smoltcp/socket-dns", "smoltcp/proto-dns"]
dhcpv4 = ["proto-ipv4", "medium-ethernet", "smoltcp/socket-dhcpv4"] dhcpv4 = ["proto-ipv4", "medium-ethernet", "smoltcp/socket-dhcpv4"]
dhcpv4-hostname = ["dhcpv4"]
proto-ipv4 = ["smoltcp/proto-ipv4"] proto-ipv4 = ["smoltcp/proto-ipv4"]
proto-ipv6 = ["smoltcp/proto-ipv6"] proto-ipv6 = ["smoltcp/proto-ipv6"]
medium-ethernet = ["smoltcp/medium-ethernet"] 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-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
embassy-time = { version = "0.1.3", path = "../embassy-time" } embassy-time = { version = "0.1.4", path = "../embassy-time" }
embassy-sync = { version = "0.3.0", path = "../embassy-sync" } embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
embedded-io-async = { version = "0.5.0", optional = true } embedded-io-async = { version = "0.6.0", optional = true }
managed = { version = "0.8.0", default-features = false, features = [ "map" ] } managed = { version = "0.8.0", default-features = false, features = [ "map" ] }
heapless = { version = "0.7.5", default-features = false } 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 } stable_deref_trait = { version = "1.2.0", default-features = false }
futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] } futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] }
atomic-pool = "1.0" atomic-pool = "1.0"
embedded-nal-async = { version = "0.5.0", optional = true } embedded-nal-async = { version = "0.6.0", optional = true }
atomic-polyfill = { version = "1.0" }

View File

@ -1,5 +1,5 @@
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections))] #![cfg_attr(feature = "nightly", feature(async_fn_in_trait))]
#![warn(missing_docs)] #![warn(missing_docs)]
#![doc = include_str!("../README.md")] #![doc = include_str!("../README.md")]
@ -39,7 +39,7 @@ use smoltcp::socket::dhcpv4::{self, RetryConfig};
pub use smoltcp::wire::EthernetAddress; pub use smoltcp::wire::EthernetAddress;
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154", feature = "medium-ip"))] #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154", feature = "medium-ip"))]
pub use smoltcp::wire::HardwareAddress; pub use smoltcp::wire::HardwareAddress;
#[cfg(feature = "udp")] #[cfg(any(feature = "udp", feature = "tcp"))]
pub use smoltcp::wire::IpListenEndpoint; pub use smoltcp::wire::IpListenEndpoint;
#[cfg(feature = "medium-ieee802154")] #[cfg(feature = "medium-ieee802154")]
pub use smoltcp::wire::{Ieee802154Address, Ieee802154Frame}; pub use smoltcp::wire::{Ieee802154Address, Ieee802154Frame};
@ -56,12 +56,22 @@ const LOCAL_PORT_MIN: u16 = 1025;
const LOCAL_PORT_MAX: u16 = 65535; const LOCAL_PORT_MAX: u16 = 65535;
#[cfg(feature = "dns")] #[cfg(feature = "dns")]
const MAX_QUERIES: usize = 4; const MAX_QUERIES: usize = 4;
#[cfg(feature = "dhcpv4-hostname")]
const MAX_HOSTNAME_LEN: usize = 32;
/// Memory resources needed for a network stack. /// Memory resources needed for a network stack.
pub struct StackResources<const SOCK: usize> { pub struct StackResources<const SOCK: usize> {
sockets: [SocketStorage<'static>; SOCK], sockets: [SocketStorage<'static>; SOCK],
#[cfg(feature = "dns")] #[cfg(feature = "dns")]
queries: [Option<dns::DnsQuery>; MAX_QUERIES], 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> { impl<const SOCK: usize> StackResources<SOCK> {
@ -73,6 +83,11 @@ impl<const SOCK: usize> StackResources<SOCK> {
sockets: [SocketStorage::EMPTY; SOCK], sockets: [SocketStorage::EMPTY; SOCK],
#[cfg(feature = "dns")] #[cfg(feature = "dns")]
queries: [INIT; MAX_QUERIES], 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. /// DHCP configuration.
#[cfg(feature = "dhcpv4")] #[cfg(feature = "dhcpv4")]
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct DhcpConfig { pub struct DhcpConfig {
/// Maximum lease duration. /// Maximum lease duration.
/// ///
@ -120,6 +136,9 @@ pub struct DhcpConfig {
pub server_port: u16, pub server_port: u16,
/// Client port. This is almost always 68. Do not change unless you know what you're doing. /// Client port. This is almost always 68. Do not change unless you know what you're doing.
pub client_port: u16, 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")] #[cfg(feature = "dhcpv4")]
@ -131,6 +150,8 @@ impl Default for DhcpConfig {
ignore_naks: Default::default(), ignore_naks: Default::default(),
server_port: smoltcp::wire::DHCP_SERVER_PORT, server_port: smoltcp::wire::DHCP_SERVER_PORT,
client_port: smoltcp::wire::DHCP_CLIENT_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, dns_socket: SocketHandle,
#[cfg(feature = "dns")] #[cfg(feature = "dns")]
dns_waker: WakerRegistration, dns_waker: WakerRegistration,
#[cfg(feature = "dhcpv4-hostname")]
hostname: &'static mut core::cell::UnsafeCell<HostnameResources>,
} }
pub(crate) struct SocketStack { pub(crate) struct SocketStack {
@ -307,6 +330,8 @@ impl<D: Driver> Stack<D> {
)), )),
#[cfg(feature = "dns")] #[cfg(feature = "dns")]
dns_waker: WakerRegistration::new(), dns_waker: WakerRegistration::new(),
#[cfg(feature = "dhcpv4-hostname")]
hostname: &mut resources.hostname,
}; };
#[cfg(feature = "proto-ipv4")] #[cfg(feature = "proto-ipv4")]
@ -484,7 +509,10 @@ impl<D: Driver> Stack<D> {
self.with_mut(|s, i| { self.with_mut(|s, i| {
let socket = s.sockets.get_mut::<dns::Socket>(i.dns_socket); let socket = s.sockets.get_mut::<dns::Socket>(i.dns_socket);
match socket.start_query(s.iface.context(), name, qtype) { 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) => { Err(dns::StartQueryError::NoFreeSlot) => {
i.dns_waker.register(cx.waker()); i.dns_waker.register(cx.waker());
Poll::Pending Poll::Pending
@ -673,6 +701,25 @@ impl<D: Driver> Inner<D> {
socket.set_max_lease_duration(c.max_lease_duration.map(crate::time::duration_to_smoltcp)); 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_ports(c.server_port, c.client_port);
socket.set_retry_config(c.retry_config); 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(); socket.reset();
} }
_ => { _ => {

View File

@ -579,11 +579,10 @@ mod embedded_io_impls {
/// TCP client compatible with `embedded-nal-async` traits. /// TCP client compatible with `embedded-nal-async` traits.
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
pub mod client { pub mod client {
use core::cell::UnsafeCell; use core::cell::{Cell, UnsafeCell};
use core::mem::MaybeUninit; use core::mem::MaybeUninit;
use core::ptr::NonNull; use core::ptr::NonNull;
use atomic_polyfill::{AtomicBool, Ordering};
use embedded_nal_async::IpAddr; use embedded_nal_async::IpAddr;
use super::*; 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> { struct Pool<T, const N: usize> {
used: [AtomicBool; N], used: [Cell<bool>; N],
data: [UnsafeCell<MaybeUninit<T>>; N], data: [UnsafeCell<MaybeUninit<T>>; N],
} }
impl<T, const N: usize> Pool<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 UNINIT: UnsafeCell<MaybeUninit<T>> = UnsafeCell::new(MaybeUninit::uninit());
const fn new() -> Self { const fn new() -> Self {
@ -724,7 +721,9 @@ pub mod client {
impl<T, const N: usize> Pool<T, N> { impl<T, const N: usize> Pool<T, N> {
fn alloc(&self) -> Option<NonNull<T>> { fn alloc(&self) -> Option<NonNull<T>> {
for n in 0..N { 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; let p = self.data[n].get() as *mut T;
return Some(unsafe { NonNull::new_unchecked(p) }); return Some(unsafe { NonNull::new_unchecked(p) });
} }
@ -738,7 +737,7 @@ pub mod client {
let n = p.as_ptr().offset_from(origin); let n = p.as_ptr().offset_from(origin);
assert!(n >= 0); assert!(n >= 0);
assert!((n as usize) < N); assert!((n as usize) < N);
self.used[n as usize].store(false, Ordering::SeqCst); self.used[n as usize].set(false);
} }
} }
} }

View File

@ -94,7 +94,7 @@ _gpio-p1 = []
_nrf52832_anomaly_109 = [] _nrf52832_anomaly_109 = []
[dependencies] [dependencies]
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true } embassy-time = { version = "0.1.4", path = "../embassy-time", optional = true }
embassy-sync = { version = "0.3.0", path = "../embassy-sync" } embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] }
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
@ -103,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-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-1 = { package = "embedded-hal", version = "=1.0.0-rc.1", optional = true}
embedded-hal-async = { 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 = { version = "0.6.0" }
embedded-io-async = { version = "0.5.0", optional = true } embedded-io-async = { version = "0.6.0", optional = true }
defmt = { version = "0.3", optional = true } defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true } log = { version = "0.4.14", optional = true }

View File

@ -1,5 +1,5 @@
#![no_std] #![no_std]
#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections))] #![cfg_attr(feature = "nightly", feature(async_fn_in_trait))]
#![doc = include_str!("../README.md")] #![doc = include_str!("../README.md")]
#![warn(missing_docs)] #![warn(missing_docs)]

View File

@ -60,7 +60,7 @@ unstable-traits = ["embedded-hal-1", "embedded-hal-nb"]
[dependencies] [dependencies]
embassy-sync = { version = "0.3.0", path = "../embassy-sync" } embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
embassy-time = { version = "0.1.3", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] } embassy-time = { version = "0.1.4", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] }
embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] }
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
@ -75,8 +75,8 @@ cortex-m = "0.7.6"
critical-section = "1.1" critical-section = "1.1"
futures = { version = "0.3.17", default-features = false, features = ["async-await"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
chrono = { version = "0.4", default-features = false, optional = true } chrono = { version = "0.4", default-features = false, optional = true }
embedded-io = { version = "0.5.0" } embedded-io = { version = "0.6.0" }
embedded-io-async = { version = "0.5.0", optional = true } embedded-io-async = { version = "0.6.0", optional = true }
embedded-storage = { version = "0.3" } embedded-storage = { version = "0.3" }
embedded-storage-async = { version = "0.4.0", optional = true } embedded-storage-async = { version = "0.4.0", optional = true }
rand_core = "0.6.4" rand_core = "0.6.4"

83
embassy-rp/src/bootsel.rs Normal file
View 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!()
}
}

View File

@ -131,7 +131,7 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI
let len = to - from; 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(()) 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; 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; 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 { if bytes.as_ptr() as usize >= 0x2000_0000 {
let aligned_data = &bytes[start_padding..end_padding]; 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 { } else {
for chunk in bytes[start_padding..end_padding].chunks_exact(PAGE_SIZE) { for chunk in bytes[start_padding..end_padding].chunks_exact(PAGE_SIZE) {
let mut ram_buf = [0xFF_u8; PAGE_SIZE]; let mut ram_buf = [0xFF_u8; PAGE_SIZE];
ram_buf.copy_from_slice(chunk); 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; 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); 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(()) 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 /// Read SPI flash unique ID
pub fn blocking_unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> { 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(()) 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> { pub fn blocking_jedec_id(&mut self) -> Result<u32, Error> {
let mut jedec = None; let mut jedec = None;
unsafe { unsafe {
self.in_ram(|| { in_ram(|| {
jedec.replace(ram_helpers::flash_jedec_id()); 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 { mod sealed {
pub trait Instance {} pub trait Instance {}
pub trait Mode {} pub trait Mode {}

View File

@ -97,6 +97,12 @@ impl<'d, T: Pin> Input<'d, T> {
Self { pin } Self { pin }
} }
/// Set the pin's Schmitt trigger.
#[inline]
pub fn set_schmitt(&mut self, enable: bool) {
self.pin.set_schmitt(enable)
}
#[inline] #[inline]
pub fn is_high(&self) -> bool { pub fn is_high(&self) -> bool {
self.pin.is_high() self.pin.is_high()
@ -216,7 +222,6 @@ fn IO_IRQ_QSPI() {
#[must_use = "futures do nothing unless you `.await` or poll them"] #[must_use = "futures do nothing unless you `.await` or poll them"]
struct InputFuture<'a, T: Pin> { struct InputFuture<'a, T: Pin> {
pin: PeripheralRef<'a, T>, pin: PeripheralRef<'a, T>,
level: InterruptTrigger,
} }
impl<'d, T: Pin> InputFuture<'d, T> { impl<'d, T: Pin> InputFuture<'d, T> {
@ -243,7 +248,6 @@ impl<'d, T: Pin> InputFuture<'d, T> {
.inte((pin.pin() / 8) as usize) .inte((pin.pin() / 8) as usize)
.write_set(|w| match level { .write_set(|w| match level {
InterruptTrigger::LevelHigh => { InterruptTrigger::LevelHigh => {
trace!("InputFuture::new enable LevelHigh for pin {}", pin.pin());
w.set_level_high(pin_group, true); w.set_level_high(pin_group, true);
} }
InterruptTrigger::LevelLow => { InterruptTrigger::LevelLow => {
@ -261,7 +265,7 @@ impl<'d, T: Pin> InputFuture<'d, T> {
} }
}); });
Self { pin, level } Self { pin }
} }
} }
@ -297,14 +301,8 @@ impl<'d, T: Pin> Future for InputFuture<'d, T> {
&& !inte.level_high(pin_group) && !inte.level_high(pin_group)
&& !inte.level_low(pin_group) && !inte.level_low(pin_group)
{ {
trace!(
"{:?} for pin {} was cleared, return Poll::Ready",
self.level,
self.pin.pin()
);
return Poll::Ready(()); return Poll::Ready(());
} }
trace!("InputFuture::poll return Poll::Pending");
Poll::Pending Poll::Pending
} }
} }
@ -326,6 +324,18 @@ impl<'d, T: Pin> Output<'d, T> {
Self { pin } Self { pin }
} }
/// Set the pin's drive strength.
#[inline]
pub fn set_drive_strength(&mut self, strength: Drive) {
self.pin.set_drive_strength(strength)
}
// Set the pin's slew rate.
#[inline]
pub fn set_slew_rate(&mut self, slew_rate: SlewRate) {
self.pin.set_slew_rate(slew_rate)
}
/// Set the output as high. /// Set the output as high.
#[inline] #[inline]
pub fn set_high(&mut self) { pub fn set_high(&mut self) {
@ -386,6 +396,18 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
Self { pin } Self { pin }
} }
/// Set the pin's drive strength.
#[inline]
pub fn set_drive_strength(&mut self, strength: Drive) {
self.pin.set_drive_strength(strength)
}
// Set the pin's slew rate.
#[inline]
pub fn set_slew_rate(&mut self, slew_rate: SlewRate) {
self.pin.set_slew_rate(slew_rate)
}
/// Set the output as high. /// Set the output as high.
#[inline] #[inline]
pub fn set_high(&mut self) { pub fn set_high(&mut self) {
@ -541,6 +563,14 @@ impl<'d, T: Pin> Flex<'d, T> {
}); });
} }
/// Set the pin's Schmitt trigger.
#[inline]
pub fn set_schmitt(&mut self, enable: bool) {
self.pin.pad_ctrl().modify(|w| {
w.set_schmitt(enable);
});
}
/// Put the pin into input mode. /// Put the pin into input mode.
/// ///
/// The pull setting is left unchanged. /// The pull setting is left unchanged.

View File

@ -6,13 +6,12 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
use pac::i2c; use pac::i2c;
use crate::gpio::sealed::Pin;
use crate::gpio::AnyPin; use crate::gpio::AnyPin;
use crate::interrupt::typelevel::{Binding, Interrupt}; use crate::interrupt::typelevel::{Binding, Interrupt};
use crate::{interrupt, pac, peripherals, Peripheral}; use crate::{interrupt, pac, peripherals, Peripheral};
/// I2C error abort reason /// I2C error abort reason
#[derive(Debug)] #[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum AbortReason { pub enum AbortReason {
/// A bus operation was not acknowledged, e.g. due to the addressed device /// A bus operation was not acknowledged, e.g. due to the addressed device
@ -27,7 +26,7 @@ pub enum AbortReason {
} }
/// I2C error /// I2C error
#[derive(Debug)] #[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error { pub enum Error {
/// I2C abort with 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> { pub async fn read_async(&mut self, addr: u16, buffer: &mut [u8]) -> Result<(), Error> {
Self::setup(addr)?; 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> { pub async fn write_async(&mut self, addr: u16, bytes: impl IntoIterator<Item = u8>) -> Result<(), Error> {
Self::setup(addr)?; Self::setup(addr)?;
self.write_async_internal(bytes, true).await 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> { 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> { impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
fn new_inner( fn new_inner(
_peri: impl Peripheral<P = T> + 'd, _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)); p.ic_rx_tl().write(|w| w.set_rx_tl(0));
// Configure SCL & SDA pins // Configure SCL & SDA pins
scl.gpio().ctrl().write(|w| w.set_funcsel(3)); set_up_i2c_pin(&scl);
sda.gpio().ctrl().write(|w| w.set_funcsel(3)); set_up_i2c_pin(&sda);
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);
});
// Configure baudrate // Configure baudrate
@ -713,7 +724,7 @@ mod nightly {
Self::setup(addr)?; Self::setup(addr)?;
self.write_async_internal(write.iter().cloned(), false).await?; 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> { async fn transaction(&mut self, address: A, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> {

View File

@ -5,12 +5,14 @@ use core::task::Poll;
use embassy_hal_internal::into_ref; use embassy_hal_internal::into_ref;
use pac::i2c; 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::interrupt::typelevel::{Binding, Interrupt};
use crate::{pac, Peripheral}; use crate::{pac, Peripheral};
/// I2C error /// I2C error
#[derive(Debug)] #[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive] #[non_exhaustive]
pub enum Error { 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)); p.ic_rx_tl().write(|w| w.set_rx_tl(0));
// Configure SCL & SDA pins // Configure SCL & SDA pins
scl.gpio().ctrl().write(|w| w.set_funcsel(3)); set_up_i2c_pin(&scl);
sda.gpio().ctrl().write(|w| w.set_funcsel(3)); set_up_i2c_pin(&sda);
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);
});
// Clear interrupts // Clear interrupts
p.ic_clr_intr().read(); p.ic_clr_intr().read();

View File

@ -1,5 +1,5 @@
#![no_std] #![no_std]
#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections))] #![cfg_attr(feature = "nightly", feature(async_fn_in_trait))]
// This mod MUST go first, so that the others see its macros. // This mod MUST go first, so that the others see its macros.
pub(crate) mod fmt; pub(crate) mod fmt;
@ -10,6 +10,7 @@ mod critical_section_impl;
mod intrinsics; mod intrinsics;
pub mod adc; pub mod adc;
pub mod bootsel;
pub mod clocks; pub mod clocks;
pub mod dma; pub mod dma;
pub mod flash; pub mod flash;
@ -193,6 +194,7 @@ embassy_hal_internal::peripherals! {
PIO1, PIO1,
WATCHDOG, WATCHDOG,
BOOTSEL,
} }
macro_rules! select_bootloader { macro_rules! select_bootloader {

View File

@ -490,8 +490,6 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for BufferedInterr
w.set_oeic(ris.oeris()); w.set_oeic(ris.oeris());
}); });
trace!("on_interrupt ris={:#X}", ris.0);
// Errors // Errors
if ris.feris() { if ris.feris() {
warn!("Framing error"); warn!("Framing error");

View File

@ -13,7 +13,7 @@ features = ["stm32wb55rg"]
[dependencies] [dependencies]
embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" } embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" }
embassy-sync = { version = "0.3.0", path = "../embassy-sync" } embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true } embassy-time = { version = "0.1.4", path = "../embassy-time", optional = true }
embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
embassy-hal-internal = { version = "0.1.0", path = "../embassy-hal-internal" } embassy-hal-internal = { version = "0.1.0", path = "../embassy-hal-internal" }
embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" }

View File

@ -33,7 +33,7 @@ flavors = [
[dependencies] [dependencies]
embassy-sync = { version = "0.3.0", path = "../embassy-sync" } embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true } embassy-time = { version = "0.1.4", path = "../embassy-time", optional = true }
embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] }
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
@ -58,16 +58,14 @@ rand_core = "0.6.3"
sdio-host = "0.5.0" sdio-host = "0.5.0"
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
critical-section = "1.1" critical-section = "1.1"
atomic-polyfill = "1.0.1" stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e6e51db6cdd7d533e52ca7a3237f7816a0486cd4" }
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8ee2862086886cd8ebaf5fd5e3bd6cfbe5baa840" }
vcell = "0.1.3" vcell = "0.1.3"
bxcan = "0.7.0" bxcan = "0.7.0"
nb = "1.0.0" nb = "1.0.0"
stm32-fmc = "0.3.0" stm32-fmc = "0.3.0"
seq-macro = "0.3.0"
cfg-if = "1.0.0" cfg-if = "1.0.0"
embedded-io = { version = "0.5.0" } embedded-io = { version = "0.6.0" }
embedded-io-async = { version = "0.5.0", optional = true } embedded-io-async = { version = "0.6.0", optional = true }
chrono = { version = "^0.4", default-features = false, optional = true} chrono = { version = "^0.4", default-features = false, optional = true}
bit_field = "0.10.2" bit_field = "0.10.2"
document-features = "0.2.7" document-features = "0.2.7"
@ -78,7 +76,7 @@ critical-section = { version = "1.1", features = ["std"] }
[build-dependencies] [build-dependencies]
proc-macro2 = "1.0.36" proc-macro2 = "1.0.36"
quote = "1.0.15" quote = "1.0.15"
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8ee2862086886cd8ebaf5fd5e3bd6cfbe5baa840", default-features = false, features = ["metadata"]} stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e6e51db6cdd7d533e52ca7a3237f7816a0486cd4", default-features = false, features = ["metadata"]}
[features] [features]

View File

@ -5,9 +5,36 @@ use std::{env, fs};
use proc_macro2::{Ident, TokenStream}; use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote}; 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() { 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() let chip_name = match env::vars()
.map(|(a, _)| a) .map(|(a, _)| a)
.filter(|x| x.starts_with("CARGO_FEATURE_STM32")) .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 // We *shouldn't* have singletons for these, but the HAL currently requires
// singletons, for using with RccPeripheral to enable/disable clocks to them. // singletons, for using with RccPeripheral to enable/disable clocks to them.
"rcc" => { "rcc" => {
if r.version.starts_with("h5") || r.version.starts_with("h7") || r.version.starts_with("f4") { for pin in p.pins {
singletons.push("MCO1".to_string()); if pin.signal.starts_with("MCO") {
singletons.push("MCO2".to_string()); let name = pin.signal.replace('_', "").to_string();
} if !singletons.contains(&name) {
if r.version.starts_with("l4") { println!("cargo:rustc-cfg={}", name.to_ascii_lowercase());
singletons.push("MCO".to_string()); singletons.push(name);
}
}
} }
singletons.push(p.name.to_string()); singletons.push(p.name.to_string());
} }
@ -359,6 +388,46 @@ fn main() {
}); });
} }
// ========
// Generate rcc fieldset and enum maps
let rcc_enum_map: HashMap<&str, HashMap<&str, &Enum>> = {
let rcc_registers = METADATA
.peripherals
.iter()
.filter_map(|p| p.registers.as_ref())
.find(|r| r.kind == "rcc")
.unwrap()
.ir;
let rcc_blocks = rcc_registers.blocks.iter().find(|b| b.name == "Rcc").unwrap().items;
let rcc_fieldsets: HashMap<&str, &FieldSet> = rcc_registers.fieldsets.iter().map(|f| (f.name, f)).collect();
let rcc_enums: HashMap<&str, &Enum> = rcc_registers.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 // Generate RccPeripheral impls
@ -378,10 +447,8 @@ fn main() {
let rst_reg = format_ident!("{}", rst.register.to_ascii_lowercase()); let rst_reg = format_ident!("{}", rst.register.to_ascii_lowercase());
let set_rst_field = format_ident!("set_{}", rst.field.to_ascii_lowercase()); let set_rst_field = format_ident!("set_{}", rst.field.to_ascii_lowercase());
quote! { 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(true)); crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false));
crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false));
});
} }
} }
None => TokenStream::new(), None => TokenStream::new(),
@ -426,31 +493,82 @@ fn main() {
(TokenStream::new(), TokenStream::new()) (TokenStream::new(), TokenStream::new())
}; };
let mux_for = |mux: Option<&'static PeripheralRccRegister>| {
// temporary hack to restrict the scope of the implementation to h5
if !&chip_name.starts_with("stm32h5") {
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);
// temporary hack to restrict the scope of the implementation until clock names can be stabilized
let clock_name = format_ident!("{}", v.name.to_ascii_lowercase());
if v.name.starts_with("AHB") || v.name.starts_with("APB") {
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! { g.extend(quote! {
impl crate::rcc::sealed::RccPeripheral for peripherals::#pname { impl crate::rcc::sealed::RccPeripheral for peripherals::#pname {
fn frequency() -> crate::time::Hertz { fn frequency() -> crate::time::Hertz {
unsafe { crate::rcc::get_freqs().#clk } #clock_frequency
} }
fn enable() { fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) {
critical_section::with(|_| { #before_enable
#before_enable #[cfg(feature = "low-power")]
#[cfg(feature = "low-power")] crate::rcc::clock_refcount_add(_cs);
crate::rcc::clock_refcount_add(); crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true));
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); #after_enable
#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() {
#rst #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 {} impl crate::rcc::RccPeripheral for peripherals::#pname {}
@ -458,12 +576,14 @@ fn main() {
} }
} }
let mut refcount_mod = TokenStream::new(); let refcount_mod: TokenStream = refcount_statics
for refcount_static in refcount_statics { .iter()
refcount_mod.extend(quote! { .map(|refcount_static| {
pub(crate) static mut #refcount_static: u8 = 0; quote! {
}); pub(crate) static mut #refcount_static: u8 = 0;
} }
})
.collect();
g.extend(quote! { g.extend(quote! {
mod refcount_statics { mod refcount_statics {
@ -719,12 +839,17 @@ fn main() {
(("sdmmc", "D6"), quote!(crate::sdmmc::D6Pin)), (("sdmmc", "D6"), quote!(crate::sdmmc::D6Pin)),
(("sdmmc", "D6"), quote!(crate::sdmmc::D7Pin)), (("sdmmc", "D6"), quote!(crate::sdmmc::D7Pin)),
(("sdmmc", "D8"), quote!(crate::sdmmc::D8Pin)), (("sdmmc", "D8"), quote!(crate::sdmmc::D8Pin)),
(("quadspi", "BK1_IO0"), quote!(crate::qspi::D0Pin)), (("quadspi", "BK1_IO0"), quote!(crate::qspi::BK1D0Pin)),
(("quadspi", "BK1_IO1"), quote!(crate::qspi::D1Pin)), (("quadspi", "BK1_IO1"), quote!(crate::qspi::BK1D1Pin)),
(("quadspi", "BK1_IO2"), quote!(crate::qspi::D2Pin)), (("quadspi", "BK1_IO2"), quote!(crate::qspi::BK1D2Pin)),
(("quadspi", "BK1_IO3"), quote!(crate::qspi::D3Pin)), (("quadspi", "BK1_IO3"), quote!(crate::qspi::BK1D3Pin)),
(("quadspi", "BK1_NCS"), quote!(crate::qspi::BK1NSSPin)),
(("quadspi", "BK2_IO0"), quote!(crate::qspi::BK2D0Pin)),
(("quadspi", "BK2_IO1"), quote!(crate::qspi::BK2D1Pin)),
(("quadspi", "BK2_IO2"), quote!(crate::qspi::BK2D2Pin)),
(("quadspi", "BK2_IO3"), quote!(crate::qspi::BK2D3Pin)),
(("quadspi", "BK2_NCS"), quote!(crate::qspi::BK2NSSPin)),
(("quadspi", "CLK"), quote!(crate::qspi::SckPin)), (("quadspi", "CLK"), quote!(crate::qspi::SckPin)),
(("quadspi", "BK1_NCS"), quote!(crate::qspi::NSSPin)),
].into(); ].into();
for p in METADATA.peripherals { for p in METADATA.peripherals {
@ -746,25 +871,8 @@ fn main() {
let af = pin.af.unwrap_or(0); let af = pin.af.unwrap_or(0);
// MCO is special // MCO is special
if pin.signal.starts_with("MCO_") { if pin.signal.starts_with("MCO") {
// Supported in H7 only for now peri = format_ident!("{}", pin.signal.replace('_', ""));
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;
}
} }
g.extend(quote! { g.extend(quote! {
@ -805,6 +913,20 @@ fn main() {
} }
} }
if regs.kind == "opamp" {
if !pin.signal.starts_with("VP") {
continue;
}
let peri = format_ident!("{}", p.name);
let pin_name = format_ident!("{}", pin.pin);
let ch: u8 = pin.signal.strip_prefix("VP").unwrap().parse().unwrap();
g.extend(quote! {
impl_opamp_pin!( #peri, #pin_name, #ch);
})
}
// DAC is special // DAC is special
if regs.kind == "dac" { if regs.kind == "dac" {
let peri = format_ident!("{}", p.name); let peri = format_ident!("{}", p.name);
@ -889,6 +1011,105 @@ fn main() {
} }
} }
// ========
// Generate Div/Mul impls for RCC prescalers/dividers/multipliers.
let rcc_registers = METADATA
.peripherals
.iter()
.filter_map(|p| p.registers.as_ref())
.find(|r| r.kind == "rcc")
.unwrap()
.ir;
for e in rcc_registers.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 // Write foreach_foo! macrotables

View File

@ -51,8 +51,7 @@ impl<T: Instance> super::sealed::AdcPin<T> for Temperature {
impl<'d, T: Instance> Adc<'d, T> { impl<'d, T: Instance> Adc<'d, T> {
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self { pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
into_ref!(adc); into_ref!(adc);
T::enable(); T::enable_and_reset();
T::reset();
T::regs().cr2().modify(|reg| reg.set_adon(true)); 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) // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = 1)

View File

@ -64,8 +64,7 @@ impl<'d, T: Instance> Adc<'d, T> {
into_ref!(adc); into_ref!(adc);
T::enable(); T::enable_and_reset();
T::reset();
// Enable the adc regulator // Enable the adc regulator
T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE)); T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE));

View File

@ -74,9 +74,9 @@ 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> {} 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 Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {}
pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {} pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {}

View File

@ -61,8 +61,7 @@ impl<'d, T: Instance> Adc<'d, T> {
delay: &mut impl DelayUs<u32>, delay: &mut impl DelayUs<u32>,
) -> Self { ) -> Self {
into_ref!(adc); into_ref!(adc);
T::enable(); T::enable_and_reset();
T::reset();
// Delay 1μs when using HSI14 as the ADC clock. // Delay 1μs when using HSI14 as the ADC clock.
// //

View File

@ -95,8 +95,7 @@ where
{ {
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self { pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
into_ref!(adc); into_ref!(adc);
T::enable(); T::enable_and_reset();
T::reset();
let presc = Prescaler::from_pclk2(T::frequency()); let presc = Prescaler::from_pclk2(T::frequency());
T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre())); T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre()));

View File

@ -9,19 +9,6 @@ pub const VREF_DEFAULT_MV: u32 = 3300;
/// VREF voltage used for factory calibration of VREFINTCAL register. /// VREF voltage used for factory calibration of VREFINTCAL register.
pub const VREF_CALIB_MV: u32 = 3000; 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; pub struct VrefInt;
impl<T: Instance> AdcPin<T> for VrefInt {} impl<T: Instance> AdcPin<T> for VrefInt {}
impl<T: Instance> super::sealed::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> { 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, delay: &mut impl DelayUs<u32>) -> Self {
into_ref!(adc); into_ref!(adc);
enable(); T::enable_and_reset();
T::regs().cr().modify(|reg| { T::regs().cr().modify(|reg| {
#[cfg(not(adc_g0))] #[cfg(not(adc_g0))]
reg.set_deeppwd(false); reg.set_deeppwd(false);

View File

@ -127,8 +127,7 @@ impl Prescaler {
impl<'d, T: Instance> Adc<'d, T> { impl<'d, T: Instance> Adc<'d, T> {
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u16>) -> Self { pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u16>) -> Self {
embassy_hal_internal::into_ref!(adc); embassy_hal_internal::into_ref!(adc);
T::enable(); T::enable_and_reset();
T::reset();
let prescaler = Prescaler::from_ker_ck(T::frequency()); let prescaler = Prescaler::from_ker_ck(T::frequency());

View File

@ -136,8 +136,7 @@ impl<'d, T: Instance> Can<'d, T> {
rx.set_as_af(rx.af_num(), AFType::Input); rx.set_as_af(rx.af_num(), AFType::Input);
tx.set_as_af(tx.af_num(), AFType::OutputPushPull); tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
T::enable(); T::enable_and_reset();
T::reset();
{ {
use crate::pac::can::vals::{Errie, Fmpie, Tmeie}; use crate::pac::can::vals::{Errie, Fmpie, Tmeie};

View File

@ -16,9 +16,7 @@ impl<'d> Crc<'d> {
// Note: enable and reset come from RccPeripheral. // Note: enable and reset come from RccPeripheral.
// enable CRC clock in RCC. // enable CRC clock in RCC.
CRC::enable(); CRC::enable_and_reset();
// Reset CRC to default values.
CRC::reset();
// Peripheral the peripheral // Peripheral the peripheral
let mut instance = Self { _peri: peripheral }; let mut instance = Self { _peri: peripheral };
instance.reset(); instance.reset();

View File

@ -69,16 +69,13 @@ impl<'d> Crc<'d> {
/// Instantiates the CRC32 peripheral and initializes it to default values. /// Instantiates the CRC32 peripheral and initializes it to default values.
pub fn new(peripheral: impl Peripheral<P = CRC> + 'd, config: Config) -> Self { pub fn new(peripheral: impl Peripheral<P = CRC> + 'd, config: Config) -> Self {
// Note: enable and reset come from RccPeripheral. // Note: enable and reset come from RccPeripheral.
// enable CRC clock in RCC. // reset to default values and enable CRC clock in RCC.
CRC::enable(); CRC::enable_and_reset();
// Reset CRC to default values.
CRC::reset();
into_ref!(peripheral); into_ref!(peripheral);
let mut instance = Self { let mut instance = Self {
_peripheral: peripheral, _peripheral: peripheral,
_config: config, _config: config,
}; };
CRC::reset();
instance.reconfigure(); instance.reconfigure();
instance.reset(); instance.reset();
instance instance

View File

@ -11,7 +11,7 @@ use crate::{peripherals, Peripheral};
#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Curstom Errors /// Custom Errors
pub enum Error { pub enum Error {
UnconfiguredChannel, UnconfiguredChannel,
InvalidValue, InvalidValue,
@ -255,8 +255,7 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
) -> Self { ) -> Self {
pin.set_as_analog(); pin.set_as_analog();
into_ref!(peri, dma); into_ref!(peri, dma);
T::enable(); T::enable_and_reset();
T::reset();
let mut dac = Self { _peri: peri, dma }; let mut dac = Self { _peri: peri, dma };
@ -366,8 +365,7 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
) -> Self { ) -> Self {
pin.set_as_analog(); pin.set_as_analog();
into_ref!(_peri, dma); into_ref!(_peri, dma);
T::enable(); T::enable_and_reset();
T::reset();
let mut dac = Self { let mut dac = Self {
phantom: PhantomData, phantom: PhantomData,
@ -483,8 +481,7 @@ impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> {
pin_ch1.set_as_analog(); pin_ch1.set_as_analog();
pin_ch2.set_as_analog(); pin_ch2.set_as_analog();
into_ref!(peri, dma_ch1, dma_ch2); into_ref!(peri, dma_ch1, dma_ch2);
T::enable(); T::enable_and_reset();
T::reset();
let mut dac_ch1 = DacCh1 { let mut dac_ch1 = DacCh1 {
_peri: peri, _peri: peri,
@ -563,35 +560,26 @@ pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
foreach_peripheral!( foreach_peripheral!(
(dac, $inst:ident) => { (dac, $inst:ident) => {
// H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented // H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented
#[cfg(rcc_h7)] #[cfg(any(rcc_h7, rcc_h7rm0433))]
impl crate::rcc::sealed::RccPeripheral for peripherals::$inst { impl crate::rcc::sealed::RccPeripheral for peripherals::$inst {
fn frequency() -> crate::time::Hertz { fn frequency() -> crate::time::Hertz {
critical_section::with(|_| unsafe { crate::rcc::get_freqs().apb1 }) critical_section::with(|_| unsafe { crate::rcc::get_freqs().apb1 })
} }
fn reset() { fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) {
critical_section::with(|_| { crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true));
crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true)); crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false));
crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false)); crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true));
}) }
}
fn enable() { fn disable_with_cs(_cs: critical_section::CriticalSection) {
critical_section::with(|_| { crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false))
crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true)); }
}) }
}
fn disable() { #[cfg(any(rcc_h7, rcc_h7rm0433))]
critical_section::with(|_| { impl crate::rcc::RccPeripheral for peripherals::$inst {}
crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false))
})
}
}
#[cfg(rcc_h7)]
impl crate::rcc::RccPeripheral for peripherals::$inst {}
impl crate::dac::sealed::Instance for peripherals::$inst { impl crate::dac::sealed::Instance for peripherals::$inst {
fn regs() -> &'static crate::pac::dac::Dac { fn regs() -> &'static crate::pac::dac::Dac {

View File

@ -330,8 +330,7 @@ where
use_embedded_synchronization: bool, use_embedded_synchronization: bool,
edm: u8, edm: u8,
) -> Self { ) -> Self {
T::reset(); T::enable_and_reset();
T::enable();
peri.regs().cr().modify(|r| { peri.regs().cr().modify(|r| {
r.set_cm(true); // disable continuous mode (snapshot mode) r.set_cm(true); // disable continuous mode (snapshot mode)

View File

@ -2,10 +2,9 @@
use core::future::Future; use core::future::Future;
use core::pin::Pin; use core::pin::Pin;
use core::sync::atomic::{fence, Ordering}; use core::sync::atomic::{fence, AtomicUsize, Ordering};
use core::task::{Context, Poll, Waker}; use core::task::{Context, Poll, Waker};
use atomic_polyfill::AtomicUsize;
use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
@ -78,10 +77,10 @@ impl State {
static STATE: State = State::new(); static STATE: State = State::new();
/// safety: must be called only once /// 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! { foreach_interrupt! {
($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => { ($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(); 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() { } else if isr.tcif(channel_num) && cr.read().tcie() {
// Acknowledge transfer complete interrupt // Acknowledge transfer complete interrupt
dma.ifcr().write(|w| w.set_tcif(channel_num, true)); dma.ifcr().write(|w| w.set_tcif(channel_num, true));
#[cfg(not(armv6m))]
STATE.complete_count[index].fetch_add(1, Ordering::Release); 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 { } else {
return; return;
} }
@ -391,7 +396,14 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> {
} }
fn reset_complete_count(&mut self) -> usize { 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) { fn set_waker(&mut self, waker: &Waker) {

View File

@ -154,10 +154,10 @@ impl State {
static STATE: State = State::new(); static STATE: State = State::new();
/// safety: must be called only once /// 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! { foreach_interrupt! {
($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => { ($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(); interrupt::typelevel::$irq::enable();
}; };
} }

View File

@ -47,6 +47,6 @@ foreach_dma_channel! {
} }
/// safety: must be called only once /// safety: must be called only once
pub(crate) unsafe fn init() { pub(crate) unsafe fn init(_cs: critical_section::CriticalSection) {
crate::_generated::init_dmamux(); crate::_generated::init_dmamux();
} }

View File

@ -53,10 +53,10 @@ impl State {
static STATE: State = State::new(); static STATE: State = State::new();
/// safety: must be called only once /// 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! { foreach_interrupt! {
($peri:ident, gpdma, $block:ident, $signal_name:ident, $irq:ident) => { ($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(); crate::interrupt::typelevel::$irq::enable();
}; };
} }

View File

@ -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 // safety: must be called only once at startup
pub(crate) unsafe fn init( pub(crate) unsafe fn init(
cs: critical_section::CriticalSection,
#[cfg(bdma)] bdma_priority: Priority, #[cfg(bdma)] bdma_priority: Priority,
#[cfg(dma)] dma_priority: Priority, #[cfg(dma)] dma_priority: Priority,
#[cfg(gpdma)] gpdma_priority: Priority, #[cfg(gpdma)] gpdma_priority: Priority,
) { ) {
#[cfg(bdma)] #[cfg(bdma)]
bdma::init(bdma_priority); bdma::init(cs, bdma_priority);
#[cfg(dma)] #[cfg(dma)]
dma::init(dma_priority); dma::init(cs, dma_priority);
#[cfg(gpdma)] #[cfg(gpdma)]
gpdma::init(gpdma_priority); gpdma::init(cs, gpdma_priority);
#[cfg(dmamux)] #[cfg(dmamux)]
dmamux::init(); dmamux::init(cs);
} }

View File

@ -41,39 +41,40 @@ mod phy_consts {
} }
use self::phy_consts::*; use self::phy_consts::*;
/// Generic SMI Ethernet PHY /// Generic SMI Ethernet PHY implementation
pub struct GenericSMI { pub struct GenericSMI {
phy_addr: u8,
#[cfg(feature = "time")] #[cfg(feature = "time")]
poll_interval: Duration, poll_interval: Duration,
#[cfg(not(feature = "time"))]
_private: (),
} }
impl GenericSMI { 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 { Self {
phy_addr,
#[cfg(feature = "time")] #[cfg(feature = "time")]
poll_interval: Duration::from_millis(500), poll_interval: Duration::from_millis(500),
#[cfg(not(feature = "time"))]
_private: (),
} }
} }
} }
unsafe impl PHY for GenericSMI { 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) { fn phy_reset<S: StationManagement>(&mut self, sm: &mut S) {
sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_RESET); sm.smi_write(self.phy_addr, PHY_REG_BCR, PHY_REG_BCR_RESET);
while sm.smi_read(PHY_REG_BCR) & PHY_REG_BCR_RESET == 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) { fn phy_init<S: StationManagement>(&mut self, sm: &mut S) {
// Clear WU CSR // Clear WU CSR
self.smi_write_ext(sm, PHY_REG_WUCSR, 0); self.smi_write_ext(sm, PHY_REG_WUCSR, 0);
// Enable auto-negotiation // 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 { 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")] #[cfg(feature = "time")]
let _ = Timer::after(self.poll_interval).poll_unpin(cx); 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 // No link without autonegotiate
if bsr & PHY_REG_BSR_ANDONE == 0 { 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 // 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) { 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(self.phy_addr, PHY_REG_CTL, 0x0003); // set address
sm.smi_write(PHY_REG_ADDAR, reg_addr); sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_addr);
sm.smi_write(PHY_REG_CTL, 0x4003); // set data sm.smi_write(self.phy_addr, PHY_REG_CTL, 0x4003); // set data
sm.smi_write(PHY_REG_ADDAR, reg_data); sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_data);
} }
} }

View File

@ -134,9 +134,9 @@ impl<'a, 'd> embassy_net_driver::TxToken for TxToken<'a, 'd> {
/// The methods cannot move out of self /// The methods cannot move out of self
pub unsafe trait StationManagement { pub unsafe trait StationManagement {
/// Read a register over SMI. /// 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. /// 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 /// Traits for an Ethernet PHY

View File

@ -107,7 +107,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
tx_en: impl Peripheral<P = impl TXEnPin<T>> + 'd, tx_en: impl Peripheral<P = impl TXEnPin<T>> + 'd,
phy: P, phy: P,
mac_addr: [u8; 6], mac_addr: [u8; 6],
phy_addr: u8,
) -> Self { ) -> Self {
into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
@ -227,7 +226,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
station_management: EthernetStationManagement { station_management: EthernetStationManagement {
peri: PhantomData, peri: PhantomData,
clock_range: clock_range, clock_range: clock_range,
phy_addr: phy_addr,
}, },
mac_addr, mac_addr,
tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
@ -271,15 +269,14 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
pub struct EthernetStationManagement<T: Instance> { pub struct EthernetStationManagement<T: Instance> {
peri: PhantomData<T>, peri: PhantomData<T>,
clock_range: Cr, clock_range: Cr,
phy_addr: u8,
} }
unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> { unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
fn smi_read(&mut self, reg: u8) -> u16 { fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 {
let mac = ETH.ethernet_mac(); let mac = ETH.ethernet_mac();
mac.macmiiar().modify(|w| { mac.macmiiar().modify(|w| {
w.set_pa(self.phy_addr); w.set_pa(phy_addr);
w.set_mr(reg); w.set_mr(reg);
w.set_mw(Mw::READ); // read operation w.set_mw(Mw::READ); // read operation
w.set_cr(self.clock_range); w.set_cr(self.clock_range);
@ -289,12 +286,12 @@ unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
mac.macmiidr().read().md() mac.macmiidr().read().md()
} }
fn smi_write(&mut self, reg: u8, val: u16) { fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) {
let mac = ETH.ethernet_mac(); let mac = ETH.ethernet_mac();
mac.macmiidr().write(|w| w.set_md(val)); mac.macmiidr().write(|w| w.set_md(val));
mac.macmiiar().modify(|w| { mac.macmiiar().modify(|w| {
w.set_pa(self.phy_addr); w.set_pa(phy_addr);
w.set_mr(reg); w.set_mr(reg);
w.set_mw(Mw::WRITE); // write w.set_mw(Mw::WRITE); // write
w.set_cr(self.clock_range); w.set_cr(self.clock_range);

View File

@ -71,7 +71,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
tx_en: impl Peripheral<P = impl TXEnPin<T>> + 'd, tx_en: impl Peripheral<P = impl TXEnPin<T>> + 'd,
phy: P, phy: P,
mac_addr: [u8; 6], mac_addr: [u8; 6],
phy_addr: u8,
) -> Self { ) -> Self {
into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
@ -202,7 +201,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
station_management: EthernetStationManagement { station_management: EthernetStationManagement {
peri: PhantomData, peri: PhantomData,
clock_range: clock_range, clock_range: clock_range,
phy_addr: phy_addr,
}, },
mac_addr, mac_addr,
}; };
@ -242,15 +240,14 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
pub struct EthernetStationManagement<T: Instance> { pub struct EthernetStationManagement<T: Instance> {
peri: PhantomData<T>, peri: PhantomData<T>,
clock_range: u8, clock_range: u8,
phy_addr: u8,
} }
unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> { unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
fn smi_read(&mut self, reg: u8) -> u16 { fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 {
let mac = ETH.ethernet_mac(); let mac = ETH.ethernet_mac();
mac.macmdioar().modify(|w| { mac.macmdioar().modify(|w| {
w.set_pa(self.phy_addr); w.set_pa(phy_addr);
w.set_rda(reg); w.set_rda(reg);
w.set_goc(0b11); // read w.set_goc(0b11); // read
w.set_cr(self.clock_range); w.set_cr(self.clock_range);
@ -260,12 +257,12 @@ unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
mac.macmdiodr().read().md() mac.macmdiodr().read().md()
} }
fn smi_write(&mut self, reg: u8, val: u16) { fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) {
let mac = ETH.ethernet_mac(); let mac = ETH.ethernet_mac();
mac.macmdiodr().write(|w| w.set_md(val)); mac.macmdiodr().write(|w| w.set_md(val));
mac.macmdioar().modify(|w| { mac.macmdioar().modify(|w| {
w.set_pa(self.phy_addr); w.set_pa(phy_addr);
w.set_rda(reg); w.set_rda(reg);
w.set_goc(0b01); // write w.set_goc(0b01); // write
w.set_cr(self.clock_range); w.set_cr(self.clock_range);

View File

@ -367,7 +367,7 @@ macro_rules! enable_irq {
} }
/// safety: must be called only once /// safety: must be called only once
pub(crate) unsafe fn init() { pub(crate) unsafe fn init(_cs: critical_section::CriticalSection) {
use crate::interrupt::typelevel::Interrupt; use crate::interrupt::typelevel::Interrupt;
foreach_exti_irq!(enable_irq); foreach_exti_irq!(enable_irq);

View File

@ -19,8 +19,10 @@ pub(crate) unsafe fn lock() {
} }
pub(crate) unsafe fn unlock() { pub(crate) unsafe fn unlock() {
pac::FLASH.keyr().write(|w| w.set_fkeyr(0x4567_0123)); if pac::FLASH.cr().read().lock() {
pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB)); pac::FLASH.keyr().write(|w| w.set_fkeyr(0x4567_0123));
pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB));
}
} }
pub(crate) unsafe fn enable_blocking_write() { pub(crate) unsafe fn enable_blocking_write() {

View File

@ -19,8 +19,10 @@ pub(crate) unsafe fn lock() {
} }
pub(crate) unsafe fn unlock() { pub(crate) unsafe fn unlock() {
pac::FLASH.keyr().write(|w| w.set_fkeyr(0x4567_0123)); if pac::FLASH.cr().read().lock() {
pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB)); pac::FLASH.keyr().write(|w| w.set_fkeyr(0x4567_0123));
pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB));
}
} }
pub(crate) unsafe fn enable_blocking_write() { pub(crate) unsafe fn enable_blocking_write() {

View File

@ -228,8 +228,10 @@ pub(crate) unsafe fn lock() {
} }
pub(crate) unsafe fn unlock() { pub(crate) unsafe fn unlock() {
pac::FLASH.keyr().write(|w| w.set_key(0x45670123)); if pac::FLASH.cr().read().lock() {
pac::FLASH.keyr().write(|w| w.set_key(0xCDEF89AB)); pac::FLASH.keyr().write(|w| w.set_key(0x45670123));
pac::FLASH.keyr().write(|w| w.set_key(0xCDEF89AB));
}
} }
pub(crate) unsafe fn enable_write() { pub(crate) unsafe fn enable_write() {

View File

@ -19,8 +19,10 @@ pub(crate) unsafe fn lock() {
} }
pub(crate) unsafe fn unlock() { pub(crate) unsafe fn unlock() {
pac::FLASH.keyr().write(|w| w.set_key(0x4567_0123)); if pac::FLASH.cr().read().lock() {
pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB)); pac::FLASH.keyr().write(|w| w.set_key(0x4567_0123));
pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB));
}
} }
pub(crate) unsafe fn enable_blocking_write() { pub(crate) unsafe fn enable_blocking_write() {

View File

@ -24,8 +24,10 @@ pub(crate) unsafe fn unlock() {
while pac::FLASH.sr().read().bsy() {} while pac::FLASH.sr().read().bsy() {}
// Unlock flash // Unlock flash
pac::FLASH.keyr().write(|w| w.set_keyr(0x4567_0123)); if pac::FLASH.cr().read().lock() {
pac::FLASH.keyr().write(|w| w.set_keyr(0xCDEF_89AB)); pac::FLASH.keyr().write(|w| w.set_keyr(0x4567_0123));
pac::FLASH.keyr().write(|w| w.set_keyr(0xCDEF_89AB));
}
} }
pub(crate) unsafe fn enable_blocking_write() { pub(crate) unsafe fn enable_blocking_write() {

View File

@ -26,11 +26,15 @@ pub(crate) unsafe fn lock() {
} }
pub(crate) unsafe fn unlock() { pub(crate) unsafe fn unlock() {
pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0x4567_0123)); if pac::FLASH.bank(0).cr().read().lock() {
pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0xCDEF_89AB)); pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0x4567_0123));
pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0xCDEF_89AB));
}
if is_dual_bank() { if is_dual_bank() {
pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0x4567_0123)); if pac::FLASH.bank(1).cr().read().lock() {
pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0xCDEF_89AB)); pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0x4567_0123));
pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0xCDEF_89AB));
}
} }
} }

View File

@ -28,17 +28,23 @@ pub(crate) unsafe fn lock() {
pub(crate) unsafe fn unlock() { pub(crate) unsafe fn unlock() {
#[cfg(any(flash_wl, flash_wb, flash_l4))] #[cfg(any(flash_wl, flash_wb, flash_l4))]
{ {
pac::FLASH.keyr().write(|w| w.set_keyr(0x4567_0123)); if pac::FLASH.cr().read().lock() {
pac::FLASH.keyr().write(|w| w.set_keyr(0xCDEF_89AB)); pac::FLASH.keyr().write(|w| w.set_keyr(0x4567_0123));
pac::FLASH.keyr().write(|w| w.set_keyr(0xCDEF_89AB));
}
} }
#[cfg(any(flash_l0, flash_l1))] #[cfg(any(flash_l0, flash_l1))]
{ {
pac::FLASH.pekeyr().write(|w| w.set_pekeyr(0x89ABCDEF)); if pac::FLASH.pecr().read().pelock() {
pac::FLASH.pekeyr().write(|w| w.set_pekeyr(0x02030405)); pac::FLASH.pekeyr().write(|w| w.set_pekeyr(0x89ABCDEF));
pac::FLASH.pekeyr().write(|w| w.set_pekeyr(0x02030405));
}
pac::FLASH.prgkeyr().write(|w| w.set_prgkeyr(0x8C9DAEBF)); if pac::FLASH.pecr().read().prglock() {
pac::FLASH.prgkeyr().write(|w| w.set_prgkeyr(0x13141516)); pac::FLASH.prgkeyr().write(|w| w.set_prgkeyr(0x8C9DAEBF));
pac::FLASH.prgkeyr().write(|w| w.set_prgkeyr(0x13141516));
}
} }
} }

View File

@ -19,8 +19,7 @@ where
const REGISTERS: *const () = T::REGS.as_ptr() as *const _; const REGISTERS: *const () = T::REGS.as_ptr() as *const _;
fn enable(&mut self) { fn enable(&mut self) {
<T as crate::rcc::sealed::RccPeripheral>::enable(); T::enable_and_reset();
<T as crate::rcc::sealed::RccPeripheral>::reset();
} }
fn memory_controller_enable(&mut self) { fn memory_controller_enable(&mut self) {

View File

@ -1,6 +1,7 @@
#![macro_use] #![macro_use]
use core::convert::Infallible; use core::convert::Infallible;
use critical_section::CriticalSection;
use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef};
use crate::pac::gpio::{self, vals}; use crate::pac::gpio::{self, vals};
@ -757,9 +758,9 @@ foreach_pin!(
}; };
); );
pub(crate) unsafe fn init() { pub(crate) unsafe fn init(_cs: CriticalSection) {
#[cfg(afio)] #[cfg(afio)]
<crate::peripherals::AFIO as crate::rcc::sealed::RccPeripheral>::enable(); <crate::peripherals::AFIO as crate::rcc::sealed::RccPeripheral>::enable_and_reset_with_cs(_cs);
crate::_generated::init_gpio(); crate::_generated::init_gpio();
} }
@ -974,6 +975,18 @@ mod eh1 {
type Error = Infallible; type Error = Infallible;
} }
impl<'d, T: Pin> InputPin for OutputOpenDrain<'d, T> {
#[inline]
fn is_high(&self) -> Result<bool, Self::Error> {
Ok(self.is_high())
}
#[inline]
fn is_low(&self) -> Result<bool, Self::Error> {
Ok(self.is_low())
}
}
impl<'d, T: Pin> OutputPin for OutputOpenDrain<'d, T> { impl<'d, T: Pin> OutputPin for OutputOpenDrain<'d, T> {
#[inline] #[inline]
fn set_high(&mut self) -> Result<(), Self::Error> { fn set_high(&mut self) -> Result<(), Self::Error> {

View File

@ -157,8 +157,7 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> {
fn new_inner(tim: impl Peripheral<P = T> + 'd) -> Self { fn new_inner(tim: impl Peripheral<P = T> + 'd) -> Self {
into_ref!(tim); into_ref!(tim);
T::enable(); T::enable_and_reset();
<T as crate::rcc::sealed::RccPeripheral>::reset();
#[cfg(stm32f334)] #[cfg(stm32f334)]
if unsafe { get_freqs() }.hrtim.is_some() { if unsafe { get_freqs() }.hrtim.is_some() {

View File

@ -7,14 +7,9 @@ use crate::interrupt;
mod _version; mod _version;
pub use _version::*; pub use _version::*;
#[cfg(feature = "time")]
mod timeout;
#[cfg(feature = "time")]
pub use timeout::*;
use crate::peripherals; use crate::peripherals;
#[derive(Debug)] #[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error { pub enum Error {
Bus, Bus,

View File

@ -1,209 +0,0 @@
use embassy_time::{Duration, Instant};
use super::{Error, I2c, Instance};
/// An I2C wrapper, which provides `embassy-time` based timeouts for all `embedded-hal` trait methods.
///
/// This is useful for recovering from a shorted bus or a device stuck in a clock stretching state.
/// A regular [I2c] would freeze until condition is removed.
pub struct TimeoutI2c<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> {
i2c: &'a mut I2c<'d, T, TXDMA, RXDMA>,
timeout: Duration,
}
fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> {
let deadline = Instant::now() + timeout;
move || {
if Instant::now() > deadline {
Err(Error::Timeout)
} else {
Ok(())
}
}
}
impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> {
pub fn new(i2c: &'a mut I2c<'d, T, TXDMA, RXDMA>, timeout: Duration) -> Self {
Self { i2c, timeout }
}
// =========================
// Async public API
#[cfg(i2c_v2)]
pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error>
where
TXDMA: crate::i2c::TxDma<T>,
{
self.write_timeout(address, write, self.timeout).await
}
#[cfg(i2c_v2)]
pub async fn write_timeout(&mut self, address: u8, write: &[u8], timeout: Duration) -> Result<(), Error>
where
TXDMA: crate::i2c::TxDma<T>,
{
self.i2c.write_timeout(address, write, timeout_fn(timeout)).await
}
#[cfg(i2c_v2)]
pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error>
where
TXDMA: crate::i2c::TxDma<T>,
{
self.write_vectored_timeout(address, write, self.timeout).await
}
#[cfg(i2c_v2)]
pub async fn write_vectored_timeout(&mut self, address: u8, write: &[&[u8]], timeout: Duration) -> Result<(), Error>
where
TXDMA: crate::i2c::TxDma<T>,
{
self.i2c
.write_vectored_timeout(address, write, timeout_fn(timeout))
.await
}
#[cfg(i2c_v2)]
pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error>
where
RXDMA: crate::i2c::RxDma<T>,
{
self.read_timeout(address, buffer, self.timeout).await
}
#[cfg(i2c_v2)]
pub async fn read_timeout(&mut self, address: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error>
where
RXDMA: crate::i2c::RxDma<T>,
{
self.i2c.read_timeout(address, buffer, timeout_fn(timeout)).await
}
#[cfg(i2c_v2)]
pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error>
where
TXDMA: super::TxDma<T>,
RXDMA: super::RxDma<T>,
{
self.write_read_timeout(address, write, read, self.timeout).await
}
#[cfg(i2c_v2)]
pub async fn write_read_timeout(
&mut self,
address: u8,
write: &[u8],
read: &mut [u8],
timeout: Duration,
) -> Result<(), Error>
where
TXDMA: super::TxDma<T>,
RXDMA: super::RxDma<T>,
{
self.i2c
.write_read_timeout(address, write, read, timeout_fn(timeout))
.await
}
// =========================
// Blocking public API
/// Blocking read with a custom timeout
pub fn blocking_read_timeout(&mut self, addr: u8, read: &mut [u8], timeout: Duration) -> Result<(), Error> {
self.i2c.blocking_read_timeout(addr, read, timeout_fn(timeout))
}
/// Blocking read with default timeout, provided in [`TimeoutI2c::new()`]
pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> {
self.blocking_read_timeout(addr, read, self.timeout)
}
/// Blocking write with a custom timeout
pub fn blocking_write_timeout(&mut self, addr: u8, write: &[u8], timeout: Duration) -> Result<(), Error> {
self.i2c.blocking_write_timeout(addr, write, timeout_fn(timeout))
}
/// Blocking write with default timeout, provided in [`TimeoutI2c::new()`]
pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> {
self.blocking_write_timeout(addr, write, self.timeout)
}
/// Blocking write-read with a custom timeout
pub fn blocking_write_read_timeout(
&mut self,
addr: u8,
write: &[u8],
read: &mut [u8],
timeout: Duration,
) -> Result<(), Error> {
self.i2c
.blocking_write_read_timeout(addr, write, read, timeout_fn(timeout))
}
/// Blocking write-read with default timeout, provided in [`TimeoutI2c::new()`]
pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
self.blocking_write_read_timeout(addr, write, read, self.timeout)
}
}
impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Read
for TimeoutI2c<'a, 'd, T, TXDMA, RXDMA>
{
type Error = Error;
fn read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_read(addr, read)
}
}
impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Write
for TimeoutI2c<'a, 'd, T, TXDMA, RXDMA>
{
type Error = Error;
fn write(&mut self, addr: u8, write: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(addr, write)
}
}
impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::WriteRead
for TimeoutI2c<'a, 'd, T, TXDMA, RXDMA>
{
type Error = Error;
fn write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_write_read(addr, write, read)
}
}
#[cfg(feature = "unstable-traits")]
mod eh1 {
use super::*;
impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::ErrorType for TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> {
type Error = Error;
}
impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::I2c for TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> {
fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_read(address, read)
}
fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
self.blocking_write(address, write)
}
fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
self.blocking_write_read(address, write, read)
}
fn transaction(
&mut self,
_address: u8,
_operations: &mut [embedded_hal_1::i2c::Operation<'_>],
) -> Result<(), Self::Error> {
todo!();
}
}
}

View File

@ -56,8 +56,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
) -> Self { ) -> Self {
into_ref!(scl, sda, tx_dma, rx_dma); into_ref!(scl, sda, tx_dma, rx_dma);
T::enable(); T::enable_and_reset();
T::reset();
scl.set_as_af_pull( scl.set_as_af_pull(
scl.af_num(), scl.af_num(),

View File

@ -1,14 +1,21 @@
use core::cmp; use core::cmp;
#[cfg(feature = "time")]
use core::future::poll_fn; use core::future::poll_fn;
use core::marker::PhantomData; use core::marker::PhantomData;
#[cfg(feature = "time")]
use core::task::Poll; use core::task::Poll;
use embassy_embedded_hal::SetConfig; use embassy_embedded_hal::SetConfig;
#[cfg(feature = "time")]
use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::drop::OnDrop;
use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_hal_internal::{into_ref, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
#[cfg(feature = "time")]
use embassy_time::{Duration, Instant};
use crate::dma::{NoDma, Transfer}; use crate::dma::NoDma;
#[cfg(feature = "time")]
use crate::dma::Transfer;
use crate::gpio::sealed::AFType; use crate::gpio::sealed::AFType;
use crate::gpio::Pull; use crate::gpio::Pull;
use crate::i2c::{Error, Instance, SclPin, SdaPin}; use crate::i2c::{Error, Instance, SclPin, SdaPin};
@ -43,6 +50,8 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
pub struct Config { pub struct Config {
pub sda_pullup: bool, pub sda_pullup: bool,
pub scl_pullup: bool, pub scl_pullup: bool,
#[cfg(feature = "time")]
pub transaction_timeout: Duration,
} }
impl Default for Config { impl Default for Config {
@ -50,6 +59,8 @@ impl Default for Config {
Self { Self {
sda_pullup: false, sda_pullup: false,
scl_pullup: false, scl_pullup: false,
#[cfg(feature = "time")]
transaction_timeout: Duration::from_millis(100),
} }
} }
} }
@ -68,9 +79,12 @@ impl State {
pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> {
_peri: PeripheralRef<'d, T>, _peri: PeripheralRef<'d, T>,
#[allow(dead_code)]
tx_dma: PeripheralRef<'d, TXDMA>, tx_dma: PeripheralRef<'d, TXDMA>,
#[allow(dead_code)] #[allow(dead_code)]
rx_dma: PeripheralRef<'d, RXDMA>, rx_dma: PeripheralRef<'d, RXDMA>,
#[cfg(feature = "time")]
timeout: Duration,
} }
impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
@ -86,8 +100,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
) -> Self { ) -> Self {
into_ref!(peri, scl, sda, tx_dma, rx_dma); into_ref!(peri, scl, sda, tx_dma, rx_dma);
T::enable(); T::enable_and_reset();
T::reset();
scl.set_as_af_pull( scl.set_as_af_pull(
scl.af_num(), scl.af_num(),
@ -132,6 +145,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
_peri: peri, _peri: peri,
tx_dma, tx_dma,
rx_dma, rx_dma,
#[cfg(feature = "time")]
timeout: config.transaction_timeout,
} }
} }
@ -422,6 +437,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
result result
} }
#[cfg(feature = "time")]
async fn write_dma_internal( async fn write_dma_internal(
&mut self, &mut self,
address: u8, address: u8,
@ -512,6 +528,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
Ok(()) Ok(())
} }
#[cfg(feature = "time")]
async fn read_dma_internal( async fn read_dma_internal(
&mut self, &mut self,
address: u8, address: u8,
@ -594,42 +611,41 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
// ========================= // =========================
// Async public API // Async public API
#[cfg(feature = "time")]
pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error>
where where
TXDMA: crate::i2c::TxDma<T>, TXDMA: crate::i2c::TxDma<T>,
{ {
self.write_timeout(address, write, || Ok(())).await self.write_timeout(address, write, self.timeout).await
} }
pub async fn write_timeout( #[cfg(feature = "time")]
&mut self, pub async fn write_timeout(&mut self, address: u8, write: &[u8], timeout: Duration) -> Result<(), Error>
address: u8,
write: &[u8],
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error>
where where
TXDMA: crate::i2c::TxDma<T>, TXDMA: crate::i2c::TxDma<T>,
{ {
if write.is_empty() { if write.is_empty() {
self.write_internal(address, write, true, check_timeout) self.write_internal(address, write, true, timeout_fn(timeout))
} else { } else {
self.write_dma_internal(address, write, true, true, check_timeout).await embassy_time::with_timeout(
timeout,
self.write_dma_internal(address, write, true, true, timeout_fn(timeout)),
)
.await
.unwrap_or(Err(Error::Timeout))
} }
} }
#[cfg(feature = "time")]
pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error>
where where
TXDMA: crate::i2c::TxDma<T>, TXDMA: crate::i2c::TxDma<T>,
{ {
self.write_vectored_timeout(address, write, || Ok(())).await self.write_vectored_timeout(address, write, self.timeout).await
} }
pub async fn write_vectored_timeout( #[cfg(feature = "time")]
&mut self, pub async fn write_vectored_timeout(&mut self, address: u8, write: &[&[u8]], timeout: Duration) -> Result<(), Error>
address: u8,
write: &[&[u8]],
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error>
where where
TXDMA: crate::i2c::TxDma<T>, TXDMA: crate::i2c::TxDma<T>,
{ {
@ -644,67 +660,88 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
let next = iter.next(); let next = iter.next();
let is_last = next.is_none(); let is_last = next.is_none();
self.write_dma_internal(address, c, first, is_last, || check_timeout()) embassy_time::with_timeout(
.await?; timeout,
self.write_dma_internal(address, c, first, is_last, timeout_fn(timeout)),
)
.await
.unwrap_or(Err(Error::Timeout))?;
first = false; first = false;
current = next; current = next;
} }
Ok(()) Ok(())
} }
#[cfg(feature = "time")]
pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error>
where where
RXDMA: crate::i2c::RxDma<T>, RXDMA: crate::i2c::RxDma<T>,
{ {
self.read_timeout(address, buffer, || Ok(())).await self.read_timeout(address, buffer, self.timeout).await
} }
pub async fn read_timeout( #[cfg(feature = "time")]
&mut self, pub async fn read_timeout(&mut self, address: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error>
address: u8,
buffer: &mut [u8],
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error>
where where
RXDMA: crate::i2c::RxDma<T>, RXDMA: crate::i2c::RxDma<T>,
{ {
if buffer.is_empty() { if buffer.is_empty() {
self.read_internal(address, buffer, false, check_timeout) self.read_internal(address, buffer, false, timeout_fn(timeout))
} else { } else {
self.read_dma_internal(address, buffer, false, check_timeout).await embassy_time::with_timeout(
timeout,
self.read_dma_internal(address, buffer, false, timeout_fn(timeout)),
)
.await
.unwrap_or(Err(Error::Timeout))
} }
} }
#[cfg(feature = "time")]
pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error>
where where
TXDMA: super::TxDma<T>, TXDMA: super::TxDma<T>,
RXDMA: super::RxDma<T>, RXDMA: super::RxDma<T>,
{ {
self.write_read_timeout(address, write, read, || Ok(())).await self.write_read_timeout(address, write, read, self.timeout).await
} }
#[cfg(feature = "time")]
pub async fn write_read_timeout( pub async fn write_read_timeout(
&mut self, &mut self,
address: u8, address: u8,
write: &[u8], write: &[u8],
read: &mut [u8], read: &mut [u8],
check_timeout: impl Fn() -> Result<(), Error>, timeout: Duration,
) -> Result<(), Error> ) -> Result<(), Error>
where where
TXDMA: super::TxDma<T>, TXDMA: super::TxDma<T>,
RXDMA: super::RxDma<T>, RXDMA: super::RxDma<T>,
{ {
let start_instant = Instant::now();
let check_timeout = timeout_fn(timeout);
if write.is_empty() { if write.is_empty() {
self.write_internal(address, write, false, || check_timeout())?; self.write_internal(address, write, false, &check_timeout)?;
} else { } else {
self.write_dma_internal(address, write, true, true, || check_timeout()) embassy_time::with_timeout(
.await?; timeout,
self.write_dma_internal(address, write, true, true, &check_timeout),
)
.await
.unwrap_or(Err(Error::Timeout))?;
} }
let time_left_until_timeout = timeout - Instant::now().duration_since(start_instant);
if read.is_empty() { if read.is_empty() {
self.read_internal(address, read, true, check_timeout)?; self.read_internal(address, read, true, &check_timeout)?;
} else { } else {
self.read_dma_internal(address, read, true, check_timeout).await?; embassy_time::with_timeout(
time_left_until_timeout,
self.read_dma_internal(address, read, true, &check_timeout),
)
.await
.unwrap_or(Err(Error::Timeout))?;
} }
Ok(()) Ok(())
@ -713,33 +750,73 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
// ========================= // =========================
// Blocking public API // Blocking public API
#[cfg(feature = "time")]
pub fn blocking_read_timeout(&mut self, address: u8, read: &mut [u8], timeout: Duration) -> Result<(), Error> {
self.read_internal(address, read, false, timeout_fn(timeout))
// Automatic Stop
}
#[cfg(not(feature = "time"))]
pub fn blocking_read_timeout( pub fn blocking_read_timeout(
&mut self, &mut self,
address: u8, address: u8,
read: &mut [u8], read: &mut [u8],
check_timeout: impl Fn() -> Result<(), Error>, check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.read_internal(address, read, false, &check_timeout) self.read_internal(address, read, false, check_timeout)
// Automatic Stop // Automatic Stop
} }
#[cfg(feature = "time")]
pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> {
self.blocking_read_timeout(address, read, self.timeout)
}
#[cfg(not(feature = "time"))]
pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> {
self.blocking_read_timeout(address, read, || Ok(())) self.blocking_read_timeout(address, read, || Ok(()))
} }
#[cfg(feature = "time")]
pub fn blocking_write_timeout(&mut self, address: u8, write: &[u8], timeout: Duration) -> Result<(), Error> {
self.write_internal(address, write, true, timeout_fn(timeout))
}
#[cfg(not(feature = "time"))]
pub fn blocking_write_timeout( pub fn blocking_write_timeout(
&mut self, &mut self,
address: u8, address: u8,
write: &[u8], write: &[u8],
check_timeout: impl Fn() -> Result<(), Error>, check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.write_internal(address, write, true, &check_timeout) self.write_internal(address, write, true, check_timeout)
} }
#[cfg(feature = "time")]
pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
self.blocking_write_timeout(address, write, self.timeout)
}
#[cfg(not(feature = "time"))]
pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
self.blocking_write_timeout(address, write, || Ok(())) self.blocking_write_timeout(address, write, || Ok(()))
} }
#[cfg(feature = "time")]
pub fn blocking_write_read_timeout(
&mut self,
address: u8,
write: &[u8],
read: &mut [u8],
timeout: Duration,
) -> Result<(), Error> {
let check_timeout = timeout_fn(timeout);
self.write_internal(address, write, false, &check_timeout)?;
self.read_internal(address, read, true, &check_timeout)
// Automatic Stop
}
#[cfg(not(feature = "time"))]
pub fn blocking_write_read_timeout( pub fn blocking_write_read_timeout(
&mut self, &mut self,
address: u8, address: u8,
@ -752,11 +829,17 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
// Automatic Stop // Automatic Stop
} }
#[cfg(feature = "time")]
pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
self.blocking_write_read_timeout(address, write, read, self.timeout)
}
#[cfg(not(feature = "time"))]
pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
self.blocking_write_read_timeout(address, write, read, || Ok(())) self.blocking_write_read_timeout(address, write, read, || Ok(()))
} }
pub fn blocking_write_vectored_timeout( fn blocking_write_vectored_with_timeout(
&mut self, &mut self,
address: u8, address: u8,
write: &[&[u8]], write: &[&[u8]],
@ -765,6 +848,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
if write.is_empty() { if write.is_empty() {
return Err(Error::ZeroLengthTransfer); return Err(Error::ZeroLengthTransfer);
} }
let first_length = write[0].len(); let first_length = write[0].len();
let last_slice_index = write.len() - 1; let last_slice_index = write.len() - 1;
@ -833,6 +917,33 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
result result
} }
#[cfg(feature = "time")]
pub fn blocking_write_vectored_timeout(
&mut self,
address: u8,
write: &[&[u8]],
timeout: Duration,
) -> Result<(), Error> {
let check_timeout = timeout_fn(timeout);
self.blocking_write_vectored_with_timeout(address, write, check_timeout)
}
#[cfg(not(feature = "time"))]
pub fn blocking_write_vectored_timeout(
&mut self,
address: u8,
write: &[&[u8]],
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
self.blocking_write_vectored_with_timeout(address, write, check_timeout)
}
#[cfg(feature = "time")]
pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> {
self.blocking_write_vectored_timeout(address, write, self.timeout)
}
#[cfg(not(feature = "time"))]
pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> { pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> {
self.blocking_write_vectored_timeout(address, write, || Ok(())) self.blocking_write_vectored_timeout(address, write, || Ok(()))
} }
@ -844,6 +955,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> {
} }
} }
#[cfg(feature = "time")]
mod eh02 { mod eh02 {
use super::*; use super::*;
@ -1043,7 +1155,7 @@ mod eh1 {
} }
} }
#[cfg(all(feature = "unstable-traits", feature = "nightly"))] #[cfg(all(feature = "unstable-traits", feature = "nightly", feature = "time"))]
mod eha { mod eha {
use super::super::{RxDma, TxDma}; use super::super::{RxDma, TxDma};
use super::*; use super::*;
@ -1089,3 +1201,15 @@ impl<'d, T: Instance> SetConfig for I2c<'d, T> {
Ok(()) Ok(())
} }
} }
#[cfg(feature = "time")]
fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> {
let deadline = Instant::now() + timeout;
move || {
if Instant::now() > deadline {
Err(Error::Timeout)
} else {
Ok(())
}
}
}

View File

@ -93,8 +93,7 @@ pub struct Ipcc;
impl Ipcc { impl Ipcc {
pub fn enable(_config: Config) { pub fn enable(_config: Config) {
IPCC::enable(); IPCC::enable_and_reset();
IPCC::reset();
IPCC::set_cpu2(true); IPCC::set_cpu2(true);
_configure_pwr(); _configure_pwr();

View File

@ -1,5 +1,5 @@
#![cfg_attr(not(test), no_std)] #![cfg_attr(not(test), no_std)]
#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections))] #![cfg_attr(feature = "nightly", feature(async_fn_in_trait))]
//! ## Feature flags //! ## Feature flags
#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)] #![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
@ -49,6 +49,8 @@ pub mod i2s;
pub mod ipcc; pub mod ipcc;
#[cfg(feature = "low-power")] #[cfg(feature = "low-power")]
pub mod low_power; pub mod low_power;
#[cfg(opamp)]
pub mod opamp;
#[cfg(quadspi)] #[cfg(quadspi)]
pub mod qspi; pub mod qspi;
#[cfg(rng)] #[cfg(rng)]
@ -153,79 +155,82 @@ impl Default for Config {
/// Initialize embassy. /// Initialize embassy.
pub fn init(config: Config) -> Peripherals { pub fn init(config: Config) -> Peripherals {
let p = Peripherals::take(); critical_section::with(|cs| {
let p = Peripherals::take_with_cs(cs);
#[cfg(dbgmcu)] #[cfg(dbgmcu)]
if config.enable_debug_during_sleep { if config.enable_debug_during_sleep {
crate::pac::DBGMCU.cr().modify(|cr| { crate::pac::DBGMCU.cr().modify(|cr| {
#[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba))] #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba))]
{ {
cr.set_dbg_stop(true); cr.set_dbg_stop(true);
cr.set_dbg_standby(true); cr.set_dbg_standby(true);
} }
#[cfg(any( #[cfg(any(
dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1, dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1,
dbgmcu_l4, dbgmcu_wb, dbgmcu_wl dbgmcu_l4, dbgmcu_wb, dbgmcu_wl
))] ))]
{ {
cr.set_dbg_sleep(true); cr.set_dbg_sleep(true);
cr.set_dbg_stop(true); cr.set_dbg_stop(true);
cr.set_dbg_standby(true); cr.set_dbg_standby(true);
} }
#[cfg(dbgmcu_h7)] #[cfg(dbgmcu_h7)]
{ {
cr.set_d1dbgcken(true); cr.set_d1dbgcken(true);
cr.set_d3dbgcken(true); cr.set_d3dbgcken(true);
cr.set_dbgsleep_d1(true); cr.set_dbgsleep_d1(true);
cr.set_dbgstby_d1(true); cr.set_dbgstby_d1(true);
cr.set_dbgstop_d1(true); cr.set_dbgstop_d1(true);
} }
}); });
}
#[cfg(not(any(stm32f1, stm32wb, stm32wl)))]
peripherals::SYSCFG::enable();
#[cfg(not(any(stm32h5, stm32h7, stm32wb, stm32wl)))]
peripherals::PWR::enable();
#[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7)))]
peripherals::FLASH::enable();
unsafe {
#[cfg(feature = "_split-pins-enabled")]
crate::pac::SYSCFG.pmcr().modify(|pmcr| {
#[cfg(feature = "split-pa0")]
pmcr.set_pa0so(true);
#[cfg(feature = "split-pa1")]
pmcr.set_pa1so(true);
#[cfg(feature = "split-pc2")]
pmcr.set_pc2so(true);
#[cfg(feature = "split-pc3")]
pmcr.set_pc3so(true);
});
gpio::init();
dma::init(
#[cfg(bdma)]
config.bdma_interrupt_priority,
#[cfg(dma)]
config.dma_interrupt_priority,
#[cfg(gpdma)]
config.gpdma_interrupt_priority,
);
#[cfg(feature = "exti")]
exti::init();
rcc::init(config.rcc);
// must be after rcc init
#[cfg(feature = "_time-driver")]
time_driver::init();
#[cfg(feature = "low-power")]
while !crate::rcc::low_power_ready() {
crate::rcc::clock_refcount_sub();
} }
}
p #[cfg(not(any(stm32f1, stm32wb, stm32wl)))]
peripherals::SYSCFG::enable_and_reset_with_cs(cs);
#[cfg(not(any(stm32h5, stm32h7, stm32wb, stm32wl)))]
peripherals::PWR::enable_and_reset_with_cs(cs);
#[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7)))]
peripherals::FLASH::enable_and_reset_with_cs(cs);
unsafe {
#[cfg(feature = "_split-pins-enabled")]
crate::pac::SYSCFG.pmcr().modify(|pmcr| {
#[cfg(feature = "split-pa0")]
pmcr.set_pa0so(true);
#[cfg(feature = "split-pa1")]
pmcr.set_pa1so(true);
#[cfg(feature = "split-pc2")]
pmcr.set_pc2so(true);
#[cfg(feature = "split-pc3")]
pmcr.set_pc3so(true);
});
gpio::init(cs);
dma::init(
cs,
#[cfg(bdma)]
config.bdma_interrupt_priority,
#[cfg(dma)]
config.dma_interrupt_priority,
#[cfg(gpdma)]
config.gpdma_interrupt_priority,
);
#[cfg(feature = "exti")]
exti::init(cs);
rcc::init(config.rcc);
// must be after rcc init
#[cfg(feature = "_time-driver")]
time_driver::init(cs);
#[cfg(feature = "low-power")]
while !crate::rcc::low_power_ready() {
crate::rcc::clock_refcount_sub(cs);
}
}
p
})
} }

View File

@ -1,5 +1,6 @@
use core::arch::asm; use core::arch::asm;
use core::marker::PhantomData; use core::marker::PhantomData;
use core::sync::atomic::{compiler_fence, Ordering};
use cortex_m::peripheral::SCB; use cortex_m::peripheral::SCB;
use embassy_executor::*; use embassy_executor::*;
@ -67,10 +68,8 @@ impl Executor {
} }
unsafe fn on_wakeup_irq(&mut self) { unsafe fn on_wakeup_irq(&mut self) {
trace!("low power: on wakeup irq");
self.time_driver.resume_time(); self.time_driver.resume_time();
trace!("low power: resume time"); trace!("low power: resume");
} }
pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) { pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) {
@ -82,21 +81,18 @@ impl Executor {
} }
fn configure_pwr(&mut self) { fn configure_pwr(&mut self) {
trace!("low power: configure_pwr");
self.scb.clear_sleepdeep(); self.scb.clear_sleepdeep();
compiler_fence(Ordering::SeqCst);
if !low_power_ready() { if !low_power_ready() {
trace!("low power: configure_pwr: low power not ready"); trace!("low power: not ready to stop");
return; } else if self.time_driver.pause_time().is_err() {
trace!("low power: failed to pause time");
} else {
trace!("low power: stop");
self.scb.set_sleepdeep();
} }
if self.time_driver.pause_time().is_err() {
trace!("low power: configure_pwr: time driver failed to pause");
return;
}
trace!("low power: enter stop...");
self.scb.set_sleepdeep();
} }
/// Run the executor. /// Run the executor.

159
embassy-stm32/src/opamp.rs Normal file
View File

@ -0,0 +1,159 @@
#![macro_use]
use embassy_hal_internal::{into_ref, PeripheralRef};
use crate::Peripheral;
#[derive(Clone, Copy)]
pub enum OpAmpGain {
Mul1,
Mul2,
Mul4,
Mul8,
Mul16,
}
pub struct OpAmpOutput<'d, 'p, T: Instance, P: NonInvertingPin<T>> {
_inner: &'d OpAmp<'d, T>,
_input: &'p mut P,
}
pub struct OpAmp<'d, T: Instance> {
_inner: PeripheralRef<'d, T>,
}
impl<'d, T: Instance> OpAmp<'d, T> {
pub fn new(opamp: impl Peripheral<P = T> + 'd) -> Self {
Self::new_inner(opamp)
}
fn new_inner(opamp: impl Peripheral<P = T> + 'd) -> Self {
into_ref!(opamp);
#[cfg(opamp_f3)]
T::regs().opampcsr().modify(|w| {
w.set_opampen(true);
});
#[cfg(opamp_g4)]
T::regs().opamp_csr().modify(|w| {
w.set_opaen(true);
});
Self { _inner: opamp }
}
pub fn buffer_for<'a, 'b, P>(&'a mut self, pin: &'b mut P, gain: OpAmpGain) -> OpAmpOutput<'a, 'b, T, P>
where
P: NonInvertingPin<T>,
{
let (vm_sel, pga_gain) = match gain {
OpAmpGain::Mul1 => (0b11, 0b00),
OpAmpGain::Mul2 => (0b10, 0b00),
OpAmpGain::Mul4 => (0b10, 0b01),
OpAmpGain::Mul8 => (0b10, 0b10),
OpAmpGain::Mul16 => (0b10, 0b11),
};
#[cfg(opamp_f3)]
T::regs().opampcsr().modify(|w| {
w.set_vp_sel(pin.channel());
w.set_vm_sel(vm_sel);
w.set_pga_gain(pga_gain);
});
#[cfg(opamp_g4)]
T::regs().opamp_csr().modify(|w| {
use crate::pac::opamp::vals::*;
w.set_vp_sel(OpampCsrVpSel::from_bits(pin.channel()));
w.set_vm_sel(OpampCsrVmSel::from_bits(vm_sel));
w.set_pga_gain(OpampCsrPgaGain::from_bits(pga_gain));
});
OpAmpOutput {
_inner: self,
_input: pin,
}
}
}
pub trait Instance: sealed::Instance + 'static {}
pub(crate) mod sealed {
pub trait Instance {
fn regs() -> crate::pac::opamp::Opamp;
}
pub trait NonInvertingPin<T: Instance> {
fn channel(&self) -> u8;
}
pub trait InvertingPin<T: Instance> {
fn channel(&self) -> u8;
}
}
pub trait NonInvertingPin<T: Instance>: sealed::NonInvertingPin<T> {}
pub trait InvertingPin<T: Instance>: sealed::InvertingPin<T> {}
#[cfg(opamp_f3)]
macro_rules! impl_opamp_output {
($inst:ident, $adc:ident, $ch:expr) => {
impl<'d, 'p, P: NonInvertingPin<crate::peripherals::$inst>> crate::adc::sealed::AdcPin<crate::peripherals::$adc>
for OpAmpOutput<'d, 'p, crate::peripherals::$inst, P>
{
fn channel(&self) -> u8 {
$ch
}
}
impl<'d, 'p, P: NonInvertingPin<crate::peripherals::$inst>> crate::adc::AdcPin<crate::peripherals::$adc>
for OpAmpOutput<'d, 'p, crate::peripherals::$inst, P>
{
}
};
}
#[cfg(opamp_f3)]
foreach_peripheral!(
(opamp, OPAMP1) => {
impl_opamp_output!(OPAMP1, ADC1, 3);
};
(opamp, OPAMP2) => {
impl_opamp_output!(OPAMP2, ADC2, 3);
};
(opamp, OPAMP3) => {
impl_opamp_output!(OPAMP3, ADC3, 1);
};
(opamp, OPAMP4) => {
impl_opamp_output!(OPAMP4, ADC4, 3);
};
);
foreach_peripheral! {
(opamp, $inst:ident) => {
impl sealed::Instance for crate::peripherals::$inst {
fn regs() -> crate::pac::opamp::Opamp {
crate::pac::$inst
}
}
impl Instance for crate::peripherals::$inst {
}
};
}
#[allow(unused_macros)]
macro_rules! impl_opamp_pin {
($inst:ident, $pin:ident, $ch:expr) => {
impl crate::opamp::NonInvertingPin<peripherals::$inst> for crate::peripherals::$pin {}
impl crate::opamp::sealed::NonInvertingPin<peripherals::$inst> for crate::peripherals::$pin {
fn channel(&self) -> u8 {
$ch
}
}
};
}

View File

@ -38,6 +38,22 @@ impl Into<u8> for QspiWidth {
} }
} }
#[allow(dead_code)]
#[derive(Copy, Clone)]
pub enum FlashSelection {
Flash1,
Flash2,
}
impl Into<bool> for FlashSelection {
fn into(self) -> bool {
match self {
FlashSelection::Flash1 => false,
FlashSelection::Flash2 => true,
}
}
}
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum MemorySize { pub enum MemorySize {
_1KiB, _1KiB,

View File

@ -7,7 +7,7 @@ use enums::*;
use crate::dma::Transfer; use crate::dma::Transfer;
use crate::gpio::sealed::AFType; use crate::gpio::sealed::AFType;
use crate::gpio::AnyPin; use crate::gpio::{AnyPin, Pull};
use crate::pac::quadspi::Quadspi as Regs; use crate::pac::quadspi::Quadspi as Regs;
use crate::rcc::RccPeripheral; use crate::rcc::RccPeripheral;
use crate::{peripherals, Peripheral}; use crate::{peripherals, Peripheral};
@ -83,30 +83,30 @@ pub struct Qspi<'d, T: Instance, Dma> {
} }
impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
pub fn new( pub fn new_bk1(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
d0: impl Peripheral<P = impl D0Pin<T>> + 'd, d0: impl Peripheral<P = impl BK1D0Pin<T>> + 'd,
d1: impl Peripheral<P = impl D1Pin<T>> + 'd, d1: impl Peripheral<P = impl BK1D1Pin<T>> + 'd,
d2: impl Peripheral<P = impl D2Pin<T>> + 'd, d2: impl Peripheral<P = impl BK1D2Pin<T>> + 'd,
d3: impl Peripheral<P = impl D3Pin<T>> + 'd, d3: impl Peripheral<P = impl BK1D3Pin<T>> + 'd,
sck: impl Peripheral<P = impl SckPin<T>> + 'd, sck: impl Peripheral<P = impl SckPin<T>> + 'd,
nss: impl Peripheral<P = impl NSSPin<T>> + 'd, nss: impl Peripheral<P = impl BK1NSSPin<T>> + 'd,
dma: impl Peripheral<P = Dma> + 'd, dma: impl Peripheral<P = Dma> + 'd,
config: Config, config: Config,
) -> Self { ) -> Self {
into_ref!(peri, d0, d1, d2, d3, sck, nss); into_ref!(peri, d0, d1, d2, d3, sck, nss);
sck.set_as_af(sck.af_num(), AFType::OutputPushPull); sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None);
sck.set_speed(crate::gpio::Speed::VeryHigh); sck.set_speed(crate::gpio::Speed::VeryHigh);
nss.set_as_af(nss.af_num(), AFType::OutputPushPull); nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up);
nss.set_speed(crate::gpio::Speed::VeryHigh); nss.set_speed(crate::gpio::Speed::VeryHigh);
d0.set_as_af(d0.af_num(), AFType::OutputPushPull); d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None);
d0.set_speed(crate::gpio::Speed::VeryHigh); d0.set_speed(crate::gpio::Speed::VeryHigh);
d1.set_as_af(d1.af_num(), AFType::OutputPushPull); d1.set_as_af_pull(d1.af_num(), AFType::OutputPushPull, Pull::None);
d1.set_speed(crate::gpio::Speed::VeryHigh); d1.set_speed(crate::gpio::Speed::VeryHigh);
d2.set_as_af(d2.af_num(), AFType::OutputPushPull); d2.set_as_af_pull(d2.af_num(), AFType::OutputPushPull, Pull::None);
d2.set_speed(crate::gpio::Speed::VeryHigh); d2.set_speed(crate::gpio::Speed::VeryHigh);
d3.set_as_af(d3.af_num(), AFType::OutputPushPull); d3.set_as_af_pull(d3.af_num(), AFType::OutputPushPull, Pull::None);
d3.set_speed(crate::gpio::Speed::VeryHigh); d3.set_speed(crate::gpio::Speed::VeryHigh);
Self::new_inner( Self::new_inner(
@ -119,6 +119,47 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
Some(nss.map_into()), Some(nss.map_into()),
dma, dma,
config, config,
FlashSelection::Flash2,
)
}
pub fn new_bk2(
peri: impl Peripheral<P = T> + 'd,
d0: impl Peripheral<P = impl BK2D0Pin<T>> + 'd,
d1: impl Peripheral<P = impl BK2D1Pin<T>> + 'd,
d2: impl Peripheral<P = impl BK2D2Pin<T>> + 'd,
d3: impl Peripheral<P = impl BK2D3Pin<T>> + 'd,
sck: impl Peripheral<P = impl SckPin<T>> + 'd,
nss: impl Peripheral<P = impl BK2NSSPin<T>> + 'd,
dma: impl Peripheral<P = Dma> + 'd,
config: Config,
) -> Self {
into_ref!(peri, d0, d1, d2, d3, sck, nss);
sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None);
sck.set_speed(crate::gpio::Speed::VeryHigh);
nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up);
nss.set_speed(crate::gpio::Speed::VeryHigh);
d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None);
d0.set_speed(crate::gpio::Speed::VeryHigh);
d1.set_as_af_pull(d1.af_num(), AFType::OutputPushPull, Pull::None);
d1.set_speed(crate::gpio::Speed::VeryHigh);
d2.set_as_af_pull(d2.af_num(), AFType::OutputPushPull, Pull::None);
d2.set_speed(crate::gpio::Speed::VeryHigh);
d3.set_as_af_pull(d3.af_num(), AFType::OutputPushPull, Pull::None);
d3.set_speed(crate::gpio::Speed::VeryHigh);
Self::new_inner(
peri,
Some(d0.map_into()),
Some(d1.map_into()),
Some(d2.map_into()),
Some(d3.map_into()),
Some(sck.map_into()),
Some(nss.map_into()),
dma,
config,
FlashSelection::Flash2,
) )
} }
@ -132,22 +173,39 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
nss: Option<PeripheralRef<'d, AnyPin>>, nss: Option<PeripheralRef<'d, AnyPin>>,
dma: impl Peripheral<P = Dma> + 'd, dma: impl Peripheral<P = Dma> + 'd,
config: Config, config: Config,
fsel: FlashSelection,
) -> Self { ) -> Self {
into_ref!(peri, dma); into_ref!(peri, dma);
T::enable(); T::enable_and_reset();
T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into()));
while T::REGS.sr().read().busy() {} while T::REGS.sr().read().busy() {}
T::REGS.cr().write(|w| { #[cfg(stm32h7)]
w.set_prescaler(config.prescaler); {
use stm32_metapac::quadspi::regs::Cr;
// Apply precautionary steps according to the errata...
T::REGS.cr().write_value(Cr(0));
while T::REGS.sr().read().busy() {}
T::REGS.cr().write_value(Cr(0xFF000001));
T::REGS.ccr().write(|w| w.set_frcm(true));
T::REGS.ccr().write(|w| w.set_frcm(true));
T::REGS.cr().write_value(Cr(0));
while T::REGS.sr().read().busy() {}
}
T::REGS.cr().modify(|w| {
w.set_en(true); w.set_en(true);
//w.set_tcen(false);
w.set_sshift(false);
w.set_fthres(config.fifo_threshold.into());
w.set_prescaler(config.prescaler);
w.set_fsel(fsel.into());
}); });
T::REGS.dcr().write(|w| { T::REGS.dcr().modify(|w| {
w.set_fsize(config.memory_size.into()); w.set_fsize(config.memory_size.into());
w.set_csht(config.cs_high_time.into()); w.set_csht(config.cs_high_time.into());
w.set_ckmode(false); w.set_ckmode(true);
}); });
Self { Self {
@ -164,6 +222,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
} }
pub fn command(&mut self, transaction: TransferConfig) { pub fn command(&mut self, transaction: TransferConfig) {
#[cfg(not(stm32h7))]
T::REGS.cr().modify(|v| v.set_dmaen(false)); T::REGS.cr().modify(|v| v.set_dmaen(false));
self.setup_transaction(QspiMode::IndirectWrite, &transaction); self.setup_transaction(QspiMode::IndirectWrite, &transaction);
@ -172,6 +231,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
} }
pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) { pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) {
#[cfg(not(stm32h7))]
T::REGS.cr().modify(|v| v.set_dmaen(false)); T::REGS.cr().modify(|v| v.set_dmaen(false));
self.setup_transaction(QspiMode::IndirectWrite, &transaction); self.setup_transaction(QspiMode::IndirectWrite, &transaction);
@ -195,7 +255,10 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
} }
pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) { pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) {
// STM32H7 does not have dmaen
#[cfg(not(stm32h7))]
T::REGS.cr().modify(|v| v.set_dmaen(false)); T::REGS.cr().modify(|v| v.set_dmaen(false));
self.setup_transaction(QspiMode::IndirectWrite, &transaction); self.setup_transaction(QspiMode::IndirectWrite, &transaction);
if let Some(len) = transaction.data_len { if let Some(len) = transaction.data_len {
@ -238,6 +301,8 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
) )
}; };
// STM32H7 does not have dmaen
#[cfg(not(stm32h7))]
T::REGS.cr().modify(|v| v.set_dmaen(true)); T::REGS.cr().modify(|v| v.set_dmaen(true));
transfer.blocking_wait(); transfer.blocking_wait();
@ -264,6 +329,8 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
) )
}; };
// STM32H7 does not have dmaen
#[cfg(not(stm32h7))]
T::REGS.cr().modify(|v| v.set_dmaen(true)); T::REGS.cr().modify(|v| v.set_dmaen(true));
transfer.blocking_wait(); transfer.blocking_wait();
@ -313,11 +380,17 @@ pub(crate) mod sealed {
pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
pin_trait!(SckPin, Instance); pin_trait!(SckPin, Instance);
pin_trait!(D0Pin, Instance); pin_trait!(BK1D0Pin, Instance);
pin_trait!(D1Pin, Instance); pin_trait!(BK1D1Pin, Instance);
pin_trait!(D2Pin, Instance); pin_trait!(BK1D2Pin, Instance);
pin_trait!(D3Pin, Instance); pin_trait!(BK1D3Pin, Instance);
pin_trait!(NSSPin, Instance); pin_trait!(BK1NSSPin, Instance);
pin_trait!(BK2D0Pin, Instance);
pin_trait!(BK2D1Pin, Instance);
pin_trait!(BK2D2Pin, Instance);
pin_trait!(BK2D3Pin, Instance);
pin_trait!(BK2NSSPin, Instance);
dma_trait!(QuadDma, Instance); dma_trait!(QuadDma, Instance);

View File

@ -1,102 +1,161 @@
use core::sync::atomic::{compiler_fence, Ordering};
use crate::pac::common::{Reg, RW};
pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource;
use crate::time::Hertz;
#[cfg(any(stm32f0, stm32f1, stm32f3))]
pub const LSI_FREQ: Hertz = Hertz(40_000);
#[cfg(not(any(stm32f0, stm32f1, stm32f3)))]
pub const LSI_FREQ: Hertz = Hertz(32_000);
#[allow(dead_code)]
#[derive(Clone, Copy)]
pub enum LseMode {
Oscillator(LseDrive),
Bypass,
}
pub struct LseConfig {
pub frequency: Hertz,
pub mode: LseMode,
}
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Default, Clone, Copy)] #[derive(Default, Clone, Copy)]
pub enum LseDrive { pub enum LseDrive {
#[cfg(any(rtc_v2f7, rtc_v2l4))]
Low = 0, Low = 0,
MediumLow = 0x01, MediumLow = 0x01,
#[default] #[default]
MediumHigh = 0x02, MediumHigh = 0x02,
#[cfg(any(rtc_v2f7, rtc_v2l4))]
High = 0x03, High = 0x03,
} }
#[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] // All families but these have the LSEDRV register
#[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f400, rcc_f410, rcc_l1)))]
impl From<LseDrive> for crate::pac::rcc::vals::Lsedrv { impl From<LseDrive> for crate::pac::rcc::vals::Lsedrv {
fn from(value: LseDrive) -> Self { fn from(value: LseDrive) -> Self {
use crate::pac::rcc::vals::Lsedrv; use crate::pac::rcc::vals::Lsedrv;
match value { match value {
#[cfg(any(rtc_v2f7, rtc_v2l4))]
LseDrive::Low => Lsedrv::LOW, LseDrive::Low => Lsedrv::LOW,
LseDrive::MediumLow => Lsedrv::MEDIUMLOW, LseDrive::MediumLow => Lsedrv::MEDIUMLOW,
LseDrive::MediumHigh => Lsedrv::MEDIUMHIGH, LseDrive::MediumHigh => Lsedrv::MEDIUMHIGH,
#[cfg(any(rtc_v2f7, rtc_v2l4))]
LseDrive::High => Lsedrv::HIGH, LseDrive::High => Lsedrv::HIGH,
} }
} }
} }
pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource;
#[cfg(not(any(rtc_v2l0, rtc_v2l1, stm32c0)))] #[cfg(not(any(rtc_v2l0, rtc_v2l1, stm32c0)))]
#[allow(dead_code)]
type Bdcr = crate::pac::rcc::regs::Bdcr; type Bdcr = crate::pac::rcc::regs::Bdcr;
#[cfg(any(rtc_v2l0, rtc_v2l1))] #[cfg(any(rtc_v2l0, rtc_v2l1))]
#[allow(dead_code)]
type Bdcr = crate::pac::rcc::regs::Csr; type Bdcr = crate::pac::rcc::regs::Csr;
#[cfg(any(stm32c0))]
type Bdcr = crate::pac::rcc::regs::Csr1;
#[allow(dead_code)] #[cfg(any(stm32c0))]
pub struct BackupDomain {} fn unlock() {}
impl BackupDomain { #[cfg(not(any(stm32c0)))]
#[cfg(any( fn unlock() {
rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, #[cfg(any(stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1))]
rtc_v3u5 let cr = crate::pac::PWR.cr();
))] #[cfg(not(any(stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1, stm32u5, stm32h5, stm32wba)))]
#[allow(dead_code, unused_variables)] let cr = crate::pac::PWR.cr1();
fn modify<R>(f: impl FnOnce(&mut Bdcr) -> R) -> R { #[cfg(any(stm32u5, stm32h5, stm32wba))]
#[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1, rtc_v2l0))] let cr = crate::pac::PWR.dbpcr();
let cr = crate::pac::PWR.cr();
#[cfg(any(rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
let cr = crate::pac::PWR.cr1();
// TODO: Missing from PAC for l0 and f0? cr.modify(|w| w.set_dbp(true));
#[cfg(not(any(rtc_v2f0, rtc_v3u5)))] while !cr.read().dbp() {}
{ }
cr.modify(|w| w.set_dbp(true));
while !cr.read().dbp() {} fn bdcr() -> Reg<Bdcr, RW> {
#[cfg(any(rtc_v2l0, rtc_v2l1))]
return crate::pac::RCC.csr();
#[cfg(not(any(rtc_v2l0, rtc_v2l1, stm32c0)))]
return crate::pac::RCC.bdcr();
#[cfg(any(stm32c0))]
return crate::pac::RCC.csr1();
}
pub struct LsConfig {
pub rtc: RtcClockSource,
pub lsi: bool,
pub lse: Option<LseConfig>,
}
impl LsConfig {
pub const fn default_lse() -> Self {
Self {
rtc: RtcClockSource::LSE,
lse: Some(LseConfig {
frequency: Hertz(32_768),
mode: LseMode::Oscillator(LseDrive::MediumHigh),
}),
lsi: false,
} }
#[cfg(any(rtc_v2l0, rtc_v2l1))]
let cr = crate::pac::RCC.csr();
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
let cr = crate::pac::RCC.bdcr();
cr.modify(|w| f(w))
} }
#[cfg(any( pub const fn default_lsi() -> Self {
rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, Self {
rtc_v3u5 rtc: RtcClockSource::LSI,
))] lsi: true,
#[allow(dead_code)] lse: None,
fn read() -> Bdcr { }
#[cfg(any(rtc_v2l0, rtc_v2l1))]
let r = crate::pac::RCC.csr().read();
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
let r = crate::pac::RCC.bdcr().read();
r
} }
#[cfg(any( pub const fn off() -> Self {
rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, Self {
rtc_v3u5 rtc: RtcClockSource::NOCLOCK,
))] lsi: false,
#[allow(dead_code, unused_variables)] lse: None,
pub fn configure_ls(clock_source: RtcClockSource, lsi: bool, lse: Option<LseDrive>) { }
if lsi { }
#[cfg(rtc_v3u5)] }
impl Default for LsConfig {
fn default() -> Self {
// on L5, just the fact that LSI is enabled makes things crash.
// TODO: investigate.
#[cfg(not(stm32l5))]
return Self::default_lsi();
#[cfg(stm32l5)]
return Self::off();
}
}
impl LsConfig {
pub(crate) fn init(&self) -> Option<Hertz> {
let rtc_clk = match self.rtc {
RtcClockSource::LSI => {
assert!(self.lsi);
Some(LSI_FREQ)
}
RtcClockSource::LSE => Some(self.lse.as_ref().unwrap().frequency),
RtcClockSource::NOCLOCK => None,
_ => todo!(),
};
let (lse_en, lse_byp, lse_drv) = match &self.lse {
Some(c) => match c.mode {
LseMode::Oscillator(lse_drv) => (true, false, Some(lse_drv)),
LseMode::Bypass => (true, true, None),
},
None => (false, false, None),
};
_ = lse_drv; // not all chips have it.
// Disable backup domain write protection
unlock();
if self.lsi {
#[cfg(any(stm32u5, stm32h5, stm32wba))]
let csr = crate::pac::RCC.bdcr(); let csr = crate::pac::RCC.bdcr();
#[cfg(not(any(stm32u5, stm32h5, stm32wba, stm32c0)))]
#[cfg(not(rtc_v3u5))]
let csr = crate::pac::RCC.csr(); let csr = crate::pac::RCC.csr();
#[cfg(any(stm32c0))]
// Disable backup domain write protection let csr = crate::pac::RCC.csr2();
Self::modify(|_| {});
#[cfg(not(any(rcc_wb, rcc_wba)))] #[cfg(not(any(rcc_wb, rcc_wba)))]
csr.modify(|w| w.set_lsion(true)); csr.modify(|w| w.set_lsion(true));
@ -111,66 +170,76 @@ impl BackupDomain {
while !csr.read().lsi1rdy() {} while !csr.read().lsi1rdy() {}
} }
if let Some(lse_drive) = lse { // backup domain configuration (LSEON, RTCEN, RTCSEL) is kept across resets.
Self::modify(|w| { // once set, changing it requires a backup domain reset.
#[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] // first check if the configuration matches what we want.
w.set_lsedrv(lse_drive.into());
// check if it's already enabled and in the source we want.
let reg = bdcr().read();
let mut ok = true;
ok &= reg.rtcsel() == self.rtc;
#[cfg(not(rcc_wba))]
{
ok &= reg.rtcen() == (self.rtc != RtcClockSource::NOCLOCK);
}
ok &= reg.lseon() == lse_en;
ok &= reg.lsebyp() == lse_byp;
#[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f400, rcc_f410, rcc_l1)))]
if let Some(lse_drv) = lse_drv {
ok &= reg.lsedrv() == lse_drv.into();
}
// if configuration is OK, we're done.
if ok {
trace!("BDCR ok: {:08x}", bdcr().read().0);
return rtc_clk;
}
// If not OK, reset backup domain and configure it.
#[cfg(not(any(rcc_l0, rcc_l0_v2, rcc_l1, stm32h5, stm32c0)))]
{
bdcr().modify(|w| w.set_bdrst(true));
bdcr().modify(|w| w.set_bdrst(false));
}
#[cfg(any(stm32h5))]
{
bdcr().modify(|w| w.set_vswrst(true));
bdcr().modify(|w| w.set_vswrst(false));
}
#[cfg(any(stm32c0))]
{
bdcr().modify(|w| w.set_rtcrst(true));
bdcr().modify(|w| w.set_rtcrst(false));
}
if lse_en {
bdcr().modify(|w| {
#[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f400, rcc_f410, rcc_l1)))]
if let Some(lse_drv) = lse_drv {
w.set_lsedrv(lse_drv.into());
}
w.set_lsebyp(lse_byp);
w.set_lseon(true); w.set_lseon(true);
}); });
while !Self::read().lserdy() {} while !bdcr().read().lserdy() {}
} }
match clock_source { if self.rtc != RtcClockSource::NOCLOCK {
RtcClockSource::LSI => assert!(lsi), bdcr().modify(|w| {
RtcClockSource::LSE => assert!(&lse.is_some()),
_ => {}
};
if clock_source == RtcClockSource::NOCLOCK {
// disable it
Self::modify(|w| {
#[cfg(not(rcc_wba))]
w.set_rtcen(false);
w.set_rtcsel(clock_source);
});
} else {
// check if it's already enabled and in the source we want.
let reg = Self::read();
let ok = reg.rtcsel() == clock_source;
#[cfg(not(rcc_wba))]
let ok = ok & reg.rtcen();
// if not, configure it.
if !ok {
#[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
#[cfg(not(any(rcc_l0, rcc_l1)))] #[cfg(not(rcc_wba))]
Self::modify(|w| w.set_bdrst(true)); w.set_rtcen(true);
w.set_rtcsel(self.rtc);
Self::modify(|w| { });
// Reset
#[cfg(not(any(rcc_l0, rcc_l1)))]
w.set_bdrst(false);
#[cfg(not(rcc_wba))]
w.set_rtcen(true);
w.set_rtcsel(clock_source);
// Restore bcdr
#[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
w.set_lscosel(reg.lscosel());
#[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
w.set_lscoen(reg.lscoen());
w.set_lseon(reg.lseon());
#[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
w.set_lsedrv(reg.lsedrv());
w.set_lsebyp(reg.lsebyp());
});
}
} }
trace!("BDCR configured: {:08x}", bdcr().read().0);
compiler_fence(Ordering::SeqCst);
rtc_clk
} }
} }

View File

@ -1,56 +0,0 @@
use core::ops::Div;
#[allow(unused_imports)]
use crate::pac::rcc;
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler};
use crate::time::Hertz;
impl Div<AHBPrescaler> for Hertz {
type Output = Hertz;
fn div(self, rhs: AHBPrescaler) -> Self::Output {
let divisor = match rhs {
AHBPrescaler::DIV1 => 1,
AHBPrescaler::DIV2 => 2,
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
AHBPrescaler::DIV3 => 3,
AHBPrescaler::DIV4 => 4,
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
AHBPrescaler::DIV5 => 5,
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
AHBPrescaler::DIV6 => 6,
AHBPrescaler::DIV8 => 8,
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
AHBPrescaler::DIV10 => 10,
AHBPrescaler::DIV16 => 16,
#[cfg(any(rcc_wb, rcc_wl5, rcc_wle))]
AHBPrescaler::DIV32 => 32,
#[cfg(not(rcc_wba))]
AHBPrescaler::DIV64 => 64,
#[cfg(not(rcc_wba))]
AHBPrescaler::DIV128 => 128,
#[cfg(not(rcc_wba))]
AHBPrescaler::DIV256 => 256,
#[cfg(not(rcc_wba))]
AHBPrescaler::DIV512 => 512,
_ => unreachable!(),
};
Hertz(self.0 / divisor)
}
}
impl Div<APBPrescaler> for Hertz {
type Output = Hertz;
fn div(self, rhs: APBPrescaler) -> Self::Output {
let divisor = match rhs {
APBPrescaler::DIV1 => 1,
APBPrescaler::DIV2 => 2,
APBPrescaler::DIV4 => 4,
APBPrescaler::DIV8 => 8,
APBPrescaler::DIV16 => 16,
_ => unreachable!(),
};
Hertz(self.0 / divisor)
}
}

View File

@ -1,6 +1,6 @@
pub use super::bus::{AHBPrescaler, APBPrescaler};
use crate::pac::flash::vals::Latency; use crate::pac::flash::vals::Latency;
use crate::pac::rcc::vals::{Hsidiv, Ppre, Sw}; use crate::pac::rcc::vals::Sw;
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Hsidiv as HSIPrescaler, Ppre as APBPrescaler};
use crate::pac::{FLASH, RCC}; use crate::pac::{FLASH, RCC};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
@ -8,9 +8,6 @@ use crate::time::Hertz;
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(48_000_000); pub const HSI_FREQ: Hertz = Hertz(48_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
/// System clock mux source /// System clock mux source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum ClockSrc { pub enum ClockSrc {
@ -19,47 +16,22 @@ pub enum ClockSrc {
LSI, LSI,
} }
#[derive(Clone, Copy)]
pub enum HSIPrescaler {
NotDivided,
Div2,
Div4,
Div8,
Div16,
Div32,
Div64,
Div128,
}
impl Into<Hsidiv> for HSIPrescaler {
fn into(self) -> Hsidiv {
match self {
HSIPrescaler::NotDivided => Hsidiv::DIV1,
HSIPrescaler::Div2 => Hsidiv::DIV2,
HSIPrescaler::Div4 => Hsidiv::DIV4,
HSIPrescaler::Div8 => Hsidiv::DIV8,
HSIPrescaler::Div16 => Hsidiv::DIV16,
HSIPrescaler::Div32 => Hsidiv::DIV32,
HSIPrescaler::Div64 => Hsidiv::DIV64,
HSIPrescaler::Div128 => Hsidiv::DIV128,
}
}
}
/// Clocks configutation /// Clocks configutation
pub struct Config { pub struct Config {
pub mux: ClockSrc, pub mux: ClockSrc,
pub ahb_pre: AHBPrescaler, pub ahb_pre: AHBPrescaler,
pub apb_pre: APBPrescaler, pub apb_pre: APBPrescaler,
pub ls: super::LsConfig,
} }
impl Default for Config { impl Default for Config {
#[inline] #[inline]
fn default() -> Config { fn default() -> Config {
Config { Config {
mux: ClockSrc::HSI(HSIPrescaler::NotDivided), mux: ClockSrc::HSI(HSIPrescaler::DIV1),
ahb_pre: AHBPrescaler::DIV1, ahb_pre: AHBPrescaler::DIV1,
apb_pre: APBPrescaler::DIV1, apb_pre: APBPrescaler::DIV1,
ls: Default::default(),
} }
} }
} }
@ -68,33 +40,34 @@ pub(crate) unsafe fn init(config: Config) {
let (sys_clk, sw) = match config.mux { let (sys_clk, sw) = match config.mux {
ClockSrc::HSI(div) => { ClockSrc::HSI(div) => {
// Enable HSI // Enable HSI
let div: Hsidiv = div.into();
RCC.cr().write(|w| { RCC.cr().write(|w| {
w.set_hsidiv(div); w.set_hsidiv(div);
w.set_hsion(true) w.set_hsion(true)
}); });
while !RCC.cr().read().hsirdy() {} while !RCC.cr().read().hsirdy() {}
(HSI_FREQ.0 >> div.to_bits(), Sw::HSI) (HSI_FREQ / div, Sw::HSI)
} }
ClockSrc::HSE(freq) => { ClockSrc::HSE(freq) => {
// Enable HSE // Enable HSE
RCC.cr().write(|w| w.set_hseon(true)); RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {} while !RCC.cr().read().hserdy() {}
(freq.0, Sw::HSE) (freq, Sw::HSE)
} }
ClockSrc::LSI => { ClockSrc::LSI => {
// Enable LSI // Enable LSI
RCC.csr2().write(|w| w.set_lsion(true)); RCC.csr2().write(|w| w.set_lsion(true));
while !RCC.csr2().read().lsirdy() {} while !RCC.csr2().read().lsirdy() {}
(LSI_FREQ.0, Sw::LSI) (super::LSI_FREQ, Sw::LSI)
} }
}; };
let rtc = config.ls.init();
// Determine the flash latency implied by the target clock speed // Determine the flash latency implied by the target clock speed
// RM0454 § 3.3.4: // RM0454 § 3.3.4:
let target_flash_latency = if sys_clk <= 24_000_000 { let target_flash_latency = if sys_clk <= Hertz(24_000_000) {
Latency::WS0 Latency::WS0
} else { } else {
Latency::WS1 Latency::WS1
@ -129,7 +102,7 @@ pub(crate) unsafe fn init(config: Config) {
} }
// Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once
let (sw, hpre, ppre) = (sw.into(), config.ahb_pre.into(), config.apb_pre.into()); let (sw, hpre, ppre) = (sw.into(), config.ahb_pre, config.apb_pre);
RCC.cfgr().modify(|w| { RCC.cfgr().modify(|w| {
w.set_sw(sw); w.set_sw(sw);
w.set_hpre(hpre); w.set_hpre(hpre);
@ -150,34 +123,21 @@ pub(crate) unsafe fn init(config: Config) {
FLASH.acr().modify(|w| w.set_latency(target_flash_latency)); FLASH.acr().modify(|w| w.set_latency(target_flash_latency));
} }
let ahb_div = match config.ahb_pre { let ahb_freq = sys_clk / config.ahb_pre;
AHBPrescaler::DIV1 => 1,
AHBPrescaler::DIV2 => 2,
AHBPrescaler::DIV4 => 4,
AHBPrescaler::DIV8 => 8,
AHBPrescaler::DIV16 => 16,
AHBPrescaler::DIV64 => 64,
AHBPrescaler::DIV128 => 128,
AHBPrescaler::DIV256 => 256,
AHBPrescaler::DIV512 => 512,
_ => unreachable!(),
};
let ahb_freq = sys_clk / ahb_div;
let (apb_freq, apb_tim_freq) = match config.apb_pre { let (apb_freq, apb_tim_freq) = match config.apb_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq), APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => { pre => {
let pre: Ppre = pre.into(); let freq = ahb_freq / pre;
let pre: u8 = 1 << (pre.to_bits() - 3); (freq, freq * 2u32)
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
} }
}; };
set_freqs(Clocks { set_freqs(Clocks {
sys: Hertz(sys_clk), sys: sys_clk,
ahb1: Hertz(ahb_freq), ahb1: ahb_freq,
apb1: Hertz(apb_freq), apb1: apb_freq,
apb1_tim: Hertz(apb_tim_freq), apb1_tim: apb_tim_freq,
rtc,
}); });
} }

View File

@ -8,9 +8,6 @@ use crate::time::Hertz;
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(8_000_000); pub const HSI_FREQ: Hertz = Hertz(8_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(40_000);
/// Configuration of the clocks /// Configuration of the clocks
/// ///
/// hse takes precedence over hsi48 if both are enabled /// hse takes precedence over hsi48 if both are enabled
@ -27,6 +24,8 @@ pub struct Config {
pub sys_ck: Option<Hertz>, pub sys_ck: Option<Hertz>,
pub hclk: Option<Hertz>, pub hclk: Option<Hertz>,
pub pclk: Option<Hertz>, pub pclk: Option<Hertz>,
pub ls: super::LsConfig,
} }
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
@ -159,6 +158,8 @@ pub(crate) unsafe fn init(config: Config) {
}) })
} }
let rtc = config.ls.init();
set_freqs(Clocks { set_freqs(Clocks {
sys: Hertz(real_sysclk), sys: Hertz(real_sysclk),
apb1: Hertz(pclk), apb1: Hertz(pclk),
@ -166,5 +167,6 @@ pub(crate) unsafe fn init(config: Config) {
apb1_tim: Hertz(pclk * timer_mul), apb1_tim: Hertz(pclk * timer_mul),
apb2_tim: Hertz(pclk * timer_mul), apb2_tim: Hertz(pclk * timer_mul),
ahb1: Hertz(hclk), ahb1: Hertz(hclk),
rtc,
}); });
} }

View File

@ -9,9 +9,6 @@ use crate::time::Hertz;
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(8_000_000); pub const HSI_FREQ: Hertz = Hertz(8_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(40_000);
/// Configuration of the clocks /// Configuration of the clocks
/// ///
#[non_exhaustive] #[non_exhaustive]
@ -25,6 +22,8 @@ pub struct Config {
pub pclk2: Option<Hertz>, pub pclk2: Option<Hertz>,
pub adcclk: Option<Hertz>, pub adcclk: Option<Hertz>,
pub pllxtpre: bool, pub pllxtpre: bool,
pub ls: super::LsConfig,
} }
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
@ -177,6 +176,8 @@ pub(crate) unsafe fn init(config: Config) {
}); });
}); });
let rtc = config.ls.init();
set_freqs(Clocks { set_freqs(Clocks {
sys: Hertz(real_sysclk), sys: Hertz(real_sysclk),
apb1: Hertz(pclk1), apb1: Hertz(pclk1),
@ -185,5 +186,6 @@ pub(crate) unsafe fn init(config: Config) {
apb2_tim: Hertz(pclk2 * timer_mul2), apb2_tim: Hertz(pclk2 * timer_mul2),
ahb1: Hertz(hclk), ahb1: Hertz(hclk),
adc: Some(Hertz(adcclk)), adc: Some(Hertz(adcclk)),
rtc,
}); });
} }

View File

@ -1,21 +1,16 @@
use core::convert::TryFrom;
use core::ops::{Div, Mul};
pub use super::bus::{AHBPrescaler, APBPrescaler};
use crate::pac::flash::vals::Latency; use crate::pac::flash::vals::Latency;
use crate::pac::rcc::vals::{Pllp, Pllsrc, Sw}; use crate::pac::rcc::vals::Sw;
pub use crate::pac::rcc::vals::{
Hpre as AHBPrescaler, Pllm as PLLPreDiv, Plln as PLLMul, Pllp as PLLPDiv, Pllq as PLLQDiv, Pllsrc as PLLSrc,
Ppre as APBPrescaler,
};
use crate::pac::{FLASH, RCC}; use crate::pac::{FLASH, RCC};
use crate::rcc::bd::BackupDomain;
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::rtc::RtcClockSource;
use crate::time::Hertz; use crate::time::Hertz;
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000); pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct HSEConfig { pub struct HSEConfig {
pub frequency: Hertz, pub frequency: Hertz,
@ -43,17 +38,17 @@ pub enum HSESrc {
pub struct PLLConfig { pub struct PLLConfig {
pub pre_div: PLLPreDiv, pub pre_div: PLLPreDiv,
pub mul: PLLMul, pub mul: PLLMul,
pub main_div: PLLMainDiv, pub p_div: PLLPDiv,
pub pll48_div: PLL48Div, pub q_div: PLLQDiv,
} }
impl Default for PLLConfig { impl Default for PLLConfig {
fn default() -> Self { fn default() -> Self {
PLLConfig { PLLConfig {
pre_div: PLLPreDiv(16), pre_div: PLLPreDiv::DIV16,
mul: PLLMul(192), mul: PLLMul::MUL192,
main_div: PLLMainDiv::Div2, p_div: PLLPDiv::DIV2,
pll48_div: PLL48Div(4), q_div: PLLQDiv::DIV4,
} }
} }
} }
@ -61,9 +56,9 @@ impl Default for PLLConfig {
impl PLLConfig { impl PLLConfig {
pub fn clocks(&self, src_freq: Hertz) -> PLLClocks { pub fn clocks(&self, src_freq: Hertz) -> PLLClocks {
let in_freq = src_freq / self.pre_div; let in_freq = src_freq / self.pre_div;
let vco_freq = Hertz((src_freq.0 as u64 * self.mul.0 as u64 / self.pre_div.0 as u64) as u32); let vco_freq = src_freq / self.pre_div * self.mul;
let main_freq = vco_freq / self.main_div; let main_freq = vco_freq / self.p_div;
let pll48_freq = vco_freq / self.pll48_div; let pll48_freq = vco_freq / self.q_div;
PLLClocks { PLLClocks {
in_freq, in_freq,
vco_freq, vco_freq,
@ -72,129 +67,6 @@ impl PLLConfig {
} }
} }
} }
/// Clock source for both main PLL and PLLI2S
#[derive(Clone, Copy, PartialEq)]
pub enum PLLSrc {
HSE,
HSI,
}
impl Into<Pllsrc> for PLLSrc {
fn into(self) -> Pllsrc {
match self {
PLLSrc::HSE => Pllsrc::HSE,
PLLSrc::HSI => Pllsrc::HSI,
}
}
}
/// Division factor for both main PLL and PLLI2S
#[derive(Clone, Copy, PartialEq)]
#[repr(transparent)]
pub struct PLLPreDiv(u8);
impl TryFrom<u8> for PLLPreDiv {
type Error = &'static str;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
2..=63 => Ok(PLLPreDiv(value)),
_ => Err("PLLPreDiv must be within range 2..=63"),
}
}
}
impl Div<PLLPreDiv> for Hertz {
type Output = Hertz;
fn div(self, rhs: PLLPreDiv) -> Self::Output {
Hertz(self.0 / u32::from(rhs.0))
}
}
/// Multiplication factor for main PLL
#[derive(Clone, Copy, PartialEq)]
#[repr(transparent)]
pub struct PLLMul(u16);
impl Mul<PLLMul> for Hertz {
type Output = Hertz;
fn mul(self, rhs: PLLMul) -> Self::Output {
Hertz(self.0 * u32::from(rhs.0))
}
}
impl TryFrom<u16> for PLLMul {
type Error = &'static str;
fn try_from(value: u16) -> Result<Self, Self::Error> {
match value {
192..=432 => Ok(PLLMul(value)),
_ => Err("PLLMul must be within range 192..=432"),
}
}
}
/// PLL division factor for the main system clock
#[derive(Clone, Copy, PartialEq)]
pub enum PLLMainDiv {
Div2,
Div4,
Div6,
Div8,
}
impl Into<Pllp> for PLLMainDiv {
fn into(self) -> Pllp {
match self {
PLLMainDiv::Div2 => Pllp::DIV2,
PLLMainDiv::Div4 => Pllp::DIV4,
PLLMainDiv::Div6 => Pllp::DIV6,
PLLMainDiv::Div8 => Pllp::DIV8,
}
}
}
impl Div<PLLMainDiv> for Hertz {
type Output = Hertz;
fn div(self, rhs: PLLMainDiv) -> Self::Output {
let divisor = match rhs {
PLLMainDiv::Div2 => 2,
PLLMainDiv::Div4 => 4,
PLLMainDiv::Div6 => 6,
PLLMainDiv::Div8 => 8,
};
Hertz(self.0 / divisor)
}
}
/// PLL division factor for USB OTG FS / SDIO / RNG
#[derive(Clone, Copy, PartialEq)]
#[repr(transparent)]
pub struct PLL48Div(u8);
impl Div<PLL48Div> for Hertz {
type Output = Hertz;
fn div(self, rhs: PLL48Div) -> Self::Output {
Hertz(self.0 / u32::from(rhs.0))
}
}
impl TryFrom<u8> for PLL48Div {
type Error = &'static str;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
2..=15 => Ok(PLL48Div(value)),
_ => Err("PLL48Div must be within range 2..=15"),
}
}
}
#[derive(Clone, Copy, PartialEq)] #[derive(Clone, Copy, PartialEq)]
pub struct PLLClocks { pub struct PLLClocks {
pub in_freq: Hertz, pub in_freq: Hertz,
@ -303,13 +175,11 @@ pub struct Config {
pub pll_mux: PLLSrc, pub pll_mux: PLLSrc,
pub pll: PLLConfig, pub pll: PLLConfig,
pub mux: ClockSrc, pub mux: ClockSrc,
pub rtc: Option<RtcClockSource>,
pub lsi: bool,
pub lse: Option<Hertz>,
pub voltage: VoltageScale, pub voltage: VoltageScale,
pub ahb_pre: AHBPrescaler, pub ahb_pre: AHBPrescaler,
pub apb1_pre: APBPrescaler, pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler, pub apb2_pre: APBPrescaler,
pub ls: super::LsConfig,
} }
impl Default for Config { impl Default for Config {
@ -322,12 +192,10 @@ impl Default for Config {
pll: PLLConfig::default(), pll: PLLConfig::default(),
voltage: VoltageScale::Range3, voltage: VoltageScale::Range3,
mux: ClockSrc::HSI, mux: ClockSrc::HSI,
rtc: None,
lsi: false,
lse: None,
ahb_pre: AHBPrescaler::DIV1, ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1,
ls: Default::default(),
} }
} }
} }
@ -367,11 +235,11 @@ pub(crate) unsafe fn init(config: Config) {
assert!(pll_clocks.pll48_freq <= Hertz(48_000_000)); assert!(pll_clocks.pll48_freq <= Hertz(48_000_000));
RCC.pllcfgr().write(|w| { RCC.pllcfgr().write(|w| {
w.set_pllsrc(config.pll_mux.into()); w.set_pllsrc(config.pll_mux);
w.set_pllm(config.pll.pre_div.0); w.set_pllm(config.pll.pre_div);
w.set_plln(config.pll.mul.0); w.set_plln(config.pll.mul);
w.set_pllp(config.pll.main_div.into()); w.set_pllp(config.pll.p_div);
w.set_pllq(config.pll.pll48_div.0); w.set_pllq(config.pll.q_div);
}); });
let (sys_clk, sw) = match config.mux { let (sys_clk, sw) = match config.mux {
@ -424,9 +292,9 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cfgr().modify(|w| { RCC.cfgr().modify(|w| {
w.set_sw(sw.into()); w.set_sw(sw.into());
w.set_hpre(config.ahb_pre.into()); w.set_hpre(config.ahb_pre);
w.set_ppre1(config.apb1_pre.into()); w.set_ppre1(config.apb1_pre);
w.set_ppre2(config.apb2_pre.into()); w.set_ppre2(config.apb2_pre);
}); });
while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {} while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {}
@ -435,11 +303,7 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cr().modify(|w| w.set_hsion(false)); RCC.cr().modify(|w| w.set_hsion(false));
} }
BackupDomain::configure_ls( let rtc = config.ls.init();
config.rtc.unwrap_or(RtcClockSource::NOCLOCK),
config.lsi,
config.lse.map(|_| Default::default()),
);
set_freqs(Clocks { set_freqs(Clocks {
sys: sys_clk, sys: sys_clk,
@ -451,5 +315,6 @@ pub(crate) unsafe fn init(config: Config) {
apb2: apb2_freq, apb2: apb2_freq,
apb2_tim: apb2_tim_freq, apb2_tim: apb2_tim_freq,
pll48: Some(pll_clocks.pll48_freq), pll48: Some(pll_clocks.pll48_freq),
rtc,
}); });
} }

View File

@ -1,7 +1,8 @@
#[cfg(rcc_f3)] #[cfg(rcc_f3)]
use crate::pac::adccommon::vals::Ckmode; use crate::pac::adccommon::vals::Ckmode;
use crate::pac::flash::vals::Latency; use crate::pac::flash::vals::Latency;
use crate::pac::rcc::vals::{Adcpres, Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre}; pub use crate::pac::rcc::vals::Adcpres;
use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre};
use crate::pac::{FLASH, RCC}; use crate::pac::{FLASH, RCC};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
@ -9,28 +10,6 @@ use crate::time::Hertz;
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(8_000_000); pub const HSI_FREQ: Hertz = Hertz(8_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(40_000);
impl From<AdcClockSource> for Adcpres {
fn from(value: AdcClockSource) -> Self {
match value {
AdcClockSource::PllDiv1 => Adcpres::DIV1,
AdcClockSource::PllDiv2 => Adcpres::DIV2,
AdcClockSource::PllDiv4 => Adcpres::DIV4,
AdcClockSource::PllDiv6 => Adcpres::DIV6,
AdcClockSource::PllDiv8 => Adcpres::DIV8,
AdcClockSource::PllDiv12 => Adcpres::DIV12,
AdcClockSource::PllDiv16 => Adcpres::DIV16,
AdcClockSource::PllDiv32 => Adcpres::DIV32,
AdcClockSource::PllDiv64 => Adcpres::DIV64,
AdcClockSource::PllDiv128 => Adcpres::DIV128,
AdcClockSource::PllDiv256 => Adcpres::DIV256,
_ => unreachable!(),
}
}
}
#[cfg(rcc_f3)] #[cfg(rcc_f3)]
impl From<AdcClockSource> for Ckmode { impl From<AdcClockSource> for Ckmode {
fn from(value: AdcClockSource) -> Self { fn from(value: AdcClockSource) -> Self {
@ -45,32 +24,13 @@ impl From<AdcClockSource> for Ckmode {
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum AdcClockSource { pub enum AdcClockSource {
PllDiv1 = 1, Pll(Adcpres),
PllDiv2 = 2,
PllDiv4 = 4,
PllDiv6 = 6,
PllDiv8 = 8,
PllDiv12 = 12,
PllDiv16 = 16,
PllDiv32 = 32,
PllDiv64 = 64,
PllDiv128 = 128,
PllDiv256 = 256,
BusDiv1, BusDiv1,
BusDiv2, BusDiv2,
BusDiv4, BusDiv4,
} }
impl AdcClockSource { impl AdcClockSource {
pub fn is_bus(&self) -> bool {
match self {
Self::BusDiv1 => true,
Self::BusDiv2 => true,
Self::BusDiv4 => true,
_ => false,
}
}
pub fn bus_div(&self) -> u32 { pub fn bus_div(&self) -> u32 {
match self { match self {
Self::BusDiv1 => 1, Self::BusDiv1 => 1,
@ -124,6 +84,7 @@ pub struct Config {
pub adc34: Option<AdcClockSource>, pub adc34: Option<AdcClockSource>,
#[cfg(stm32f334)] #[cfg(stm32f334)]
pub hrtim: HrtimClockSource, pub hrtim: HrtimClockSource,
pub ls: super::LsConfig,
} }
// Information required to setup the PLL clock // Information required to setup the PLL clock
@ -137,67 +98,67 @@ struct PllConfig {
/// Initialize and Set the clock frequencies /// Initialize and Set the clock frequencies
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
// Calculate the real System clock, and PLL configuration if applicable // Calculate the real System clock, and PLL configuration if applicable
let (Hertz(sysclk), pll_config) = get_sysclk(&config); let (sysclk, pll_config) = get_sysclk(&config);
assert!(sysclk <= 72_000_000); assert!(sysclk.0 <= 72_000_000);
// Calculate real AHB clock // Calculate real AHB clock
let hclk = config.hclk.map(|h| h.0).unwrap_or(sysclk); let hclk = config.hclk.map(|h| h).unwrap_or(sysclk);
let (hpre_bits, hpre_div) = match sysclk / hclk { let hpre = match sysclk.0 / hclk.0 {
0 => unreachable!(), 0 => unreachable!(),
1 => (Hpre::DIV1, 1), 1 => Hpre::DIV1,
2 => (Hpre::DIV2, 2), 2 => Hpre::DIV2,
3..=5 => (Hpre::DIV4, 4), 3..=5 => Hpre::DIV4,
6..=11 => (Hpre::DIV8, 8), 6..=11 => Hpre::DIV8,
12..=39 => (Hpre::DIV16, 16), 12..=39 => Hpre::DIV16,
40..=95 => (Hpre::DIV64, 64), 40..=95 => Hpre::DIV64,
96..=191 => (Hpre::DIV128, 128), 96..=191 => Hpre::DIV128,
192..=383 => (Hpre::DIV256, 256), 192..=383 => Hpre::DIV256,
_ => (Hpre::DIV512, 512), _ => Hpre::DIV512,
}; };
let hclk = sysclk / hpre_div; let hclk = sysclk / hpre;
assert!(hclk <= 72_000_000); assert!(hclk <= Hertz(72_000_000));
// Calculate real APB1 clock // Calculate real APB1 clock
let pclk1 = config.pclk1.map(|p| p.0).unwrap_or(hclk); let pclk1 = config.pclk1.unwrap_or(hclk);
let (ppre1_bits, ppre1) = match hclk / pclk1 { let ppre1 = match hclk / pclk1 {
0 => unreachable!(), 0 => unreachable!(),
1 => (Ppre::DIV1, 1), 1 => Ppre::DIV1,
2 => (Ppre::DIV2, 2), 2 => Ppre::DIV2,
3..=5 => (Ppre::DIV4, 4), 3..=5 => Ppre::DIV4,
6..=11 => (Ppre::DIV8, 8), 6..=11 => Ppre::DIV8,
_ => (Ppre::DIV16, 16), _ => Ppre::DIV16,
}; };
let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; let timer_mul1 = if ppre1 == Ppre::DIV1 { 1u32 } else { 2 };
let pclk1 = hclk / ppre1; let pclk1 = hclk / ppre1;
assert!(pclk1 <= 36_000_000); assert!(pclk1 <= Hertz(36_000_000));
// Calculate real APB2 clock // Calculate real APB2 clock
let pclk2 = config.pclk2.map(|p| p.0).unwrap_or(hclk); let pclk2 = config.pclk2.unwrap_or(hclk);
let (ppre2_bits, ppre2) = match hclk / pclk2 { let ppre2 = match hclk / pclk2 {
0 => unreachable!(), 0 => unreachable!(),
1 => (Ppre::DIV1, 1), 1 => Ppre::DIV1,
2 => (Ppre::DIV2, 2), 2 => Ppre::DIV2,
3..=5 => (Ppre::DIV4, 4), 3..=5 => Ppre::DIV4,
6..=11 => (Ppre::DIV8, 8), 6..=11 => Ppre::DIV8,
_ => (Ppre::DIV16, 16), _ => Ppre::DIV16,
}; };
let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; let timer_mul2 = if ppre2 == Ppre::DIV1 { 1u32 } else { 2 };
let pclk2 = hclk / ppre2; let pclk2 = hclk / ppre2;
assert!(pclk2 <= 72_000_000); assert!(pclk2 <= Hertz(72_000_000));
// Set latency based on HCLK frquency // Set latency based on HCLK frquency
// RM0316: "The prefetch buffer must be kept on when using a prescaler // RM0316: "The prefetch buffer must be kept on when using a prescaler
// different from 1 on the AHB clock.", "Half-cycle access cannot be // different from 1 on the AHB clock.", "Half-cycle access cannot be
// used when there is a prescaler different from 1 on the AHB clock" // used when there is a prescaler different from 1 on the AHB clock"
FLASH.acr().modify(|w| { FLASH.acr().modify(|w| {
w.set_latency(if hclk <= 24_000_000 { w.set_latency(if hclk <= Hertz(24_000_000) {
Latency::WS0 Latency::WS0
} else if hclk <= 48_000_000 { } else if hclk <= Hertz(48_000_000) {
Latency::WS1 Latency::WS1
} else { } else {
Latency::WS2 Latency::WS2
}); });
if hpre_div != 1 { if hpre != Hpre::DIV1 {
w.set_hlfcya(false); w.set_hlfcya(false);
w.set_prftbe(true); w.set_prftbe(true);
} }
@ -240,9 +201,9 @@ pub(crate) unsafe fn init(config: Config) {
// Set prescalers // Set prescalers
// CFGR has been written before (PLL, PLL48) don't overwrite these settings // CFGR has been written before (PLL, PLL48) don't overwrite these settings
RCC.cfgr().modify(|w| { RCC.cfgr().modify(|w| {
w.set_ppre2(ppre2_bits); w.set_ppre2(ppre2);
w.set_ppre1(ppre1_bits); w.set_ppre1(ppre1);
w.set_hpre(hpre_bits); w.set_hpre(hpre);
}); });
// Wait for the new prescalers to kick in // Wait for the new prescalers to kick in
@ -260,45 +221,43 @@ pub(crate) unsafe fn init(config: Config) {
}); });
#[cfg(rcc_f3)] #[cfg(rcc_f3)]
let adc = config.adc.map(|adc| { let adc = config.adc.map(|adc| match adc {
if !adc.is_bus() { AdcClockSource::Pll(adcpres) => {
RCC.cfgr2().modify(|w| { RCC.cfgr2().modify(|w| {
// Make sure that we're using the PLL // Make sure that we're using the PLL
pll_config.unwrap(); pll_config.unwrap();
w.set_adc12pres(adc.into()); w.set_adc12pres(adcpres);
Hertz(sysclk / adc as u32) sysclk / adcpres
})
} else {
crate::pac::ADC_COMMON.ccr().modify(|w| {
assert!(!(adc.bus_div() == 1 && hpre_bits != Hpre::DIV1));
w.set_ckmode(adc.into());
Hertz(sysclk / adc.bus_div() as u32)
}) })
} }
_ => crate::pac::ADC_COMMON.ccr().modify(|w| {
assert!(!(adc.bus_div() == 1 && hpre != Hpre::DIV1));
w.set_ckmode(adc.into());
sysclk / adc.bus_div()
}),
}); });
#[cfg(all(rcc_f3, adc3_common))] #[cfg(all(rcc_f3, adc3_common))]
let adc34 = config.adc.map(|adc| { let adc34 = config.adc34.map(|adc| match adc {
if !adc.is_bus() { AdcClockSource::Pll(adcpres) => {
RCC.cfgr2().modify(|w| { RCC.cfgr2().modify(|w| {
// Make sure that we're using the PLL // Make sure that we're using the PLL
pll_config.unwrap(); pll_config.unwrap();
w.set_adc12pres(adc.into()); w.set_adc34pres(adcpres);
Hertz(sysclk / adc as u32) sysclk / adcpres
})
} else {
crate::pac::ADC3_COMMON.ccr().modify(|w| {
assert!(!(adc.bus_div() == 1 && hpre_bits != Hpre::DIV1));
w.set_ckmode(adc.into());
Hertz(sysclk / adc.bus_div() as u32)
}) })
} }
_ => crate::pac::ADC_COMMON.ccr().modify(|w| {
assert!(!(adc.bus_div() == 1 && hpre != Hpre::DIV1));
w.set_ckmode(adc.into());
sysclk / adc.bus_div()
}),
}); });
#[cfg(stm32f334)] #[cfg(stm32f334)]
@ -310,21 +269,23 @@ pub(crate) unsafe fn init(config: Config) {
// Make sure that we're using the PLL // Make sure that we're using the PLL
pll_config.unwrap(); pll_config.unwrap();
assert!((pclk2 == sysclk) || (pclk2 * 2 == sysclk)); assert!((pclk2 == sysclk) || (pclk2 * 2u32 == sysclk));
RCC.cfgr3().modify(|w| w.set_hrtim1sw(Timsw::PLL)); RCC.cfgr3().modify(|w| w.set_hrtim1sw(Timsw::PLL));
Some(Hertz(sysclk * 2)) Some(sysclk * 2u32)
} }
}; };
let rtc = config.ls.init();
set_freqs(Clocks { set_freqs(Clocks {
sys: Hertz(sysclk), sys: sysclk,
apb1: Hertz(pclk1), apb1: pclk1,
apb2: Hertz(pclk2), apb2: pclk2,
apb1_tim: Hertz(pclk1 * timer_mul1), apb1_tim: pclk1 * timer_mul1,
apb2_tim: Hertz(pclk2 * timer_mul2), apb2_tim: pclk2 * timer_mul2,
ahb1: Hertz(hclk), ahb1: hclk,
#[cfg(rcc_f3)] #[cfg(rcc_f3)]
adc: adc, adc: adc,
#[cfg(all(rcc_f3, adc3_common))] #[cfg(all(rcc_f3, adc3_common))]
@ -333,6 +294,7 @@ pub(crate) unsafe fn init(config: Config) {
adc34: None, adc34: None,
#[cfg(stm32f334)] #[cfg(stm32f334)]
hrtim: hrtim, hrtim: hrtim,
rtc,
}); });
} }
@ -421,16 +383,16 @@ fn calc_pll(config: &Config, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) {
#[inline] #[inline]
#[allow(unused_variables)] #[allow(unused_variables)]
fn get_usb_pre(config: &Config, sysclk: u32, pclk1: u32, pll_config: &Option<PllConfig>) -> Usbpre { fn get_usb_pre(config: &Config, sysclk: Hertz, pclk1: Hertz, pll_config: &Option<PllConfig>) -> Usbpre {
cfg_if::cfg_if! { cfg_if::cfg_if! {
// Some chips do not have USB // Some chips do not have USB
if #[cfg(any(stm32f301, stm32f318, stm32f334))] { if #[cfg(any(stm32f301, stm32f318, stm32f334))] {
panic!("USB clock not supported by the chip"); panic!("USB clock not supported by the chip");
} else { } else {
let usb_ok = config.hse.is_some() && pll_config.is_some() && (pclk1 >= 10_000_000); let usb_ok = config.hse.is_some() && pll_config.is_some() && (pclk1 >= Hertz(10_000_000));
match (usb_ok, sysclk) { match (usb_ok, sysclk) {
(true, 72_000_000) => Usbpre::DIV1_5, (true, Hertz(72_000_000)) => Usbpre::DIV1_5,
(true, 48_000_000) => Usbpre::DIV1, (true, Hertz(48_000_000)) => Usbpre::DIV1,
_ => panic!( _ => panic!(
"USB clock is only valid if the PLL output frequency is either 48MHz or 72MHz" "USB clock is only valid if the PLL output frequency is either 48MHz or 72MHz"
), ),

View File

@ -1,23 +1,11 @@
use core::marker::PhantomData; use crate::pac::rcc::vals::{Hpre, Pllm, Plln, Pllq, Pllr, Ppre, Sw};
use embassy_hal_internal::into_ref;
use stm32_metapac::rcc::vals::{Mco1, Mco2, Mcopre};
use crate::gpio::sealed::AFType;
use crate::gpio::Speed;
use crate::pac::rcc::vals::{Hpre, Ppre, Sw};
use crate::pac::{FLASH, PWR, RCC}; use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::bd::{BackupDomain, RtcClockSource};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
use crate::{peripherals, Peripheral};
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000); pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
/// Clocks configuration /// Clocks configuration
#[non_exhaustive] #[non_exhaustive]
#[derive(Default)] #[derive(Default)]
@ -36,9 +24,7 @@ pub struct Config {
pub pllsai: Option<Hertz>, pub pllsai: Option<Hertz>,
pub pll48: bool, pub pll48: bool,
pub rtc: Option<RtcClockSource>, pub ls: super::LsConfig,
pub lsi: bool,
pub lse: Option<Hertz>,
} }
#[cfg(stm32f410)] #[cfg(stm32f410)]
@ -52,7 +38,7 @@ fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> {
None None
} }
#[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))] #[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423)))]
fn calculate_sai_i2s_pll_values(vco_in: u32, max_div: u32, target: Option<u32>) -> Option<(u32, u32, u32)> { fn calculate_sai_i2s_pll_values(vco_in: u32, max_div: u32, target: Option<u32>) -> Option<(u32, u32, u32)> {
let min_div = 2; let min_div = 2;
let target = match target { let target = match target {
@ -178,12 +164,12 @@ fn setup_pll(
let real_pll48clk = vco_in * plln / pllq; let real_pll48clk = vco_in * plln / pllq;
RCC.pllcfgr().modify(|w| { RCC.pllcfgr().modify(|w| {
w.set_pllm(pllm as u8); w.set_pllm(Pllm::from_bits(pllm as u8));
w.set_plln(plln as u16); w.set_plln(Plln::from_bits(plln as u16));
w.set_pllp(Pllp::from_bits(pllp as u8)); w.set_pllp(Pllp::from_bits(pllp as u8));
w.set_pllq(pllq as u8); w.set_pllq(Pllq::from_bits(pllq as u8));
w.set_pllsrc(Pllsrc::from_bits(use_hse as u8)); w.set_pllsrc(Pllsrc::from_bits(use_hse as u8));
w.set_pllr(0); w.set_pllr(Pllr::from_bits(0));
}); });
let real_pllsysclk = vco_in * plln / sysclk_div; let real_pllsysclk = vco_in * plln / sysclk_div;
@ -197,164 +183,6 @@ fn setup_pll(
} }
} }
pub enum McoClock {
DIV1,
DIV2,
DIV3,
DIV4,
DIV5,
}
impl McoClock {
fn into_raw(&self) -> Mcopre {
match self {
McoClock::DIV1 => Mcopre::DIV1,
McoClock::DIV2 => Mcopre::DIV2,
McoClock::DIV3 => Mcopre::DIV3,
McoClock::DIV4 => Mcopre::DIV4,
McoClock::DIV5 => Mcopre::DIV5,
}
}
}
#[derive(Copy, Clone)]
pub enum Mco1Source {
Hsi,
Lse,
Hse,
Pll,
}
impl Default for Mco1Source {
fn default() -> Self {
Self::Hsi
}
}
pub trait McoSource {
type Raw;
fn into_raw(&self) -> Self::Raw;
}
impl McoSource for Mco1Source {
type Raw = Mco1;
fn into_raw(&self) -> Self::Raw {
match self {
Mco1Source::Hsi => Mco1::HSI,
Mco1Source::Lse => Mco1::LSE,
Mco1Source::Hse => Mco1::HSE,
Mco1Source::Pll => Mco1::PLL,
}
}
}
#[derive(Copy, Clone)]
pub enum Mco2Source {
SysClk,
Plli2s,
Hse,
Pll,
}
impl Default for Mco2Source {
fn default() -> Self {
Self::SysClk
}
}
impl McoSource for Mco2Source {
type Raw = Mco2;
fn into_raw(&self) -> Self::Raw {
match self {
Mco2Source::SysClk => Mco2::SYSCLK,
Mco2Source::Plli2s => Mco2::PLLI2S,
Mco2Source::Hse => Mco2::HSE,
Mco2Source::Pll => Mco2::PLL,
}
}
}
pub(crate) mod sealed {
use stm32_metapac::rcc::vals::Mcopre;
pub trait McoInstance {
type Source;
unsafe fn apply_clock_settings(source: Self::Source, prescaler: Mcopre);
}
}
pub trait McoInstance: sealed::McoInstance + 'static {}
pin_trait!(McoPin, McoInstance);
impl sealed::McoInstance for peripherals::MCO1 {
type Source = Mco1;
unsafe fn apply_clock_settings(source: Self::Source, prescaler: Mcopre) {
RCC.cfgr().modify(|w| {
w.set_mco1(source);
w.set_mco1pre(prescaler);
});
match source {
Mco1::PLL => {
RCC.cr().modify(|w| w.set_pllon(true));
while !RCC.cr().read().pllrdy() {}
}
Mco1::HSI => {
RCC.cr().modify(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
}
_ => {}
}
}
}
impl McoInstance for peripherals::MCO1 {}
impl sealed::McoInstance for peripherals::MCO2 {
type Source = Mco2;
unsafe fn apply_clock_settings(source: Self::Source, prescaler: Mcopre) {
RCC.cfgr().modify(|w| {
w.set_mco2(source);
w.set_mco2pre(prescaler);
});
match source {
Mco2::PLL => {
RCC.cr().modify(|w| w.set_pllon(true));
while !RCC.cr().read().pllrdy() {}
}
#[cfg(not(stm32f410))]
Mco2::PLLI2S => {
RCC.cr().modify(|w| w.set_plli2son(true));
while !RCC.cr().read().plli2srdy() {}
}
_ => {}
}
}
}
impl McoInstance for peripherals::MCO2 {}
pub struct Mco<'d, T: McoInstance> {
phantom: PhantomData<&'d mut T>,
}
impl<'d, T: McoInstance> Mco<'d, T> {
pub fn new(
_peri: impl Peripheral<P = T> + 'd,
pin: impl Peripheral<P = impl McoPin<T>> + 'd,
source: impl McoSource<Raw = T::Source>,
prescaler: McoClock,
) -> Self {
into_ref!(pin);
critical_section::with(|_| unsafe {
T::apply_clock_settings(source.into_raw(), prescaler.into_raw());
pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
pin.set_speed(Speed::VeryHigh);
});
Self { phantom: PhantomData }
}
}
fn flash_setup(sysclk: u32) { fn flash_setup(sysclk: u32) {
use crate::pac::flash::vals::Latency; use crate::pac::flash::vals::Latency;
@ -508,17 +336,7 @@ pub(crate) unsafe fn init(config: Config) {
}) })
}); });
BackupDomain::configure_ls( let rtc = config.ls.init();
config.rtc.unwrap_or(RtcClockSource::NOCLOCK),
config.lsi,
config.lse.map(|_| Default::default()),
);
let rtc = match config.rtc {
Some(RtcClockSource::LSI) => Some(LSI_FREQ),
Some(RtcClockSource::LSE) => Some(config.lse.unwrap()),
_ => None,
};
set_freqs(Clocks { set_freqs(Clocks {
sys: Hertz(sysclk), sys: Hertz(sysclk),
@ -540,8 +358,7 @@ pub(crate) unsafe fn init(config: Config) {
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
pllsai: plls.pllsaiclk.map(Hertz), pllsai: plls.pllsaiclk.map(Hertz),
rtc: rtc, rtc,
rtc_hse: None,
}); });
} }

View File

@ -1,16 +1,12 @@
use crate::pac::pwr::vals::Vos; use crate::pac::pwr::vals::Vos;
use crate::pac::rcc::vals::{Hpre, Ppre, Sw}; use crate::pac::rcc::vals::{Hpre, Pllm, Plln, Pllp, Pllq, Pllsrc, Ppre, Sw};
use crate::pac::{FLASH, PWR, RCC}; use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::bd::{BackupDomain, RtcClockSource};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000); pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
/// Clocks configuration /// Clocks configuration
#[non_exhaustive] #[non_exhaustive]
#[derive(Default)] #[derive(Default)]
@ -23,14 +19,10 @@ pub struct Config {
pub pclk2: Option<Hertz>, pub pclk2: Option<Hertz>,
pub pll48: bool, pub pll48: bool,
pub rtc: Option<RtcClockSource>, pub ls: super::LsConfig,
pub lsi: bool,
pub lse: Option<Hertz>,
} }
fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults { fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults {
use crate::pac::rcc::vals::{Pllp, Pllsrc};
let sysclk = pllsysclk.unwrap_or(pllsrcclk); let sysclk = pllsysclk.unwrap_or(pllsrcclk);
if pllsysclk.is_none() && !pll48clk { if pllsysclk.is_none() && !pll48clk {
RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc::from_bits(use_hse as u8))); RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc::from_bits(use_hse as u8)));
@ -84,10 +76,10 @@ fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bo
let real_pll48clk = vco_in * plln / pllq; let real_pll48clk = vco_in * plln / pllq;
RCC.pllcfgr().modify(|w| { RCC.pllcfgr().modify(|w| {
w.set_pllm(pllm as u8); w.set_pllm(Pllm::from_bits(pllm as u8));
w.set_plln(plln as u16); w.set_plln(Plln::from_bits(plln as u16));
w.set_pllp(Pllp::from_bits(pllp as u8)); w.set_pllp(Pllp::from_bits(pllp as u8));
w.set_pllq(pllq as u8); w.set_pllq(Pllq::from_bits(pllq as u8));
w.set_pllsrc(Pllsrc::from_bits(use_hse as u8)); w.set_pllsrc(Pllsrc::from_bits(use_hse as u8));
}); });
@ -263,17 +255,7 @@ pub(crate) unsafe fn init(config: Config) {
}) })
}); });
BackupDomain::configure_ls( let rtc = config.ls.init();
config.rtc.unwrap_or(RtcClockSource::NOCLOCK),
config.lsi,
config.lse.map(|_| Default::default()),
);
let rtc = match config.rtc {
Some(RtcClockSource::LSI) => Some(LSI_FREQ),
Some(RtcClockSource::LSE) => Some(config.lse.unwrap()),
_ => None,
};
set_freqs(Clocks { set_freqs(Clocks {
sys: Hertz(sysclk), sys: Hertz(sysclk),

View File

@ -1,6 +1,8 @@
pub use super::bus::{AHBPrescaler, APBPrescaler};
use crate::pac::flash::vals::Latency; use crate::pac::flash::vals::Latency;
use crate::pac::rcc::vals::{self, Hsidiv, Ppre, Sw}; use crate::pac::rcc::vals::{self, Sw};
pub use crate::pac::rcc::vals::{
Hpre as AHBPrescaler, Hsidiv as HSI16Prescaler, Pllm, Plln, Pllp, Pllq, Pllr, Ppre as APBPrescaler,
};
use crate::pac::{FLASH, PWR, RCC}; use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
@ -8,9 +10,6 @@ use crate::time::Hertz;
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000); pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
/// System clock mux source /// System clock mux source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum ClockSrc { pub enum ClockSrc {
@ -20,33 +19,6 @@ pub enum ClockSrc {
LSI, LSI,
} }
#[derive(Clone, Copy)]
pub enum HSI16Prescaler {
NotDivided,
Div2,
Div4,
Div8,
Div16,
Div32,
Div64,
Div128,
}
impl Into<Hsidiv> for HSI16Prescaler {
fn into(self) -> Hsidiv {
match self {
HSI16Prescaler::NotDivided => Hsidiv::DIV1,
HSI16Prescaler::Div2 => Hsidiv::DIV2,
HSI16Prescaler::Div4 => Hsidiv::DIV4,
HSI16Prescaler::Div8 => Hsidiv::DIV8,
HSI16Prescaler::Div16 => Hsidiv::DIV16,
HSI16Prescaler::Div32 => Hsidiv::DIV32,
HSI16Prescaler::Div64 => Hsidiv::DIV64,
HSI16Prescaler::Div128 => Hsidiv::DIV128,
}
}
}
/// The PLL configuration. /// The PLL configuration.
/// ///
/// * `VCOCLK = source / m * n` /// * `VCOCLK = source / m * n`
@ -60,15 +32,15 @@ pub struct PllConfig {
/// The initial divisor of that clock signal /// The initial divisor of that clock signal
pub m: Pllm, pub m: Pllm,
/// The PLL VCO multiplier, which must be in the range `8..=86`. /// The PLL VCO multiplier, which must be in the range `8..=86`.
pub n: u8, pub n: Plln,
/// The final divisor for `PLLRCLK` output which drives the system clock /// The final divisor for `PLLRCLK` output which drives the system clock
pub r: Pllr, pub r: Pllr,
/// The divisor for the `PLLQCLK` output, if desired /// The divisor for the `PLLQCLK` output, if desired
pub q: Option<Pllr>, pub q: Option<Pllq>,
/// The divisor for the `PLLPCLK` output, if desired /// The divisor for the `PLLPCLK` output, if desired
pub p: Option<Pllr>, pub p: Option<Pllp>,
} }
impl Default for PllConfig { impl Default for PllConfig {
@ -77,9 +49,9 @@ impl Default for PllConfig {
// HSI16 / 1 * 8 / 2 = 64 MHz // HSI16 / 1 * 8 / 2 = 64 MHz
PllConfig { PllConfig {
source: PllSrc::HSI16, source: PllSrc::HSI16,
m: Pllm::Div1, m: Pllm::DIV1,
n: 8, n: Plln::MUL8,
r: Pllr::Div2, r: Pllr::DIV2,
q: None, q: None,
p: None, p: None,
} }
@ -92,131 +64,51 @@ pub enum PllSrc {
HSE(Hertz), HSE(Hertz),
} }
#[derive(Clone, Copy)]
pub enum Pllm {
Div1,
Div2,
Div3,
Div4,
Div5,
Div6,
Div7,
Div8,
}
impl From<Pllm> for u8 {
fn from(v: Pllm) -> Self {
match v {
Pllm::Div1 => 0b000,
Pllm::Div2 => 0b001,
Pllm::Div3 => 0b010,
Pllm::Div4 => 0b011,
Pllm::Div5 => 0b100,
Pllm::Div6 => 0b101,
Pllm::Div7 => 0b110,
Pllm::Div8 => 0b111,
}
}
}
impl From<Pllm> for u32 {
fn from(v: Pllm) -> Self {
match v {
Pllm::Div1 => 1,
Pllm::Div2 => 2,
Pllm::Div3 => 3,
Pllm::Div4 => 4,
Pllm::Div5 => 5,
Pllm::Div6 => 6,
Pllm::Div7 => 7,
Pllm::Div8 => 8,
}
}
}
#[derive(Clone, Copy)]
pub enum Pllr {
Div2,
Div3,
Div4,
Div5,
Div6,
Div7,
Div8,
}
impl From<Pllr> for u8 {
fn from(v: Pllr) -> Self {
match v {
Pllr::Div2 => 0b000,
Pllr::Div3 => 0b001,
Pllr::Div4 => 0b010,
Pllr::Div5 => 0b011,
Pllr::Div6 => 0b101,
Pllr::Div7 => 0b110,
Pllr::Div8 => 0b111,
}
}
}
impl From<Pllr> for u32 {
fn from(v: Pllr) -> Self {
match v {
Pllr::Div2 => 2,
Pllr::Div3 => 3,
Pllr::Div4 => 4,
Pllr::Div5 => 5,
Pllr::Div6 => 6,
Pllr::Div7 => 7,
Pllr::Div8 => 8,
}
}
}
/// Clocks configutation /// Clocks configutation
pub struct Config { pub struct Config {
pub mux: ClockSrc, pub mux: ClockSrc,
pub ahb_pre: AHBPrescaler, pub ahb_pre: AHBPrescaler,
pub apb_pre: APBPrescaler, pub apb_pre: APBPrescaler,
pub low_power_run: bool, pub low_power_run: bool,
pub ls: super::LsConfig,
} }
impl Default for Config { impl Default for Config {
#[inline] #[inline]
fn default() -> Config { fn default() -> Config {
Config { Config {
mux: ClockSrc::HSI16(HSI16Prescaler::NotDivided), mux: ClockSrc::HSI16(HSI16Prescaler::DIV1),
ahb_pre: AHBPrescaler::DIV1, ahb_pre: AHBPrescaler::DIV1,
apb_pre: APBPrescaler::DIV1, apb_pre: APBPrescaler::DIV1,
low_power_run: false, low_power_run: false,
ls: Default::default(),
} }
} }
} }
impl PllConfig { impl PllConfig {
pub(crate) fn init(self) -> u32 { pub(crate) fn init(self) -> Hertz {
assert!(self.n >= 8 && self.n <= 86);
let (src, input_freq) = match self.source { let (src, input_freq) = match self.source {
PllSrc::HSI16 => (vals::Pllsrc::HSI16, HSI_FREQ.0), PllSrc::HSI16 => (vals::Pllsrc::HSI16, HSI_FREQ),
PllSrc::HSE(freq) => (vals::Pllsrc::HSE, freq.0), PllSrc::HSE(freq) => (vals::Pllsrc::HSE, freq),
}; };
let m_freq = input_freq / u32::from(self.m); let m_freq = input_freq / self.m;
// RM0454 § 5.4.4: // RM0454 § 5.4.4:
// > Caution: The software must set these bits so that the PLL input frequency after the // > Caution: The software must set these bits so that the PLL input frequency after the
// > /M divider is between 2.66 and 16 MHz. // > /M divider is between 2.66 and 16 MHz.
debug_assert!(m_freq >= 2_660_000 && m_freq <= 16_000_000); debug_assert!(m_freq.0 >= 2_660_000 && m_freq.0 <= 16_000_000);
let n_freq = m_freq * self.n as u32; let n_freq = m_freq * self.n as u32;
// RM0454 § 5.4.4: // RM0454 § 5.4.4:
// > Caution: The software must set these bits so that the VCO output frequency is between // > Caution: The software must set these bits so that the VCO output frequency is between
// > 64 and 344 MHz. // > 64 and 344 MHz.
debug_assert!(n_freq >= 64_000_000 && n_freq <= 344_000_000); debug_assert!(n_freq.0 >= 64_000_000 && n_freq.0 <= 344_000_000);
let r_freq = n_freq / u32::from(self.r); let r_freq = n_freq / self.r;
// RM0454 § 5.4.4: // RM0454 § 5.4.4:
// > Caution: The software must set this bitfield so as not to exceed 64 MHz on this clock. // > Caution: The software must set this bitfield so as not to exceed 64 MHz on this clock.
debug_assert!(r_freq <= 64_000_000); debug_assert!(r_freq.0 <= 64_000_000);
// RM0454 § 5.2.3: // RM0454 § 5.2.3:
// > To modify the PLL configuration, proceed as follows: // > To modify the PLL configuration, proceed as follows:
@ -239,25 +131,16 @@ impl PllConfig {
} }
} }
// Configure PLLSYSCFGR // Configure PLLCFGR
RCC.pllsyscfgr().modify(|w| { RCC.pllcfgr().modify(|w| {
w.set_pllr(u8::from(self.r)); w.set_pllr(self.r);
w.set_pllren(false); w.set_pllren(false);
w.set_pllq(self.q.unwrap_or(Pllq::DIV2));
if let Some(q) = self.q {
w.set_pllq(u8::from(q));
}
w.set_pllqen(false); w.set_pllqen(false);
w.set_pllp(self.p.unwrap_or(Pllp::DIV2));
if let Some(p) = self.p {
w.set_pllp(u8::from(p));
}
w.set_pllpen(false); w.set_pllpen(false);
w.set_plln(self.n); w.set_plln(self.n);
w.set_pllm(self.m);
w.set_pllm(self.m as u8);
w.set_pllsrc(src) w.set_pllsrc(src)
}); });
@ -269,7 +152,7 @@ impl PllConfig {
// > 5. Enable the desired PLL outputs by configuring PLLPEN, PLLQEN, and PLLREN in PLL // > 5. Enable the desired PLL outputs by configuring PLLPEN, PLLQEN, and PLLREN in PLL
// > configuration register (RCC_PLLCFGR). // > configuration register (RCC_PLLCFGR).
RCC.pllsyscfgr().modify(|w| { RCC.pllcfgr().modify(|w| {
// We'll use R for system clock, so enable that unconditionally // We'll use R for system clock, so enable that unconditionally
w.set_pllren(true); w.set_pllren(true);
@ -286,21 +169,20 @@ pub(crate) unsafe fn init(config: Config) {
let (sys_clk, sw) = match config.mux { let (sys_clk, sw) = match config.mux {
ClockSrc::HSI16(div) => { ClockSrc::HSI16(div) => {
// Enable HSI16 // Enable HSI16
let div: Hsidiv = div.into();
RCC.cr().write(|w| { RCC.cr().write(|w| {
w.set_hsidiv(div); w.set_hsidiv(div);
w.set_hsion(true) w.set_hsion(true)
}); });
while !RCC.cr().read().hsirdy() {} while !RCC.cr().read().hsirdy() {}
(HSI_FREQ.0 >> div.to_bits(), Sw::HSI) (HSI_FREQ / div, Sw::HSI)
} }
ClockSrc::HSE(freq) => { ClockSrc::HSE(freq) => {
// Enable HSE // Enable HSE
RCC.cr().write(|w| w.set_hseon(true)); RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {} while !RCC.cr().read().hserdy() {}
(freq.0, Sw::HSE) (freq, Sw::HSE)
} }
ClockSrc::PLL(pll) => { ClockSrc::PLL(pll) => {
let freq = pll.init(); let freq = pll.init();
@ -310,15 +192,15 @@ pub(crate) unsafe fn init(config: Config) {
// Enable LSI // Enable LSI
RCC.csr().write(|w| w.set_lsion(true)); RCC.csr().write(|w| w.set_lsion(true));
while !RCC.csr().read().lsirdy() {} while !RCC.csr().read().lsirdy() {}
(LSI_FREQ.0, Sw::LSI) (super::LSI_FREQ, Sw::LSI)
} }
}; };
// Determine the flash latency implied by the target clock speed // Determine the flash latency implied by the target clock speed
// RM0454 § 3.3.4: // RM0454 § 3.3.4:
let target_flash_latency = if sys_clk <= 24_000_000 { let target_flash_latency = if sys_clk.0 <= 24_000_000 {
Latency::WS0 Latency::WS0
} else if sys_clk <= 48_000_000 { } else if sys_clk.0 <= 48_000_000 {
Latency::WS1 Latency::WS1
} else { } else {
Latency::WS2 Latency::WS2
@ -353,7 +235,7 @@ pub(crate) unsafe fn init(config: Config) {
} }
// Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once
let (sw, hpre, ppre) = (sw.into(), config.ahb_pre.into(), config.apb_pre.into()); let (sw, hpre, ppre) = (sw.into(), config.ahb_pre, config.apb_pre);
RCC.cfgr().modify(|w| { RCC.cfgr().modify(|w| {
w.set_sw(sw); w.set_sw(sw);
w.set_hpre(hpre); w.set_hpre(hpre);
@ -374,27 +256,28 @@ pub(crate) unsafe fn init(config: Config) {
FLASH.acr().modify(|w| w.set_latency(target_flash_latency)); FLASH.acr().modify(|w| w.set_latency(target_flash_latency));
} }
let ahb_freq = Hertz(sys_clk) / config.ahb_pre; let ahb_freq = sys_clk / config.ahb_pre;
let (apb_freq, apb_tim_freq) = match config.apb_pre { let (apb_freq, apb_tim_freq) = match config.apb_pre {
APBPrescaler::DIV1 => (ahb_freq.0, ahb_freq.0), APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => { pre => {
let pre: Ppre = pre.into(); let freq = ahb_freq / pre;
let pre: u8 = 1 << (pre.to_bits() - 3); (freq, freq * 2u32)
let freq = ahb_freq.0 / pre as u32;
(freq, freq * 2)
} }
}; };
if config.low_power_run { if config.low_power_run {
assert!(sys_clk <= 2_000_000); assert!(sys_clk.0 <= 2_000_000);
PWR.cr1().modify(|w| w.set_lpr(true)); PWR.cr1().modify(|w| w.set_lpr(true));
} }
let rtc = config.ls.init();
set_freqs(Clocks { set_freqs(Clocks {
sys: Hertz(sys_clk), sys: sys_clk,
ahb1: ahb_freq, ahb1: ahb_freq,
apb1: Hertz(apb_freq), apb1: apb_freq,
apb1_tim: Hertz(apb_tim_freq), apb1_tim: apb_tim_freq,
rtc,
}); });
} }

View File

@ -2,7 +2,10 @@ use stm32_metapac::flash::vals::Latency;
use stm32_metapac::rcc::vals::{Adcsel, Pllsrc, Sw}; use stm32_metapac::rcc::vals::{Adcsel, Pllsrc, Sw};
use stm32_metapac::FLASH; use stm32_metapac::FLASH;
pub use super::bus::{AHBPrescaler, APBPrescaler}; pub use crate::pac::rcc::vals::{
Adcsel as AdcClockSource, Hpre as AHBPrescaler, Pllm as PllM, Plln as PllN, Pllp as PllP, Pllq as PllQ,
Pllr as PllR, Ppre as APBPrescaler,
};
use crate::pac::{PWR, RCC}; use crate::pac::{PWR, RCC};
use crate::rcc::sealed::RccPeripheral; use crate::rcc::sealed::RccPeripheral;
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
@ -11,32 +14,6 @@ use crate::time::Hertz;
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000); pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
#[derive(Clone, Copy)]
pub enum AdcClockSource {
NoClk,
SysClk,
PllP,
}
impl AdcClockSource {
pub fn adcsel(&self) -> Adcsel {
match self {
AdcClockSource::NoClk => Adcsel::NOCLK,
AdcClockSource::SysClk => Adcsel::SYSCLK,
AdcClockSource::PllP => Adcsel::PLLP,
}
}
}
impl Default for AdcClockSource {
fn default() -> Self {
Self::NoClk
}
}
/// System clock mux source /// System clock mux source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum ClockSrc { pub enum ClockSrc {
@ -61,181 +38,6 @@ impl Into<Pllsrc> for PllSrc {
} }
} }
seq_macro::seq!(P in 2..=31 {
/// Output divider for the PLL P output.
#[derive(Clone, Copy)]
pub enum PllP {
// Note: If PLL P is set to 0 the PLLP bit controls the output division. There does not seem to
// a good reason to do this so the API does not support it.
// Div1 is invalid
#(
Div~P,
)*
}
impl From<PllP> for u8 {
/// Returns the register value for the P output divider.
fn from(val: PllP) -> u8 {
match val {
#(
PllP::Div~P => P,
)*
}
}
}
});
impl PllP {
/// Returns the numeric value of the P output divider.
pub fn to_div(self) -> u32 {
let val: u8 = self.into();
val as u32
}
}
/// Output divider for the PLL Q output.
#[derive(Clone, Copy)]
pub enum PllQ {
Div2,
Div4,
Div6,
Div8,
}
impl PllQ {
/// Returns the numeric value of the Q output divider.
pub fn to_div(self) -> u32 {
let val: u8 = self.into();
(val as u32 + 1) * 2
}
}
impl From<PllQ> for u8 {
/// Returns the register value for the Q output divider.
fn from(val: PllQ) -> u8 {
match val {
PllQ::Div2 => 0b00,
PllQ::Div4 => 0b01,
PllQ::Div6 => 0b10,
PllQ::Div8 => 0b11,
}
}
}
/// Output divider for the PLL R output.
#[derive(Clone, Copy)]
pub enum PllR {
Div2,
Div4,
Div6,
Div8,
}
impl PllR {
/// Returns the numeric value of the R output divider.
pub fn to_div(self) -> u32 {
let val: u8 = self.into();
(val as u32 + 1) * 2
}
}
impl From<PllR> for u8 {
/// Returns the register value for the R output divider.
fn from(val: PllR) -> u8 {
match val {
PllR::Div2 => 0b00,
PllR::Div4 => 0b01,
PllR::Div6 => 0b10,
PllR::Div8 => 0b11,
}
}
}
seq_macro::seq!(N in 8..=127 {
/// Multiplication factor for the PLL VCO input clock.
#[derive(Clone, Copy)]
pub enum PllN {
#(
Mul~N,
)*
}
impl From<PllN> for u8 {
/// Returns the register value for the N multiplication factor.
fn from(val: PllN) -> u8 {
match val {
#(
PllN::Mul~N => N,
)*
}
}
}
impl PllN {
/// Returns the numeric value of the N multiplication factor.
pub fn to_mul(self) -> u32 {
match self {
#(
PllN::Mul~N => N,
)*
}
}
}
});
/// PLL Pre-division. This must be set such that the PLL input is between 2.66 MHz and 16 MHz.
#[derive(Copy, Clone)]
pub enum PllM {
Div1,
Div2,
Div3,
Div4,
Div5,
Div6,
Div7,
Div8,
Div9,
Div10,
Div11,
Div12,
Div13,
Div14,
Div15,
Div16,
}
impl PllM {
/// Returns the numeric value of the M pre-division.
pub fn to_div(self) -> u32 {
let val: u8 = self.into();
val as u32 + 1
}
}
impl From<PllM> for u8 {
/// Returns the register value for the M pre-division.
fn from(val: PllM) -> u8 {
match val {
PllM::Div1 => 0b0000,
PllM::Div2 => 0b0001,
PllM::Div3 => 0b0010,
PllM::Div4 => 0b0011,
PllM::Div5 => 0b0100,
PllM::Div6 => 0b0101,
PllM::Div7 => 0b0110,
PllM::Div8 => 0b0111,
PllM::Div9 => 0b1000,
PllM::Div10 => 0b1001,
PllM::Div11 => 0b1010,
PllM::Div12 => 0b1011,
PllM::Div13 => 0b1100,
PllM::Div14 => 0b1101,
PllM::Div15 => 0b1110,
PllM::Div16 => 0b1111,
}
}
}
/// PLL Configuration /// PLL Configuration
/// ///
/// Use this struct to configure the PLL source, input frequency, multiplication factor, and output /// Use this struct to configure the PLL source, input frequency, multiplication factor, and output
@ -261,32 +63,6 @@ pub struct Pll {
pub div_r: Option<PllR>, pub div_r: Option<PllR>,
} }
fn ahb_div(ahb: AHBPrescaler) -> u32 {
match ahb {
AHBPrescaler::DIV1 => 1,
AHBPrescaler::DIV2 => 2,
AHBPrescaler::DIV4 => 4,
AHBPrescaler::DIV8 => 8,
AHBPrescaler::DIV16 => 16,
AHBPrescaler::DIV64 => 64,
AHBPrescaler::DIV128 => 128,
AHBPrescaler::DIV256 => 256,
AHBPrescaler::DIV512 => 512,
_ => unreachable!(),
}
}
fn apb_div(apb: APBPrescaler) -> u32 {
match apb {
APBPrescaler::DIV1 => 1,
APBPrescaler::DIV2 => 2,
APBPrescaler::DIV4 => 4,
APBPrescaler::DIV8 => 8,
APBPrescaler::DIV16 => 16,
_ => unreachable!(),
}
}
/// Sets the source for the 48MHz clock to the USB and RNG peripherals. /// Sets the source for the 48MHz clock to the USB and RNG peripherals.
pub enum Clock48MhzSrc { pub enum Clock48MhzSrc {
/// Use the High Speed Internal Oscillator. For USB usage, the CRS must be used to calibrate the /// Use the High Speed Internal Oscillator. For USB usage, the CRS must be used to calibrate the
@ -322,6 +98,8 @@ pub struct Config {
pub clock_48mhz_src: Option<Clock48MhzSrc>, pub clock_48mhz_src: Option<Clock48MhzSrc>,
pub adc12_clock_source: AdcClockSource, pub adc12_clock_source: AdcClockSource,
pub adc345_clock_source: AdcClockSource, pub adc345_clock_source: AdcClockSource,
pub ls: super::LsConfig,
} }
/// Configuration for the Clock Recovery System (CRS) used to trim the HSI48 oscillator. /// Configuration for the Clock Recovery System (CRS) used to trim the HSI48 oscillator.
@ -341,8 +119,9 @@ impl Default for Config {
low_power_run: false, low_power_run: false,
pll: None, pll: None,
clock_48mhz_src: None, clock_48mhz_src: None,
adc12_clock_source: Default::default(), adc12_clock_source: Adcsel::NOCLK,
adc345_clock_source: Default::default(), adc345_clock_source: Adcsel::NOCLK,
ls: Default::default(),
} }
} }
} }
@ -360,12 +139,12 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cr().write(|w| w.set_hsion(true)); RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {} while !RCC.cr().read().hsirdy() {}
HSI_FREQ.0 HSI_FREQ
} }
PllSrc::HSE(freq) => { PllSrc::HSE(freq) => {
RCC.cr().write(|w| w.set_hseon(true)); RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {} while !RCC.cr().read().hserdy() {}
freq.0 freq
} }
}; };
@ -373,36 +152,36 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cr().modify(|w| w.set_pllon(false)); RCC.cr().modify(|w| w.set_pllon(false));
while RCC.cr().read().pllrdy() {} while RCC.cr().read().pllrdy() {}
let internal_freq = src_freq / pll_config.prediv_m.to_div() * pll_config.mul_n.to_mul(); let internal_freq = src_freq / pll_config.prediv_m * pll_config.mul_n;
RCC.pllcfgr().write(|w| { RCC.pllcfgr().write(|w| {
w.set_plln(pll_config.mul_n.into()); w.set_plln(pll_config.mul_n);
w.set_pllm(pll_config.prediv_m.into()); w.set_pllm(pll_config.prediv_m);
w.set_pllsrc(pll_config.source.into()); w.set_pllsrc(pll_config.source.into());
}); });
let pll_p_freq = pll_config.div_p.map(|div_p| { let pll_p_freq = pll_config.div_p.map(|div_p| {
RCC.pllcfgr().modify(|w| { RCC.pllcfgr().modify(|w| {
w.set_pllpdiv(div_p.into()); w.set_pllp(div_p);
w.set_pllpen(true); w.set_pllpen(true);
}); });
Hertz(internal_freq / div_p.to_div()) internal_freq / div_p
}); });
let pll_q_freq = pll_config.div_q.map(|div_q| { let pll_q_freq = pll_config.div_q.map(|div_q| {
RCC.pllcfgr().modify(|w| { RCC.pllcfgr().modify(|w| {
w.set_pllq(div_q.into()); w.set_pllq(div_q);
w.set_pllqen(true); w.set_pllqen(true);
}); });
Hertz(internal_freq / div_q.to_div()) internal_freq / div_q
}); });
let pll_r_freq = pll_config.div_r.map(|div_r| { let pll_r_freq = pll_config.div_r.map(|div_r| {
RCC.pllcfgr().modify(|w| { RCC.pllcfgr().modify(|w| {
w.set_pllr(div_r.into()); w.set_pllr(div_r);
w.set_pllren(true); w.set_pllren(true);
}); });
Hertz(internal_freq / div_r.to_div()) internal_freq / div_r
}); });
// Enable the PLL // Enable the PLL
@ -422,14 +201,14 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cr().write(|w| w.set_hsion(true)); RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {} while !RCC.cr().read().hsirdy() {}
(HSI_FREQ.0, Sw::HSI16) (HSI_FREQ, Sw::HSI16)
} }
ClockSrc::HSE(freq) => { ClockSrc::HSE(freq) => {
// Enable HSE // Enable HSE
RCC.cr().write(|w| w.set_hseon(true)); RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {} while !RCC.cr().read().hserdy() {}
(freq.0, Sw::HSE) (freq, Sw::HSE)
} }
ClockSrc::PLL => { ClockSrc::PLL => {
assert!(pll_freq.is_some()); assert!(pll_freq.is_some());
@ -470,35 +249,32 @@ pub(crate) unsafe fn init(config: Config) {
} }
} }
(freq, Sw::PLLRCLK) (Hertz(freq), Sw::PLLRCLK)
} }
}; };
RCC.cfgr().modify(|w| { RCC.cfgr().modify(|w| {
w.set_sw(sw); w.set_sw(sw);
w.set_hpre(config.ahb_pre.into()); w.set_hpre(config.ahb_pre);
w.set_ppre1(config.apb1_pre.into()); w.set_ppre1(config.apb1_pre);
w.set_ppre2(config.apb2_pre.into()); w.set_ppre2(config.apb2_pre);
}); });
let ahb_freq: u32 = match config.ahb_pre { let ahb_freq = sys_clk / config.ahb_pre;
AHBPrescaler::DIV1 => sys_clk,
pre => sys_clk / ahb_div(pre),
};
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq), APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => { pre => {
let freq = ahb_freq / apb_div(pre); let freq = ahb_freq / pre;
(freq, freq * 2) (freq, freq * 2u32)
} }
}; };
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre { let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq), APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => { pre => {
let freq = ahb_freq / apb_div(pre); let freq = ahb_freq / pre;
(freq, freq * 2) (freq, freq * 2u32)
} }
}; };
@ -520,7 +296,7 @@ pub(crate) unsafe fn init(config: Config) {
// Enable and setup CRS if needed // Enable and setup CRS if needed
if let Some(crs_config) = crs_config { if let Some(crs_config) = crs_config {
crate::peripherals::CRS::enable(); crate::peripherals::CRS::enable_and_reset();
let sync_src = match crs_config.sync_src { let sync_src = match crs_config.sync_src {
CrsSyncSource::Gpio => crate::pac::crs::vals::Syncsrc::GPIO, CrsSyncSource::Gpio => crate::pac::crs::vals::Syncsrc::GPIO,
@ -546,43 +322,40 @@ pub(crate) unsafe fn init(config: Config) {
RCC.ccipr().modify(|w| w.set_clk48sel(source)); RCC.ccipr().modify(|w| w.set_clk48sel(source));
} }
RCC.ccipr() RCC.ccipr().modify(|w| w.set_adc12sel(config.adc12_clock_source));
.modify(|w| w.set_adc12sel(config.adc12_clock_source.adcsel())); RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source));
RCC.ccipr()
.modify(|w| w.set_adc345sel(config.adc345_clock_source.adcsel()));
let adc12_ck = match config.adc12_clock_source { let adc12_ck = match config.adc12_clock_source {
AdcClockSource::NoClk => None, AdcClockSource::NOCLK => None,
AdcClockSource::PllP => match &pll_freq { AdcClockSource::PLLP => pll_freq.as_ref().unwrap().pll_p,
Some(pll) => pll.pll_p, AdcClockSource::SYSCLK => Some(sys_clk),
None => None, _ => unreachable!(),
},
AdcClockSource::SysClk => Some(Hertz(sys_clk)),
}; };
let adc345_ck = match config.adc345_clock_source { let adc345_ck = match config.adc345_clock_source {
AdcClockSource::NoClk => None, AdcClockSource::NOCLK => None,
AdcClockSource::PllP => match &pll_freq { AdcClockSource::PLLP => pll_freq.as_ref().unwrap().pll_p,
Some(pll) => pll.pll_p, AdcClockSource::SYSCLK => Some(sys_clk),
None => None, _ => unreachable!(),
},
AdcClockSource::SysClk => Some(Hertz(sys_clk)),
}; };
if config.low_power_run { if config.low_power_run {
assert!(sys_clk <= 2_000_000); assert!(sys_clk <= Hertz(2_000_000));
PWR.cr1().modify(|w| w.set_lpr(true)); PWR.cr1().modify(|w| w.set_lpr(true));
} }
let rtc = config.ls.init();
set_freqs(Clocks { set_freqs(Clocks {
sys: Hertz(sys_clk), sys: sys_clk,
ahb1: Hertz(ahb_freq), ahb1: ahb_freq,
ahb2: Hertz(ahb_freq), ahb2: ahb_freq,
apb1: Hertz(apb1_freq), apb1: apb1_freq,
apb1_tim: Hertz(apb1_tim_freq), apb1_tim: apb1_tim_freq,
apb2: Hertz(apb2_freq), apb2: apb2_freq,
apb2_tim: Hertz(apb2_tim_freq), apb2_tim: apb2_tim_freq,
adc: adc12_ck, adc: adc12_ck,
adc34: adc345_ck, adc34: adc345_ck,
rtc,
}); });
} }

View File

@ -6,8 +6,8 @@ use crate::pac::pwr::vals::Vos;
pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource; pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource;
#[cfg(stm32h7)] #[cfg(stm32h7)]
pub use crate::pac::rcc::vals::Adcsel as AdcClockSource; pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
pub use crate::pac::rcc::vals::Ckpersel as PerClockSource;
use crate::pac::rcc::vals::{Ckpersel, Hsidiv, Pllrge, Pllsrc, Pllvcosel, Sw, Timpre}; use crate::pac::rcc::vals::{Ckpersel, Hsidiv, Pllrge, Pllsrc, Pllvcosel, Sw, Timpre};
pub use crate::pac::rcc::vals::{Ckpersel as PerClockSource, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul};
use crate::pac::{FLASH, PWR, RCC}; use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
@ -21,18 +21,15 @@ pub const CSI_FREQ: Hertz = Hertz(4_000_000);
/// HSI48 speed /// HSI48 speed
pub const HSI48_FREQ: Hertz = Hertz(48_000_000); pub const HSI48_FREQ: Hertz = Hertz(48_000_000);
/// LSI speed const VCO_RANGE: RangeInclusive<Hertz> = Hertz(150_000_000)..=Hertz(420_000_000);
pub const LSI_FREQ: Hertz = Hertz(32_000);
const VCO_RANGE: RangeInclusive<u32> = 150_000_000..=420_000_000;
#[cfg(any(stm32h5, pwr_h7rm0455))] #[cfg(any(stm32h5, pwr_h7rm0455))]
const VCO_WIDE_RANGE: RangeInclusive<u32> = 128_000_000..=560_000_000; const VCO_WIDE_RANGE: RangeInclusive<Hertz> = Hertz(128_000_000)..=Hertz(560_000_000);
#[cfg(pwr_h7rm0468)] #[cfg(pwr_h7rm0468)]
const VCO_WIDE_RANGE: RangeInclusive<u32> = 192_000_000..=836_000_000; const VCO_WIDE_RANGE: RangeInclusive<Hertz> = Hertz(192_000_000)..=Hertz(836_000_000);
#[cfg(any(pwr_h7rm0399, pwr_h7rm0433))] #[cfg(any(pwr_h7rm0399, pwr_h7rm0433))]
const VCO_WIDE_RANGE: RangeInclusive<u32> = 192_000_000..=960_000_000; const VCO_WIDE_RANGE: RangeInclusive<Hertz> = Hertz(192_000_000)..=Hertz(960_000_000);
pub use super::bus::{AHBPrescaler, APBPrescaler}; pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler};
#[derive(Clone, Copy, Eq, PartialEq)] #[derive(Clone, Copy, Eq, PartialEq)]
pub enum VoltageScale { pub enum VoltageScale {
@ -46,9 +43,9 @@ pub enum VoltageScale {
pub enum HseMode { pub enum HseMode {
/// crystal/ceramic oscillator (HSEBYP=0) /// crystal/ceramic oscillator (HSEBYP=0)
Oscillator, Oscillator,
/// external analog clock (low swing) (HSEBYP=1, HSEEXT=0) /// external analog clock (low swing) (HSEBYP=1, HSEEXT=0)
Bypass, Bypass,
/// external digital clock (full swing) (HSEBYP=1, HSEEXT=1) /// external digital clock (full swing) (HSEBYP=1, HSEEXT=1)
#[cfg(any(rcc_h5, rcc_h50))] #[cfg(any(rcc_h5, rcc_h50))]
BypassDigital, BypassDigital,
} }
@ -61,6 +58,15 @@ pub struct Hse {
pub mode: HseMode, pub mode: HseMode,
} }
#[cfg(stm32h7)]
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum Lse {
/// 32.768 kHz crystal/ceramic oscillator (LSEBYP=0)
Oscillator,
/// external clock input up to 1MHz (LSEBYP=1)
Bypass(Hertz),
}
#[derive(Clone, Copy, Eq, PartialEq)] #[derive(Clone, Copy, Eq, PartialEq)]
pub enum Hsi { pub enum Hsi {
/// 64Mhz /// 64Mhz
@ -98,19 +104,19 @@ pub struct Pll {
#[cfg(stm32h5)] #[cfg(stm32h5)]
pub source: PllSource, pub source: PllSource,
/// PLL pre-divider (DIVM). Must be between 1 and 63. /// PLL pre-divider (DIVM).
pub prediv: u8, pub prediv: PllPreDiv,
/// PLL multiplication factor. Must be between 4 and 512. /// PLL multiplication factor.
pub mul: u16, pub mul: PllMul,
/// PLL P division factor. If None, PLL P output is disabled. Must be between 1 and 128. /// PLL P division factor. If None, PLL P output is disabled.
/// On PLL1, it must be even (in particular, it cannot be 1.) /// On PLL1, it must be even (in particular, it cannot be 1.)
pub divp: Option<u16>, pub divp: Option<PllDiv>,
/// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128. /// PLL Q division factor. If None, PLL Q output is disabled.
pub divq: Option<u16>, pub divq: Option<PllDiv>,
/// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128. /// PLL R division factor. If None, PLL R output is disabled.
pub divr: Option<u16>, pub divr: Option<PllDiv>,
} }
fn apb_div_tim(apb: &APBPrescaler, clk: Hertz, tim: TimerPrescaler) -> Hertz { fn apb_div_tim(apb: &APBPrescaler, clk: Hertz, tim: TimerPrescaler) -> Hertz {
@ -157,6 +163,10 @@ impl From<TimerPrescaler> for Timpre {
pub struct Config { pub struct Config {
pub hsi: Option<Hsi>, pub hsi: Option<Hsi>,
pub hse: Option<Hse>, pub hse: Option<Hse>,
#[cfg(stm32h7)]
pub lse: Option<Lse>,
#[cfg(stm32h7)]
pub lsi: bool,
pub csi: bool, pub csi: bool,
pub hsi48: bool, pub hsi48: bool,
pub sys: Sysclk, pub sys: Sysclk,
@ -181,6 +191,7 @@ pub struct Config {
pub adc_clock_source: AdcClockSource, pub adc_clock_source: AdcClockSource,
pub timer_prescaler: TimerPrescaler, pub timer_prescaler: TimerPrescaler,
pub voltage_scale: VoltageScale, pub voltage_scale: VoltageScale,
pub ls: super::LsConfig,
} }
impl Default for Config { impl Default for Config {
@ -188,6 +199,10 @@ impl Default for Config {
Self { Self {
hsi: Some(Hsi::Mhz64), hsi: Some(Hsi::Mhz64),
hse: None, hse: None,
#[cfg(stm32h7)]
lse: None,
#[cfg(stm32h7)]
lsi: false,
csi: false, csi: false,
hsi48: false, hsi48: false,
sys: Sysclk::HSI, sys: Sysclk::HSI,
@ -210,6 +225,7 @@ impl Default for Config {
adc_clock_source: AdcClockSource::from_bits(0), // PLL2_P on H7, HCLK on H5 adc_clock_source: AdcClockSource::from_bits(0), // PLL2_P on H7, HCLK on H5
timer_prescaler: TimerPrescaler::DefaultX2, timer_prescaler: TimerPrescaler::DefaultX2,
voltage_scale: VoltageScale::Scale0, voltage_scale: VoltageScale::Scale0,
ls: Default::default(),
} }
} }
} }
@ -372,7 +388,7 @@ pub(crate) unsafe fn init(config: Config) {
let pll1 = init_pll(0, config.pll1, &pll_input); let pll1 = init_pll(0, config.pll1, &pll_input);
let pll2 = init_pll(1, config.pll2, &pll_input); let pll2 = init_pll(1, config.pll2, &pll_input);
#[cfg(any(rcc_h5, stm32h7))] #[cfg(any(rcc_h5, stm32h7))]
let _pll3 = init_pll(2, config.pll3, &pll_input); let pll3 = init_pll(2, config.pll3, &pll_input);
// Configure sysclk // Configure sysclk
let (sys, sw) = match config.sys { let (sys, sw) = match config.sys {
@ -431,7 +447,7 @@ pub(crate) unsafe fn init(config: Config) {
#[cfg(stm32h7)] #[cfg(stm32h7)]
let adc = match config.adc_clock_source { let adc = match config.adc_clock_source {
AdcClockSource::PLL2_P => pll2.p, AdcClockSource::PLL2_P => pll2.p,
AdcClockSource::PLL3_R => _pll3.r, AdcClockSource::PLL3_R => pll3.r,
AdcClockSource::PER => _per_ck, AdcClockSource::PER => _per_ck,
_ => unreachable!(), _ => unreachable!(),
}; };
@ -441,13 +457,15 @@ pub(crate) unsafe fn init(config: Config) {
AdcClockSource::SYSCLK => Some(sys), AdcClockSource::SYSCLK => Some(sys),
AdcClockSource::PLL2_R => pll2.r, AdcClockSource::PLL2_R => pll2.r,
AdcClockSource::HSE => hse, AdcClockSource::HSE => hse,
AdcClockSource::HSI_KER => hsi, AdcClockSource::HSI => hsi,
AdcClockSource::CSI_KER => csi, AdcClockSource::CSI => csi,
_ => unreachable!(), _ => unreachable!(),
}; };
flash_setup(hclk, config.voltage_scale); flash_setup(hclk, config.voltage_scale);
let rtc = config.ls.init();
#[cfg(stm32h7)] #[cfg(stm32h7)]
{ {
RCC.d1cfgr().modify(|w| { RCC.d1cfgr().modify(|w| {
@ -523,9 +541,55 @@ pub(crate) unsafe fn init(config: Config) {
apb3, apb3,
#[cfg(stm32h7)] #[cfg(stm32h7)]
apb4, apb4,
#[cfg(stm32h5)]
apb4: Hertz(1),
apb1_tim, apb1_tim,
apb2_tim, apb2_tim,
adc: adc, adc,
rtc,
#[cfg(stm32h5)]
hsi: None,
#[cfg(stm32h5)]
hsi48: None,
#[cfg(stm32h5)]
lsi: None,
#[cfg(stm32h5)]
csi: None,
#[cfg(stm32h5)]
lse: None,
#[cfg(stm32h5)]
hse: None,
#[cfg(stm32h5)]
pll1_q: pll1.q,
#[cfg(stm32h5)]
pll2_q: pll2.q,
#[cfg(stm32h5)]
pll2_p: pll2.p,
#[cfg(stm32h5)]
pll2_r: pll2.r,
#[cfg(rcc_h5)]
pll3_p: pll3.p,
#[cfg(rcc_h5)]
pll3_q: pll3.q,
#[cfg(rcc_h5)]
pll3_r: pll3.r,
#[cfg(stm32h5)]
pll3_1: None,
#[cfg(rcc_h50)]
pll3_p: None,
#[cfg(rcc_h50)]
pll3_q: None,
#[cfg(rcc_h50)]
pll3_r: None,
#[cfg(stm32h5)]
audioclk: None,
#[cfg(stm32h5)]
per: None,
}); });
} }
@ -553,9 +617,9 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
// "To save power when PLL1 is not used, the value of PLL1M must be set to 0."" // "To save power when PLL1 is not used, the value of PLL1M must be set to 0.""
#[cfg(stm32h7)] #[cfg(stm32h7)]
RCC.pllckselr().write(|w| w.set_divm(num, 0)); RCC.pllckselr().write(|w| w.set_divm(num, PllPreDiv::from_bits(0)));
#[cfg(stm32h5)] #[cfg(stm32h5)]
RCC.pllcfgr(num).write(|w| w.set_divm(0)); RCC.pllcfgr(num).write(|w| w.set_divm(PllPreDiv::from_bits(0)));
return PllOutput { return PllOutput {
p: None, p: None,
@ -564,9 +628,6 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
}; };
}; };
assert!(1 <= config.prediv && config.prediv <= 63);
assert!(4 <= config.mul && config.mul <= 512);
#[cfg(stm32h5)] #[cfg(stm32h5)]
let source = config.source; let source = config.source;
#[cfg(stm32h7)] #[cfg(stm32h7)]
@ -593,31 +654,25 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
let wide_allowed = ref_range != Pllrge::RANGE1; let wide_allowed = ref_range != Pllrge::RANGE1;
let vco_clk = ref_clk * config.mul; let vco_clk = ref_clk * config.mul;
let vco_range = if VCO_RANGE.contains(&vco_clk.0) { let vco_range = if VCO_RANGE.contains(&vco_clk) {
Pllvcosel::MEDIUMVCO Pllvcosel::MEDIUMVCO
} else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk.0) { } else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk) {
Pllvcosel::WIDEVCO Pllvcosel::WIDEVCO
} else { } else {
panic!("pll vco_clk out of range: {} mhz", vco_clk.0) panic!("pll vco_clk out of range: {} mhz", vco_clk.0)
}; };
let p = config.divp.map(|div| { let p = config.divp.map(|div| {
assert!(1 <= div && div <= 128);
if num == 0 { if num == 0 {
// on PLL1, DIVP must be even. // on PLL1, DIVP must be even.
assert!(div % 2 == 0); // The enum value is 1 less than the divider, so check it's odd.
assert!(div.to_bits() % 2 == 1);
} }
vco_clk / div vco_clk / div
}); });
let q = config.divq.map(|div| { let q = config.divq.map(|div| vco_clk / div);
assert!(1 <= div && div <= 128); let r = config.divr.map(|div| vco_clk / div);
vco_clk / div
});
let r = config.divr.map(|div| {
assert!(1 <= div && div <= 128);
vco_clk / div
});
#[cfg(stm32h5)] #[cfg(stm32h5)]
RCC.pllcfgr(num).write(|w| { RCC.pllcfgr(num).write(|w| {
@ -648,10 +703,10 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
} }
RCC.plldivr(num).write(|w| { RCC.plldivr(num).write(|w| {
w.set_plln(config.mul - 1); w.set_plln(config.mul);
w.set_pllp((config.divp.unwrap_or(1) - 1) as u8); w.set_pllp(config.divp.unwrap_or(PllDiv::DIV2));
w.set_pllq((config.divq.unwrap_or(1) - 1) as u8); w.set_pllq(config.divq.unwrap_or(PllDiv::DIV2));
w.set_pllr((config.divr.unwrap_or(1) - 1) as u8); w.set_pllr(config.divr.unwrap_or(PllDiv::DIV2));
}); });
RCC.cr().modify(|w| w.set_pllon(num, true)); RCC.cr().modify(|w| w.set_pllon(num, true));

View File

@ -1,349 +0,0 @@
use super::bd::BackupDomain;
pub use super::bus::{AHBPrescaler, APBPrescaler};
use super::RtcClockSource;
pub use crate::pac::pwr::vals::Vos as VoltageScale;
use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
#[cfg(crs)]
use crate::pac::{crs, CRS, SYSCFG};
use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz;
/// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
/// System clock mux source
#[derive(Clone, Copy)]
pub enum ClockSrc {
MSI(MSIRange),
PLL(PLLSource, PLLMul, PLLDiv),
HSE(Hertz),
HSI16,
}
/// MSI Clock Range
///
/// These ranges control the frequency of the MSI. Internally, these ranges map
/// to the `MSIRANGE` bits in the `RCC_ICSCR` register.
#[derive(Clone, Copy)]
pub enum MSIRange {
/// Around 65.536 kHz
Range0,
/// Around 131.072 kHz
Range1,
/// Around 262.144 kHz
Range2,
/// Around 524.288 kHz
Range3,
/// Around 1.048 MHz
Range4,
/// Around 2.097 MHz (reset value)
Range5,
/// Around 4.194 MHz
Range6,
}
impl Default for MSIRange {
fn default() -> MSIRange {
MSIRange::Range5
}
}
/// PLL divider
#[derive(Clone, Copy)]
pub enum PLLDiv {
Div2,
Div3,
Div4,
}
/// PLL multiplier
#[derive(Clone, Copy)]
pub enum PLLMul {
Mul3,
Mul4,
Mul6,
Mul8,
Mul12,
Mul16,
Mul24,
Mul32,
Mul48,
}
/// PLL clock input source
#[derive(Clone, Copy)]
pub enum PLLSource {
HSI16,
HSE(Hertz),
}
impl From<PLLMul> for Pllmul {
fn from(val: PLLMul) -> Pllmul {
match val {
PLLMul::Mul3 => Pllmul::MUL3,
PLLMul::Mul4 => Pllmul::MUL4,
PLLMul::Mul6 => Pllmul::MUL6,
PLLMul::Mul8 => Pllmul::MUL8,
PLLMul::Mul12 => Pllmul::MUL12,
PLLMul::Mul16 => Pllmul::MUL16,
PLLMul::Mul24 => Pllmul::MUL24,
PLLMul::Mul32 => Pllmul::MUL32,
PLLMul::Mul48 => Pllmul::MUL48,
}
}
}
impl From<PLLDiv> for Plldiv {
fn from(val: PLLDiv) -> Plldiv {
match val {
PLLDiv::Div2 => Plldiv::DIV2,
PLLDiv::Div3 => Plldiv::DIV3,
PLLDiv::Div4 => Plldiv::DIV4,
}
}
}
impl From<PLLSource> for Pllsrc {
fn from(val: PLLSource) -> Pllsrc {
match val {
PLLSource::HSI16 => Pllsrc::HSI16,
PLLSource::HSE(_) => Pllsrc::HSE,
}
}
}
impl From<MSIRange> for Msirange {
fn from(val: MSIRange) -> Msirange {
match val {
MSIRange::Range0 => Msirange::RANGE0,
MSIRange::Range1 => Msirange::RANGE1,
MSIRange::Range2 => Msirange::RANGE2,
MSIRange::Range3 => Msirange::RANGE3,
MSIRange::Range4 => Msirange::RANGE4,
MSIRange::Range5 => Msirange::RANGE5,
MSIRange::Range6 => Msirange::RANGE6,
}
}
}
/// Clocks configutation
pub struct Config {
pub mux: ClockSrc,
pub ahb_pre: AHBPrescaler,
pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler,
#[cfg(crs)]
pub enable_hsi48: bool,
pub rtc: Option<RtcClockSource>,
pub lse: Option<Hertz>,
pub lsi: bool,
pub voltage_scale: VoltageScale,
}
impl Default for Config {
#[inline]
fn default() -> Config {
Config {
mux: ClockSrc::MSI(MSIRange::default()),
ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1,
#[cfg(crs)]
enable_hsi48: false,
rtc: None,
lse: None,
lsi: false,
voltage_scale: VoltageScale::RANGE1,
}
}
}
pub(crate) unsafe fn init(config: Config) {
// Set voltage scale
while PWR.csr().read().vosf() {}
PWR.cr().write(|w| w.set_vos(config.voltage_scale));
while PWR.csr().read().vosf() {}
let (sys_clk, sw) = match config.mux {
ClockSrc::MSI(range) => {
// Set MSI range
RCC.icscr().write(|w| w.set_msirange(range.into()));
// Enable MSI
RCC.cr().write(|w| w.set_msion(true));
while !RCC.cr().read().msirdy() {}
let freq = 32_768 * (1 << (range as u8 + 1));
(freq, Sw::MSI)
}
ClockSrc::HSI16 => {
// Enable HSI16
RCC.cr().write(|w| w.set_hsi16on(true));
while !RCC.cr().read().hsi16rdyf() {}
(HSI_FREQ.0, Sw::HSI16)
}
ClockSrc::HSE(freq) => {
// Enable HSE
RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {}
(freq.0, Sw::HSE)
}
ClockSrc::PLL(src, mul, div) => {
let freq = match src {
PLLSource::HSE(freq) => {
// Enable HSE
RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {}
freq.0
}
PLLSource::HSI16 => {
// Enable HSI
RCC.cr().write(|w| w.set_hsi16on(true));
while !RCC.cr().read().hsi16rdyf() {}
HSI_FREQ.0
}
};
// Disable PLL
RCC.cr().modify(|w| w.set_pllon(false));
while RCC.cr().read().pllrdy() {}
let freq = match mul {
PLLMul::Mul3 => freq * 3,
PLLMul::Mul4 => freq * 4,
PLLMul::Mul6 => freq * 6,
PLLMul::Mul8 => freq * 8,
PLLMul::Mul12 => freq * 12,
PLLMul::Mul16 => freq * 16,
PLLMul::Mul24 => freq * 24,
PLLMul::Mul32 => freq * 32,
PLLMul::Mul48 => freq * 48,
};
let freq = match div {
PLLDiv::Div2 => freq / 2,
PLLDiv::Div3 => freq / 3,
PLLDiv::Div4 => freq / 4,
};
assert!(freq <= 32_000_000);
RCC.cfgr().write(move |w| {
w.set_pllmul(mul.into());
w.set_plldiv(div.into());
w.set_pllsrc(src.into());
});
// Enable PLL
RCC.cr().modify(|w| w.set_pllon(true));
while !RCC.cr().read().pllrdy() {}
(freq, Sw::PLL)
}
};
BackupDomain::configure_ls(
config.rtc.unwrap_or(RtcClockSource::NOCLOCK),
config.lsi,
config.lse.map(|_| Default::default()),
);
let wait_states = match config.voltage_scale {
VoltageScale::RANGE1 => match sys_clk {
..=16_000_000 => 0,
_ => 1,
},
VoltageScale::RANGE2 => match sys_clk {
..=8_000_000 => 0,
_ => 1,
},
VoltageScale::RANGE3 => 0,
_ => unreachable!(),
};
FLASH.acr().modify(|w| {
w.set_latency(wait_states != 0);
});
RCC.cfgr().modify(|w| {
w.set_sw(sw);
w.set_hpre(config.ahb_pre.into());
w.set_ppre1(config.apb1_pre.into());
w.set_ppre2(config.apb2_pre.into());
});
let ahb_freq: u32 = match config.ahb_pre {
AHBPrescaler::DIV1 => sys_clk,
pre => {
let pre: Hpre = pre.into();
let pre = 1 << (pre.to_bits() as u32 - 7);
sys_clk / pre
}
};
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
};
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
};
#[cfg(crs)]
if config.enable_hsi48 {
// Reset CRS peripheral
RCC.apb1rstr().modify(|w| w.set_crsrst(true));
RCC.apb1rstr().modify(|w| w.set_crsrst(false));
// Enable CRS peripheral
RCC.apb1enr().modify(|w| w.set_crsen(true));
// Initialize CRS
CRS.cfgr().write(|w|
// Select LSE as synchronization source
w.set_syncsrc(crs::vals::Syncsrc::LSE));
CRS.cr().modify(|w| {
w.set_autotrimen(true);
w.set_cen(true);
});
// Enable VREFINT reference for HSI48 oscillator
SYSCFG.cfgr3().modify(|w| {
w.set_enref_hsi48(true);
w.set_en_vrefint(true);
});
// Select HSI48 as USB clock
RCC.ccipr().modify(|w| w.set_hsi48msel(true));
// Enable dedicated USB clock
RCC.crrcr().modify(|w| w.set_hsi48on(true));
while !RCC.crrcr().read().hsi48rdy() {}
}
set_freqs(Clocks {
sys: Hertz(sys_clk),
ahb1: Hertz(ahb_freq),
apb1: Hertz(apb1_freq),
apb2: Hertz(apb2_freq),
apb1_tim: Hertz(apb1_tim_freq),
apb2_tim: Hertz(apb2_tim_freq),
});
}

View File

@ -0,0 +1,219 @@
pub use crate::pac::pwr::vals::Vos as VoltageScale;
pub use crate::pac::rcc::vals::{
Hpre as AHBPrescaler, Msirange as MSIRange, Plldiv as PLLDiv, Pllmul as PLLMul, Ppre as APBPrescaler,
};
use crate::pac::rcc::vals::{Pllsrc, Sw};
#[cfg(crs)]
use crate::pac::{crs, CRS, SYSCFG};
use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz;
/// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// System clock mux source
#[derive(Clone, Copy)]
pub enum ClockSrc {
MSI(MSIRange),
PLL(PLLSource, PLLMul, PLLDiv),
HSE(Hertz),
HSI16,
}
/// PLL clock input source
#[derive(Clone, Copy)]
pub enum PLLSource {
HSI16,
HSE(Hertz),
}
impl From<PLLSource> for Pllsrc {
fn from(val: PLLSource) -> Pllsrc {
match val {
PLLSource::HSI16 => Pllsrc::HSI16,
PLLSource::HSE(_) => Pllsrc::HSE,
}
}
}
/// Clocks configutation
pub struct Config {
pub mux: ClockSrc,
pub ahb_pre: AHBPrescaler,
pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler,
#[cfg(crs)]
pub enable_hsi48: bool,
pub ls: super::LsConfig,
pub voltage_scale: VoltageScale,
}
impl Default for Config {
#[inline]
fn default() -> Config {
Config {
mux: ClockSrc::MSI(MSIRange::RANGE5),
ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1,
#[cfg(crs)]
enable_hsi48: false,
voltage_scale: VoltageScale::RANGE1,
ls: Default::default(),
}
}
}
pub(crate) unsafe fn init(config: Config) {
// Set voltage scale
while PWR.csr().read().vosf() {}
PWR.cr().write(|w| w.set_vos(config.voltage_scale));
while PWR.csr().read().vosf() {}
let (sys_clk, sw) = match config.mux {
ClockSrc::MSI(range) => {
// Set MSI range
RCC.icscr().write(|w| w.set_msirange(range));
// Enable MSI
RCC.cr().write(|w| w.set_msion(true));
while !RCC.cr().read().msirdy() {}
let freq = 32_768 * (1 << (range as u8 + 1));
(Hertz(freq), Sw::MSI)
}
ClockSrc::HSI16 => {
// Enable HSI16
RCC.cr().write(|w| w.set_hsi16on(true));
while !RCC.cr().read().hsi16rdy() {}
(HSI_FREQ, Sw::HSI16)
}
ClockSrc::HSE(freq) => {
// Enable HSE
RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {}
(freq, Sw::HSE)
}
ClockSrc::PLL(src, mul, div) => {
let freq = match src {
PLLSource::HSE(freq) => {
// Enable HSE
RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {}
freq
}
PLLSource::HSI16 => {
// Enable HSI
RCC.cr().write(|w| w.set_hsi16on(true));
while !RCC.cr().read().hsi16rdy() {}
HSI_FREQ
}
};
// Disable PLL
RCC.cr().modify(|w| w.set_pllon(false));
while RCC.cr().read().pllrdy() {}
let freq = freq * mul / div;
assert!(freq <= Hertz(32_000_000));
RCC.cfgr().write(move |w| {
w.set_pllmul(mul);
w.set_plldiv(div);
w.set_pllsrc(src.into());
});
// Enable PLL
RCC.cr().modify(|w| w.set_pllon(true));
while !RCC.cr().read().pllrdy() {}
(freq, Sw::PLL)
}
};
let rtc = config.ls.init();
let wait_states = match (config.voltage_scale, sys_clk.0) {
(VoltageScale::RANGE1, ..=16_000_000) => 0,
(VoltageScale::RANGE2, ..=8_000_000) => 0,
(VoltageScale::RANGE3, ..=4_200_000) => 0,
_ => 1,
};
#[cfg(stm32l1)]
FLASH.acr().write(|w| w.set_acc64(true));
FLASH.acr().modify(|w| w.set_prften(true));
FLASH.acr().modify(|w| w.set_latency(wait_states != 0));
RCC.cfgr().modify(|w| {
w.set_sw(sw);
w.set_hpre(config.ahb_pre);
w.set_ppre1(config.apb1_pre);
w.set_ppre2(config.apb2_pre);
});
let ahb_freq = sys_clk / config.ahb_pre;
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let freq = ahb_freq / pre;
(freq, freq * 2u32)
}
};
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => {
let freq = ahb_freq / pre;
(freq, freq * 2u32)
}
};
#[cfg(crs)]
if config.enable_hsi48 {
// Reset CRS peripheral
RCC.apb1rstr().modify(|w| w.set_crsrst(true));
RCC.apb1rstr().modify(|w| w.set_crsrst(false));
// Enable CRS peripheral
RCC.apb1enr().modify(|w| w.set_crsen(true));
// Initialize CRS
CRS.cfgr().write(|w|
// Select LSE as synchronization source
w.set_syncsrc(crs::vals::Syncsrc::LSE));
CRS.cr().modify(|w| {
w.set_autotrimen(true);
w.set_cen(true);
});
// Enable VREFINT reference for HSI48 oscillator
SYSCFG.cfgr3().modify(|w| {
w.set_enref_hsi48(true);
w.set_en_vrefint(true);
});
// Select HSI48 as USB clock
RCC.ccipr().modify(|w| w.set_hsi48msel(true));
// Enable dedicated USB clock
RCC.crrcr().modify(|w| w.set_hsi48on(true));
while !RCC.crrcr().read().hsi48rdy() {}
}
set_freqs(Clocks {
sys: sys_clk,
ahb1: ahb_freq,
apb1: apb1_freq,
apb2: apb2_freq,
apb1_tim: apb1_tim_freq,
apb2_tim: apb2_tim_freq,
rtc,
});
}

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