Compare commits

..

6 Commits

Author SHA1 Message Date
3b7fec6efc wip 2023-10-03 17:59:49 -05:00
731df8be49 wip 2023-10-03 17:58:44 -05:00
2849bfcc6b wip 2023-10-03 17:57:12 -05:00
a4b20fc943 wip 2023-10-03 17:49:18 -05:00
8bb48f3083 wip 2023-10-03 17:47:41 -05:00
d7ce823d79 wpan: fix ipcc delay 2023-10-03 17:47:29 -05:00
127 changed files with 3827 additions and 2507 deletions

378
ci.sh
View File

@ -1,12 +1,9 @@
#!/bin/bash #!/bin/bash
set -eo pipefail set -euo 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')
@ -18,195 +15,194 @@ fi
find . -name '*.rs' -not -path '*target*' | xargs rustfmt --check --skip-children --unstable-features --edition 2021 find . -name '*.rs' -not -path '*target*' | xargs rustfmt --check --skip-children --unstable-features --edition 2021
cargo batch \ cargo batch \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/stm32wb55rg # \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,log \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,defmt \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,integrated-timers \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,integrated-timers \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt,integrated-timers \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt \
--- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \
--- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32 \
--- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,integrated-timers \
--- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread \
--- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread,integrated-timers \
--- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
--- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,nightly,dhcpv4-hostname \
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ieee802154 \
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,medium-ieee802154 \
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,nightly \
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet \
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet,nightly \
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,nightly \
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet,nightly \
--- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet,medium-ieee802154,nightly \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52805,gpiote,time-driver-rtc1 \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52810,gpiote,time-driver-rtc1 \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52811,gpiote,time-driver-rtc1 \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52820,gpiote,time-driver-rtc1 \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52832,gpiote,time-driver-rtc1,reset-pin-as-gpio \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52833,gpiote,time-driver-rtc1,unstable-traits,nfc-pins-as-gpio \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,nrf9160-s,gpiote,time-driver-rtc1 \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,nrf9160-ns,gpiote,time-driver-rtc1,unstable-traits \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,nrf5340-app-s,gpiote,time-driver-rtc1,unstable-traits \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,nrf5340-app-ns,gpiote,time-driver-rtc1 \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,nrf5340-net,gpiote,time-driver-rtc1,unstable-traits \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52840,gpiote,time-driver-rtc1 \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52840,log,gpiote,time-driver-rtc1 \
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52840,defmt,gpiote,time-driver-rtc1,unstable-traits \
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits,defmt \
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits,log \
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits \
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly \
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,intrinsics \
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,qspi-as-gpio \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,time-driver-any \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,time-driver-any \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f401ve,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f405zg,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f407zg,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f410tb,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f411ce,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f412zg,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f413vh,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f415zg,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f417zg,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f423zh,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f427zi,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,unstable-traits,embedded-sdmmc \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f437zi,log,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f439zi,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f446ze,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f469zi,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f479zi,defmt,exti,time-driver-any,unstable-traits,embedded-sdmmc \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f730i8,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h753zi,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h735zg,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l422cb,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wb15cc,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l072cz,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l041f6,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l073cz,defmt,exti,time-driver-any,unstable-traits,low-power \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f398ve,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f378cc,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32g0c1ve,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f217zg,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,stm32l552ze,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32wl54jc-cm0p,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wle5jb,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32g474pe,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f107vc,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f103re,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f100c4,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32h503rb,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32h562ag,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features ''\
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log' \
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log,firmware-logs' \
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt,firmware-logs' \
--- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features '' \
--- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'overclock' \
--- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,nightly \
--- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,nightly \
--- build --release --manifest-path embassy-boot/rp/Cargo.toml --target thumbv6m-none-eabi --features nightly \
--- build --release --manifest-path embassy-boot/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4,nightly \
--- build --release --manifest-path docs/modules/ROOT/examples/basic/Cargo.toml --target thumbv7em-none-eabi \
--- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-pac/Cargo.toml --target thumbv7em-none-eabi \
--- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-hal/Cargo.toml --target thumbv7em-none-eabi \
--- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-irq/Cargo.toml --target thumbv7em-none-eabi \
--- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml --target thumbv7em-none-eabi \
--- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \
--- build --release --manifest-path examples/nrf52840-rtic/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840-rtic \
--- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \
--- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \
--- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \
--- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f1 \
--- build --release --manifest-path examples/stm32f2/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f2 \
--- build --release --manifest-path examples/stm32f3/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f3 \
--- build --release --manifest-path examples/stm32f334/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f334 \
--- build --release --manifest-path examples/stm32f4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f4 \
--- build --release --manifest-path examples/stm32f7/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f7 \
--- build --release --manifest-path examples/stm32c0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32c0 \
--- build --release --manifest-path examples/stm32g0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32g0 \
--- build --release --manifest-path examples/stm32g4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32g4 \
--- build --release --manifest-path examples/stm32h5/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h5 \
--- build --release --manifest-path examples/stm32h7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7 \
--- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32l0 \
--- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32l1 \
--- build --release --manifest-path examples/stm32l4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32l4 \
--- build --release --manifest-path examples/stm32l5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32l5 \
--- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \
--- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wb \
--- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32wba \
--- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl \
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --out-dir out/examples/boot/nrf52840 \
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --out-dir out/examples/boot/nrf9160 \
--- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/rp \
--- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f3 \
--- build --release --manifest-path examples/boot/application/stm32f7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f7 \
--- build --release --manifest-path examples/boot/application/stm32h7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32h7 \
--- build --release --manifest-path examples/boot/application/stm32l0/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/stm32l0 \
--- build --release --manifest-path examples/boot/application/stm32l1/Cargo.toml --target thumbv7m-none-eabi --features skip-include --out-dir out/examples/boot/stm32l1 \
--- build --release --manifest-path examples/boot/application/stm32l4/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32l4 \
--- build --release --manifest-path examples/boot/application/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --features skip-include --out-dir out/examples/boot/stm32wl \
--- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
--- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \
--- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \
--- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \
--- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/stm32f103c8 \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --out-dir out/tests/stm32f429zi \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g491re --out-dir out/tests/stm32g491re \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g071rb --out-dir out/tests/stm32g071rb \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32c031c6 --out-dir out/tests/stm32c031c6 \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi --out-dir out/tests/stm32h755zi \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/stm32wb55rg \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h563zi --out-dir out/tests/stm32h563zi \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585ai --out-dir out/tests/stm32u585ai \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l073rz --out-dir out/tests/stm32l073rz \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l152re --out-dir out/tests/stm32l152re \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4a6zg --out-dir out/tests/stm32l4a6zg \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4r5zi --out-dir out/tests/stm32l4r5zi \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze --out-dir out/tests/stm32l552ze \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f767zi --out-dir out/tests/stm32f767zi \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f207zg --out-dir out/tests/stm32f207zg \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303ze --out-dir out/tests/stm32f303ze \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l496zg --out-dir out/tests/stm32l496zg \
--- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \
--- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \
--- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \
$BUILD_EXTRA
# --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly \
# --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,log \
# --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,defmt \
# --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
# --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \
# --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m \
# --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,integrated-timers \
# --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread \
# --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,integrated-timers \
# --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt \
# --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-interrupt,integrated-timers \
# --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt \
# --- build --release --manifest-path embassy-executor/Cargo.toml --target thumbv7em-none-eabi --features nightly,arch-cortex-m,executor-thread,executor-interrupt,integrated-timers \
# --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32 \
# --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,integrated-timers \
# --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread \
# --- build --release --manifest-path embassy-executor/Cargo.toml --target riscv32imac-unknown-none-elf --features nightly,arch-riscv32,executor-thread,integrated-timers \
# --- build --release --manifest-path embassy-sync/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt \
# --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \
# --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \
# --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \
# --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,nightly \
# --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \
# --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ieee802154 \
# --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,medium-ieee802154 \
# --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,nightly \
# --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet \
# --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ethernet,nightly \
# --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,nightly \
# --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet,nightly \
# --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,proto-ipv6,medium-ip,medium-ethernet,medium-ieee802154,nightly \
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52805,gpiote,time-driver-rtc1 \
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52810,gpiote,time-driver-rtc1 \
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52811,gpiote,time-driver-rtc1 \
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52820,gpiote,time-driver-rtc1 \
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52832,gpiote,time-driver-rtc1,reset-pin-as-gpio \
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52833,gpiote,time-driver-rtc1,unstable-traits,nfc-pins-as-gpio \
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,nrf9160-s,gpiote,time-driver-rtc1 \
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,nrf9160-ns,gpiote,time-driver-rtc1,unstable-traits \
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,nrf5340-app-s,gpiote,time-driver-rtc1,unstable-traits \
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,nrf5340-app-ns,gpiote,time-driver-rtc1 \
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,nrf5340-net,gpiote,time-driver-rtc1,unstable-traits \
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52840,gpiote,time-driver-rtc1 \
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52840,log,gpiote,time-driver-rtc1 \
# --- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nightly,nrf52840,defmt,gpiote,time-driver-rtc1,unstable-traits \
# --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits,defmt \
# --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits,log \
# --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,unstable-traits \
# --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly \
# --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,intrinsics \
# --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,qspi-as-gpio \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,time-driver-any \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,time-driver-any \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f401ve,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f405zg,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f407zg,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f410tb,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f411ce,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f412zg,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f413vh,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f415zg,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f417zg,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f423zh,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f427zi,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,unstable-traits,embedded-sdmmc \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f437zi,log,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f439zi,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f446ze,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f469zi,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f479zi,defmt,exti,time-driver-any,unstable-traits,embedded-sdmmc \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f730i8,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h753zi,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h735zg,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l422cb,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wb15cc,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l072cz,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l041f6,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l073cz,defmt,exti,time-driver-any,unstable-traits,low-power \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f398ve,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f378cc,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32g0c1ve,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f217zg,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,stm32l552ze,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32wl54jc-cm0p,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wle5jb,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32g474pe,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f107vc,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f103re,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f100c4,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32h503rb,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32h562ag,defmt,exti,time-driver-any,unstable-traits \
# --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features ''\
# --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log' \
# --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \
# --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log,firmware-logs' \
# --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt,firmware-logs' \
# --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features '' \
# --- build --release --manifest-path cyw43-pio/Cargo.toml --target thumbv6m-none-eabi --features 'overclock' \
# --- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,nightly \
# --- build --release --manifest-path embassy-boot/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,nightly \
# --- build --release --manifest-path embassy-boot/rp/Cargo.toml --target thumbv6m-none-eabi --features nightly \
# --- build --release --manifest-path embassy-boot/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4,nightly \
# --- build --release --manifest-path docs/modules/ROOT/examples/basic/Cargo.toml --target thumbv7em-none-eabi \
# --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-pac/Cargo.toml --target thumbv7em-none-eabi \
# --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-hal/Cargo.toml --target thumbv7em-none-eabi \
# --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-irq/Cargo.toml --target thumbv7em-none-eabi \
# --- build --release --manifest-path docs/modules/ROOT/examples/layer-by-layer/blinky-async/Cargo.toml --target thumbv7em-none-eabi \
# --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \
# --- build --release --manifest-path examples/nrf52840-rtic/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840-rtic \
# --- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \
# --- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \
# --- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \
# --- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f1 \
# --- build --release --manifest-path examples/stm32f2/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f2 \
# --- build --release --manifest-path examples/stm32f3/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f3 \
# --- build --release --manifest-path examples/stm32f334/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f334 \
# --- build --release --manifest-path examples/stm32f4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f4 \
# --- build --release --manifest-path examples/stm32f7/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f7 \
# --- build --release --manifest-path examples/stm32c0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32c0 \
# --- build --release --manifest-path examples/stm32g0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32g0 \
# --- build --release --manifest-path examples/stm32g4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32g4 \
# --- build --release --manifest-path examples/stm32h5/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h5 \
# --- build --release --manifest-path examples/stm32h7/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32h7 \
# --- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32l0 \
# --- build --release --manifest-path examples/stm32l1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32l1 \
# --- build --release --manifest-path examples/stm32l4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32l4 \
# --- build --release --manifest-path examples/stm32l5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32l5 \
# --- build --release --manifest-path examples/stm32u5/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32u5 \
# --- build --release --manifest-path examples/stm32wb/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wb \
# --- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/stm32wba \
# --- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32wl \
# --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --out-dir out/examples/boot/nrf52840 \
# --- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --out-dir out/examples/boot/nrf9160 \
# --- build --release --manifest-path examples/boot/application/rp/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/rp \
# --- build --release --manifest-path examples/boot/application/stm32f3/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f3 \
# --- build --release --manifest-path examples/boot/application/stm32f7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32f7 \
# --- build --release --manifest-path examples/boot/application/stm32h7/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32h7 \
# --- build --release --manifest-path examples/boot/application/stm32l0/Cargo.toml --target thumbv6m-none-eabi --features skip-include --out-dir out/examples/boot/stm32l0 \
# --- build --release --manifest-path examples/boot/application/stm32l1/Cargo.toml --target thumbv7m-none-eabi --features skip-include --out-dir out/examples/boot/stm32l1 \
# --- build --release --manifest-path examples/boot/application/stm32l4/Cargo.toml --target thumbv7em-none-eabi --features skip-include --out-dir out/examples/boot/stm32l4 \
# --- build --release --manifest-path examples/boot/application/stm32wl/Cargo.toml --target thumbv7em-none-eabihf --features skip-include --out-dir out/examples/boot/stm32wl \
# --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840 \
# --- build --release --manifest-path examples/boot/bootloader/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns \
# --- build --release --manifest-path examples/boot/bootloader/rp/Cargo.toml --target thumbv6m-none-eabi \
# --- build --release --manifest-path examples/boot/bootloader/stm32/Cargo.toml --target thumbv7em-none-eabi --features embassy-stm32/stm32wl55jc-cm4 \
# --- build --release --manifest-path examples/wasm/Cargo.toml --target wasm32-unknown-unknown --out-dir out/examples/wasm \
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f103c8 --out-dir out/tests/stm32f103c8 \
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi --out-dir out/tests/stm32f429zi \
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g491re --out-dir out/tests/stm32g491re \
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g071rb --out-dir out/tests/stm32g071rb \
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32c031c6 --out-dir out/tests/stm32c031c6 \
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi --out-dir out/tests/stm32h755zi \
#
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h563zi --out-dir out/tests/stm32h563zi \
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585ai --out-dir out/tests/stm32u585ai \
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l073rz --out-dir out/tests/stm32l073rz \
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l152re --out-dir out/tests/stm32l152re \
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4a6zg --out-dir out/tests/stm32l4a6zg \
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4r5zi --out-dir out/tests/stm32l4r5zi \
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze --out-dir out/tests/stm32l552ze \
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f767zi --out-dir out/tests/stm32f767zi \
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f207zg --out-dir out/tests/stm32f207zg \
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303ze --out-dir out/tests/stm32f303ze \
# --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l496zg --out-dir out/tests/stm32l496zg \
# --- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \
# --- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \
# --- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \
# $BUILD_EXTRA
rm out/tests/stm32wb55rg/wpan_mac rm /ci/cache/teleprobe_cache.json
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

@ -11,7 +11,7 @@ pub use asynch::Partition;
pub use blocking::BlockingPartition; pub use blocking::BlockingPartition;
/// Partition error /// Partition error
#[derive(Debug, PartialEq, Eq)] #[derive(Debug)]
#[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

@ -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.6.0" } embedded-io-async = { version = "0.5.0" }
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" } embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
ppproto = { version = "0.1.2"} ppproto = { version = "0.1.2"}

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}; use embedded_io_async::{BufRead, Write, WriteAllError};
use ppproto::pppos::{BufferFullError, PPPoS, PPPoSAction}; use ppproto::pppos::{BufferFullError, PPPoS, PPPoSAction};
pub use ppproto::{Config, Ipv4Status}; pub use ppproto::{Config, Ipv4Status};
@ -49,12 +49,23 @@ 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.
/// ///
@ -114,7 +125,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.map_err(RunError::Write)?, PPPoSAction::Transmit(n) => rw.write_all(&tx_buf[..n]).await?,
} }
let status = ppp.status(); let status = ppp.status();
@ -137,7 +148,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.map_err(RunError::Write)?, Ok(n) => rw.write_all(&tx_buf[..n]).await?,
Err(BufferFullError) => unreachable!(), Err(BufferFullError) => unreachable!(),
} }
tx_chan.tx_done(); tx_chan.tx_done();

View File

@ -33,7 +33,6 @@ 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"]
@ -54,7 +53,7 @@ smoltcp = { version = "0.10.0", default-features = false, features = [
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
embassy-time = { version = "0.1.3", path = "../embassy-time" } embassy-time = { version = "0.1.3", path = "../embassy-time" }
embassy-sync = { version = "0.3.0", path = "../embassy-sync" } embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
embedded-io-async = { version = "0.6.0", optional = true } embedded-io-async = { version = "0.5.0", optional = true }
managed = { version = "0.8.0", default-features = false, features = [ "map" ] } managed = { version = "0.8.0", default-features = false, features = [ "map" ] }
heapless = { version = "0.7.5", default-features = false } heapless = { version = "0.7.5", default-features = false }
@ -63,5 +62,5 @@ 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.6.0", optional = true } embedded-nal-async = { version = "0.5.0", optional = true }
atomic-polyfill = { version = "1.0" } atomic-polyfill = { version = "1.0" }

View File

@ -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(any(feature = "udp", feature = "tcp"))] #[cfg(feature = "udp")]
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,22 +56,12 @@ 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> {
@ -83,11 +73,6 @@ 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],
}),
} }
} }
} }
@ -119,7 +104,6 @@ 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.
/// ///
@ -136,9 +120,6 @@ 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")]
@ -150,8 +131,6 @@ 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,
} }
} }
} }
@ -253,8 +232,6 @@ 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 {
@ -330,8 +307,6 @@ 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")]
@ -698,25 +673,6 @@ 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

@ -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.6.0" } embedded-io = { version = "0.5.0" }
embedded-io-async = { version = "0.6.0", optional = true } embedded-io-async = { version = "0.5.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

@ -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.6.0" } embedded-io = { version = "0.5.0" }
embedded-io-async = { version = "0.6.0", optional = true } embedded-io-async = { version = "0.5.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"

View File

@ -1,83 +0,0 @@
//! 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 { in_ram(|| ram_helpers::flash_range_erase(from, len))? }; unsafe { self.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 { in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf))? } unsafe { self.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 { in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, aligned_data))? } unsafe { self.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 { in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, &ram_buf))? } unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, &ram_buf))? }
aligned_offset += PAGE_SIZE; aligned_offset += PAGE_SIZE;
} }
} }
@ -194,15 +194,47 @@ 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 { in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf))? } unsafe { self.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 { in_ram(|| ram_helpers::flash_unique_id(uid))? }; unsafe { self.in_ram(|| ram_helpers::flash_unique_id(uid))? };
Ok(()) Ok(())
} }
@ -210,7 +242,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 {
in_ram(|| { self.in_ram(|| {
jedec.replace(ram_helpers::flash_jedec_id()); jedec.replace(ram_helpers::flash_jedec_id());
})?; })?;
}; };
@ -839,38 +871,6 @@ 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

@ -6,12 +6,13 @@ 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, PartialEq, Eq)] #[derive(Debug)]
#[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
@ -26,7 +27,7 @@ pub enum AbortReason {
} }
/// I2C error /// I2C error
#[derive(Debug, PartialEq, Eq)] #[derive(Debug)]
#[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
@ -294,24 +295,13 @@ 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, true, true).await self.read_async_internal(buffer, false, 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> {
@ -328,22 +318,6 @@ 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,
@ -381,8 +355,23 @@ 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
set_up_i2c_pin(&scl); scl.gpio().ctrl().write(|w| w.set_funcsel(3));
set_up_i2c_pin(&sda); sda.gpio().ctrl().write(|w| w.set_funcsel(3));
scl.pad_ctrl().write(|w| {
w.set_schmitt(true);
w.set_ie(true);
w.set_od(false);
w.set_pue(true);
w.set_pde(false);
});
sda.pad_ctrl().write(|w| {
w.set_schmitt(true);
w.set_ie(true);
w.set_od(false);
w.set_pue(true);
w.set_pde(false);
});
// Configure baudrate // Configure baudrate
@ -724,7 +713,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, true, true).await self.read_async_internal(read, false, 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,14 +5,12 @@ 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::{ use crate::i2c::{i2c_reserved_addr, AbortReason, Instance, InterruptHandler, SclPin, SdaPin, FIFO_SIZE};
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, PartialEq, Eq)] #[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive] #[non_exhaustive]
pub enum Error { pub enum Error {
@ -102,8 +100,23 @@ 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
set_up_i2c_pin(&scl); scl.gpio().ctrl().write(|w| w.set_funcsel(3));
set_up_i2c_pin(&sda); sda.gpio().ctrl().write(|w| w.set_funcsel(3));
scl.pad_ctrl().write(|w| {
w.set_schmitt(true);
w.set_ie(true);
w.set_od(false);
w.set_pue(true);
w.set_pde(false);
});
sda.pad_ctrl().write(|w| {
w.set_schmitt(true);
w.set_ie(true);
w.set_od(false);
w.set_pue(true);
w.set_pde(false);
});
// Clear interrupts // Clear interrupts
p.ic_clr_intr().read(); p.ic_clr_intr().read();

View File

@ -10,7 +10,6 @@ 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;
@ -194,7 +193,6 @@ embassy_hal_internal::peripherals! {
PIO1, PIO1,
WATCHDOG, WATCHDOG,
BOOTSEL,
} }
macro_rules! select_bootloader { macro_rules! select_bootloader {

View File

@ -59,14 +59,15 @@ sdio-host = "0.5.0"
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
critical-section = "1.1" critical-section = "1.1"
atomic-polyfill = "1.0.1" atomic-polyfill = "1.0.1"
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-6bfa5a0dcec6a9bd42cea94ba11eeae1a17a7f2c" } stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-06d13dfd245cc9bf86fd88c35b401bdb84c079c4" }
vcell = "0.1.3" vcell = "0.1.3"
bxcan = "0.7.0" bxcan = "0.7.0"
nb = "1.0.0" nb = "1.0.0"
stm32-fmc = "0.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.6.0" } embedded-io = { version = "0.5.0" }
embedded-io-async = { version = "0.6.0", optional = true } embedded-io-async = { version = "0.5.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"
@ -77,7 +78,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-6bfa5a0dcec6a9bd42cea94ba11eeae1a17a7f2c", default-features = false, features = ["metadata"]} stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-06d13dfd245cc9bf86fd88c35b401bdb84c079c4", default-features = false, features = ["metadata"]}
[features] [features]

View File

@ -50,14 +50,12 @@ 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" => {
for pin in p.pins { if r.version.starts_with("h5") || r.version.starts_with("h7") || r.version.starts_with("f4") {
if pin.signal.starts_with("MCO") { singletons.push("MCO1".to_string());
let name = pin.signal.replace('_', "").to_string(); singletons.push("MCO2".to_string());
if !singletons.contains(&name) { }
println!("cargo:rustc-cfg={}", name.to_ascii_lowercase()); if r.version.starts_with("l4") {
singletons.push(name); singletons.push("MCO".to_string());
}
}
} }
singletons.push(p.name.to_string()); singletons.push(p.name.to_string());
} }
@ -753,8 +751,25 @@ 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_") {
peri = format_ident!("{}", pin.signal.replace('_', "")); // Supported in H7 only for now
if regs.version.starts_with("h5")
|| regs.version.starts_with("h7")
|| regs.version.starts_with("f4")
{
peri = format_ident!("{}", pin.signal.replace('_', ""));
} else {
continue;
}
}
if pin.signal == "MCO" {
// Supported in H7 only for now
if regs.version.starts_with("l4") {
peri = format_ident!("MCO");
} else {
continue;
}
} }
g.extend(quote! { g.extend(quote! {
@ -893,105 +908,6 @@ 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

@ -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))]
/// Custom Errors /// Curstom Errors
pub enum Error { pub enum Error {
UnconfiguredChannel, UnconfiguredChannel,
InvalidValue, InvalidValue,
@ -564,7 +564,7 @@ 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(any(rcc_h7, rcc_h7rm0433))] #[cfg(rcc_h7)]
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 })
@ -590,7 +590,7 @@ foreach_peripheral!(
} }
} }
#[cfg(any(rcc_h7, rcc_h7rm0433))] #[cfg(rcc_h7)]
impl crate::rcc::RccPeripheral for peripherals::$inst {} impl crate::rcc::RccPeripheral for peripherals::$inst {}
impl crate::dac::sealed::Instance for peripherals::$inst { impl crate::dac::sealed::Instance for peripherals::$inst {

View File

@ -41,40 +41,39 @@ mod phy_consts {
} }
use self::phy_consts::*; use self::phy_consts::*;
/// Generic SMI Ethernet PHY implementation /// Generic SMI Ethernet PHY
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 {
/// Construct the PHY. It assumes the address `phy_addr` in the SMI communication pub fn new() -> Self {
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(self.phy_addr, PHY_REG_BCR, PHY_REG_BCR_RESET); sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_RESET);
while sm.smi_read(self.phy_addr, PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {} while sm.smi_read(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( sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_AN | PHY_REG_BCR_ANRST | PHY_REG_BCR_100M);
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 {
@ -84,7 +83,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(self.phy_addr, PHY_REG_BSR); let bsr = sm.smi_read(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 {
@ -109,9 +108,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(self.phy_addr, PHY_REG_CTL, 0x0003); // set address sm.smi_write(PHY_REG_CTL, 0x0003); // set address
sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_addr); sm.smi_write(PHY_REG_ADDAR, reg_addr);
sm.smi_write(self.phy_addr, PHY_REG_CTL, 0x4003); // set data sm.smi_write(PHY_REG_CTL, 0x4003); // set data
sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_data); sm.smi_write(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, phy_addr: u8, reg: u8) -> u16; fn smi_read(&mut self, reg: u8) -> u16;
/// Write a register over SMI. /// Write a register over SMI.
fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16); fn smi_write(&mut self, reg: u8, val: u16);
} }
/// Traits for an Ethernet PHY /// Traits for an Ethernet PHY

View File

@ -107,6 +107,7 @@ 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);
@ -226,6 +227,7 @@ 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),
@ -269,14 +271,15 @@ 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, phy_addr: u8, reg: u8) -> u16 { fn smi_read(&mut self, reg: u8) -> u16 {
let mac = ETH.ethernet_mac(); let mac = ETH.ethernet_mac();
mac.macmiiar().modify(|w| { mac.macmiiar().modify(|w| {
w.set_pa(phy_addr); w.set_pa(self.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);
@ -286,12 +289,12 @@ unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
mac.macmiidr().read().md() mac.macmiidr().read().md()
} }
fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) { fn smi_write(&mut self, 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(phy_addr); w.set_pa(self.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,6 +71,7 @@ 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);
@ -201,6 +202,7 @@ 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,
}; };
@ -240,14 +242,15 @@ 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, phy_addr: u8, reg: u8) -> u16 { fn smi_read(&mut self, reg: u8) -> u16 {
let mac = ETH.ethernet_mac(); let mac = ETH.ethernet_mac();
mac.macmdioar().modify(|w| { mac.macmdioar().modify(|w| {
w.set_pa(phy_addr); w.set_pa(self.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);
@ -257,12 +260,12 @@ unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
mac.macmdiodr().read().md() mac.macmdiodr().read().md()
} }
fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) { fn smi_write(&mut self, 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(phy_addr); w.set_pa(self.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

@ -19,10 +19,8 @@ pub(crate) unsafe fn lock() {
} }
pub(crate) unsafe fn unlock() { pub(crate) unsafe fn unlock() {
if pac::FLASH.cr().read().lock() { pac::FLASH.keyr().write(|w| w.set_fkeyr(0x4567_0123));
pac::FLASH.keyr().write(|w| w.set_fkeyr(0x4567_0123)); pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB));
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,10 +19,8 @@ pub(crate) unsafe fn lock() {
} }
pub(crate) unsafe fn unlock() { pub(crate) unsafe fn unlock() {
if pac::FLASH.cr().read().lock() { pac::FLASH.keyr().write(|w| w.set_fkeyr(0x4567_0123));
pac::FLASH.keyr().write(|w| w.set_fkeyr(0x4567_0123)); pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB));
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,10 +228,8 @@ pub(crate) unsafe fn lock() {
} }
pub(crate) unsafe fn unlock() { pub(crate) unsafe fn unlock() {
if pac::FLASH.cr().read().lock() { pac::FLASH.keyr().write(|w| w.set_key(0x45670123));
pac::FLASH.keyr().write(|w| w.set_key(0x45670123)); pac::FLASH.keyr().write(|w| w.set_key(0xCDEF89AB));
pac::FLASH.keyr().write(|w| w.set_key(0xCDEF89AB));
}
} }
pub(crate) unsafe fn enable_write() { pub(crate) unsafe fn enable_write() {

View File

@ -19,10 +19,8 @@ pub(crate) unsafe fn lock() {
} }
pub(crate) unsafe fn unlock() { pub(crate) unsafe fn unlock() {
if pac::FLASH.cr().read().lock() { pac::FLASH.keyr().write(|w| w.set_key(0x4567_0123));
pac::FLASH.keyr().write(|w| w.set_key(0x4567_0123)); pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB));
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,10 +24,8 @@ pub(crate) unsafe fn unlock() {
while pac::FLASH.sr().read().bsy() {} while pac::FLASH.sr().read().bsy() {}
// Unlock flash // Unlock flash
if pac::FLASH.cr().read().lock() { pac::FLASH.keyr().write(|w| w.set_keyr(0x4567_0123));
pac::FLASH.keyr().write(|w| w.set_keyr(0x4567_0123)); pac::FLASH.keyr().write(|w| w.set_keyr(0xCDEF_89AB));
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,15 +26,11 @@ pub(crate) unsafe fn lock() {
} }
pub(crate) unsafe fn unlock() { pub(crate) unsafe fn unlock() {
if pac::FLASH.bank(0).cr().read().lock() { pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0x4567_0123));
pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0x4567_0123)); pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0xCDEF_89AB));
pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0xCDEF_89AB));
}
if is_dual_bank() { if is_dual_bank() {
if pac::FLASH.bank(1).cr().read().lock() { pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0x4567_0123));
pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0x4567_0123)); pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0xCDEF_89AB));
pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0xCDEF_89AB));
}
} }
} }

View File

@ -28,23 +28,17 @@ 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))]
{ {
if pac::FLASH.cr().read().lock() { pac::FLASH.keyr().write(|w| w.set_keyr(0x4567_0123));
pac::FLASH.keyr().write(|w| w.set_keyr(0x4567_0123)); pac::FLASH.keyr().write(|w| w.set_keyr(0xCDEF_89AB));
pac::FLASH.keyr().write(|w| w.set_keyr(0xCDEF_89AB));
}
} }
#[cfg(any(flash_l0, flash_l1))] #[cfg(any(flash_l0, flash_l1))]
{ {
if pac::FLASH.pecr().read().pelock() { pac::FLASH.pekeyr().write(|w| w.set_pekeyr(0x89ABCDEF));
pac::FLASH.pekeyr().write(|w| w.set_pekeyr(0x89ABCDEF)); pac::FLASH.pekeyr().write(|w| w.set_pekeyr(0x02030405));
pac::FLASH.pekeyr().write(|w| w.set_pekeyr(0x02030405));
}
if pac::FLASH.pecr().read().prglock() { pac::FLASH.prgkeyr().write(|w| w.set_prgkeyr(0x8C9DAEBF));
pac::FLASH.prgkeyr().write(|w| w.set_prgkeyr(0x8C9DAEBF)); pac::FLASH.prgkeyr().write(|w| w.set_prgkeyr(0x13141516));
pac::FLASH.prgkeyr().write(|w| w.set_prgkeyr(0x13141516));
}
} }
} }

View File

@ -974,18 +974,6 @@ 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

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

View File

@ -93,15 +93,30 @@ pub struct Ipcc;
impl Ipcc { impl Ipcc {
pub fn enable(_config: Config) { pub fn enable(_config: Config) {
// TODO: move these lines to the rcc mod
// set LPTIM1 & LPTIM2 clock source
crate::pac::RCC.ccipr().modify(|w| {
w.set_lptim1sel(0b00); // PCLK
w.set_lptim2sel(0b00); // PCLK
});
// set RF wake-up clock = LSE
crate::pac::RCC.csr().modify(|w| w.set_rfwkpsel(0b01));
IPCC::enable(); IPCC::enable();
IPCC::reset(); IPCC::reset();
// insert bus access and fence for delay
IPCC::enable();
compiler_fence(Ordering::SeqCst);
IPCC::set_cpu2(true); IPCC::set_cpu2(true);
_configure_pwr(); // insert bus access and fence for delay
IPCC::set_cpu2(true);
compiler_fence(Ordering::SeqCst);
let regs = IPCC::regs(); IPCC::regs().cpu(0).cr().modify(|w| {
regs.cpu(0).cr().modify(|w| {
w.set_rxoie(true); w.set_rxoie(true);
w.set_txfie(true); w.set_txfie(true);
}); });
@ -263,18 +278,3 @@ pub(crate) mod sealed {
fn state() -> &'static State; fn state() -> &'static State;
} }
} }
fn _configure_pwr() {
// TODO: move the rest of this to rcc
let rcc = crate::pac::RCC;
// TODO: required
// set RF wake-up clock = LSE
rcc.csr().modify(|w| w.set_rfwkpsel(0b01));
// set LPTIM1 & LPTIM2 clock source
rcc.ccipr().modify(|w| {
w.set_lptim1sel(0b00); // PCLK
w.set_lptim2sel(0b00); // PCLK
});
}

View File

@ -4,15 +4,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
use crate::Peripheral; use crate::Peripheral;
#[derive(Clone, Copy)] #[cfg(opamp_f3)]
pub enum OpAmpGain {
Mul1,
Mul2,
Mul4,
Mul8,
Mul16,
}
pub struct OpAmpOutput<'d, 'p, T: Instance, P: NonInvertingPin<T>> { pub struct OpAmpOutput<'d, 'p, T: Instance, P: NonInvertingPin<T>> {
_inner: &'d OpAmp<'d, T>, _inner: &'d OpAmp<'d, T>,
_input: &'p mut P, _input: &'p mut P,
@ -43,32 +35,14 @@ impl<'d, T: Instance> OpAmp<'d, T> {
Self { _inner: opamp } Self { _inner: opamp }
} }
pub fn buffer_for<'a, 'b, P>(&'a mut self, pin: &'b mut P, gain: OpAmpGain) -> OpAmpOutput<'a, 'b, T, P> #[cfg(opamp_f3)]
pub fn buffer_for<'a, 'b, P>(&'a mut self, pin: &'b mut P) -> OpAmpOutput<'a, 'b, T, P>
where where
P: NonInvertingPin<T>, 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)] #[cfg(opamp_f3)]
T::regs().opampcsr().modify(|w| { T::regs().opampcsr().modify(|w| {
w.set_vp_sel(pin.channel()); 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 { OpAmpOutput {

View File

@ -1,161 +1,110 @@
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,
} }
// All families but these have the LSEDRV register #[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))]
#[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;
#[cfg(any(stm32c0))] #[allow(dead_code)]
fn unlock() {} pub struct BackupDomain {}
#[cfg(not(any(stm32c0)))] impl BackupDomain {
fn unlock() { #[cfg(any(
#[cfg(any(stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1))] rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3,
let cr = crate::pac::PWR.cr(); rtc_v3u5
#[cfg(not(any(stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1, stm32u5, stm32h5, stm32wba)))] ))]
let cr = crate::pac::PWR.cr1(); #[allow(dead_code, unused_variables)]
#[cfg(any(stm32u5, stm32h5, stm32wba))] fn modify<R>(f: impl FnOnce(&mut Bdcr) -> R) -> R {
let cr = crate::pac::PWR.dbpcr(); #[cfg(any(rtc_v2f2, rtc_v2f3, rtc_v2l1, rtc_v2l0))]
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();
cr.modify(|w| w.set_dbp(true)); // TODO: Missing from PAC for l0 and f0?
while !cr.read().dbp() {} #[cfg(not(any(rtc_v2f0, rtc_v3u5)))]
} {
cr.modify(|w| w.set_dbp(true));
fn bdcr() -> Reg<Bdcr, RW> { while !cr.read().dbp() {}
#[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))
} }
pub const fn default_lsi() -> Self { #[cfg(any(
Self { rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3,
rtc: RtcClockSource::LSI, rtc_v3u5
lsi: true, ))]
lse: None, #[allow(dead_code)]
} 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
} }
pub const fn off() -> Self { #[cfg(any(
Self { rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3,
rtc: RtcClockSource::NOCLOCK, rtc_v3u5
lsi: false, ))]
lse: None, #[allow(dead_code, unused_variables)]
} pub fn configure_ls(clock_source: RtcClockSource, lsi: bool, lse: Option<LseDrive>) {
} use atomic_polyfill::{compiler_fence, Ordering};
}
impl Default for LsConfig { match clock_source {
fn default() -> Self { RtcClockSource::LSI => assert!(lsi),
// on L5, just the fact that LSI is enabled makes things crash. RtcClockSource::LSE => assert!(&lse.is_some()),
// 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 { if lsi {
Some(c) => match c.mode { #[cfg(rtc_v3u5)]
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))]
let csr = crate::pac::RCC.csr2(); // Disable backup domain write protection
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));
@ -175,71 +124,60 @@ impl LsConfig {
// first check if the configuration matches what we want. // first check if the configuration matches what we want.
// check if it's already enabled and in the source we want. // check if it's already enabled and in the source we want.
let reg = bdcr().read(); let reg = Self::read();
let mut ok = true; let mut ok = true;
ok &= reg.rtcsel() == self.rtc; ok &= reg.rtcsel() == clock_source;
#[cfg(not(rcc_wba))] #[cfg(not(rcc_wba))]
{ {
ok &= reg.rtcen() == (self.rtc != RtcClockSource::NOCLOCK); ok &= reg.rtcen() == (clock_source != RtcClockSource::NOCLOCK);
} }
ok &= reg.lseon() == lse_en; ok &= reg.lseon() == lse.is_some();
ok &= reg.lsebyp() == lse_byp; #[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))]
#[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f400, rcc_f410, rcc_l1)))] if let Some(lse_drive) = lse {
if let Some(lse_drv) = lse_drv { ok &= reg.lsedrv() == lse_drive.into();
ok &= reg.lsedrv() == lse_drv.into();
} }
// if configuration is OK, we're done. // if configuration is OK, we're done.
if ok { if ok {
trace!("BDCR ok: {:08x}", bdcr().read().0); // RTC code assumes backup domain is unlocked
return rtc_clk; Self::modify(|w| {});
trace!("BDCR ok: {:08x}", Self::read().0);
compiler_fence(Ordering::SeqCst);
return;
} }
// If not OK, reset backup domain and configure it. // If not OK, reset backup domain and configure it.
#[cfg(not(any(rcc_l0, rcc_l0_v2, rcc_l1, stm32h5, stm32c0)))] #[cfg(not(any(rcc_l0, rcc_l1)))]
{ {
bdcr().modify(|w| w.set_bdrst(true)); Self::modify(|w| w.set_bdrst(true));
bdcr().modify(|w| w.set_bdrst(false)); Self::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 { if let Some(lse_drive) = lse {
bdcr().modify(|w| { Self::modify(|w| {
#[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f400, rcc_f410, rcc_l1)))] #[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))]
if let Some(lse_drv) = lse_drv { w.set_lsedrv(lse_drive.into());
w.set_lsedrv(lse_drv.into());
}
w.set_lsebyp(lse_byp);
w.set_lseon(true); w.set_lseon(true);
}); });
while !bdcr().read().lserdy() {} while !Self::read().lserdy() {}
} }
if self.rtc != RtcClockSource::NOCLOCK { if clock_source != RtcClockSource::NOCLOCK {
bdcr().modify(|w| { Self::modify(|w| {
#[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!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet."); assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet.");
#[cfg(not(rcc_wba))] #[cfg(not(rcc_wba))]
w.set_rtcen(true); w.set_rtcen(true);
w.set_rtcsel(self.rtc); w.set_rtcsel(clock_source);
}); });
} }
trace!("BDCR configured: {:08x}", bdcr().read().0); trace!("BDCR configured: {:08x}", Self::read().0);
compiler_fence(Ordering::SeqCst); compiler_fence(Ordering::SeqCst);
rtc_clk
} }
} }

View File

@ -0,0 +1,56 @@
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::Sw; use crate::pac::rcc::vals::{Hsidiv, Ppre, 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,6 +8,9 @@ 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 {
@ -16,22 +19,47 @@ 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::DIV1), mux: ClockSrc::HSI(HSIPrescaler::NotDivided),
ahb_pre: AHBPrescaler::DIV1, ahb_pre: AHBPrescaler::DIV1,
apb_pre: APBPrescaler::DIV1, apb_pre: APBPrescaler::DIV1,
ls: Default::default(),
} }
} }
} }
@ -40,34 +68,33 @@ 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 / div, Sw::HSI) (HSI_FREQ.0 >> div.to_bits(), 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, Sw::HSE) (freq.0, 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() {}
(super::LSI_FREQ, Sw::LSI) (LSI_FREQ.0, 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 <= Hertz(24_000_000) { let target_flash_latency = if sys_clk <= 24_000_000 {
Latency::WS0 Latency::WS0
} else { } else {
Latency::WS1 Latency::WS1
@ -102,7 +129,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, config.apb_pre); let (sw, hpre, ppre) = (sw.into(), config.ahb_pre.into(), config.apb_pre.into());
RCC.cfgr().modify(|w| { RCC.cfgr().modify(|w| {
w.set_sw(sw); w.set_sw(sw);
w.set_hpre(hpre); w.set_hpre(hpre);
@ -123,21 +150,34 @@ 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 = sys_clk / config.ahb_pre; let ahb_div = match 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 freq = ahb_freq / pre; let pre: Ppre = pre.into();
(freq, freq * 2u32) let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
} }
}; };
set_freqs(Clocks { set_freqs(Clocks {
sys: sys_clk, sys: Hertz(sys_clk),
ahb1: ahb_freq, ahb1: Hertz(ahb_freq),
apb1: apb_freq, apb1: Hertz(apb_freq),
apb1_tim: apb_tim_freq, apb1_tim: Hertz(apb_tim_freq),
rtc,
}); });
} }

View File

@ -8,6 +8,9 @@ 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
@ -24,8 +27,6 @@ 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) {
@ -158,8 +159,6 @@ 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),
@ -167,6 +166,5 @@ 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,6 +9,9 @@ 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]
@ -22,8 +25,6 @@ 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) {
@ -176,8 +177,6 @@ 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),
@ -186,6 +185,5 @@ 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,16 +1,21 @@
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::Sw; use crate::pac::rcc::vals::{Pllp, Pllsrc, 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,
@ -38,17 +43,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 p_div: PLLPDiv, pub main_div: PLLMainDiv,
pub q_div: PLLQDiv, pub pll48_div: PLL48Div,
} }
impl Default for PLLConfig { impl Default for PLLConfig {
fn default() -> Self { fn default() -> Self {
PLLConfig { PLLConfig {
pre_div: PLLPreDiv::DIV16, pre_div: PLLPreDiv(16),
mul: PLLMul::MUL192, mul: PLLMul(192),
p_div: PLLPDiv::DIV2, main_div: PLLMainDiv::Div2,
q_div: PLLQDiv::DIV4, pll48_div: PLL48Div(4),
} }
} }
} }
@ -56,9 +61,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 = src_freq / self.pre_div * self.mul; let vco_freq = Hertz((src_freq.0 as u64 * self.mul.0 as u64 / self.pre_div.0 as u64) as u32);
let main_freq = vco_freq / self.p_div; let main_freq = vco_freq / self.main_div;
let pll48_freq = vco_freq / self.q_div; let pll48_freq = vco_freq / self.pll48_div;
PLLClocks { PLLClocks {
in_freq, in_freq,
vco_freq, vco_freq,
@ -67,6 +72,129 @@ 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,
@ -175,11 +303,13 @@ 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 {
@ -192,10 +322,12 @@ 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(),
} }
} }
} }
@ -235,11 +367,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); w.set_pllsrc(config.pll_mux.into());
w.set_pllm(config.pll.pre_div); w.set_pllm(config.pll.pre_div.0);
w.set_plln(config.pll.mul); w.set_plln(config.pll.mul.0);
w.set_pllp(config.pll.p_div); w.set_pllp(config.pll.main_div.into());
w.set_pllq(config.pll.q_div); w.set_pllq(config.pll.pll48_div.0);
}); });
let (sys_clk, sw) = match config.mux { let (sys_clk, sw) = match config.mux {
@ -292,9 +424,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); w.set_hpre(config.ahb_pre.into());
w.set_ppre1(config.apb1_pre); w.set_ppre1(config.apb1_pre.into());
w.set_ppre2(config.apb2_pre); w.set_ppre2(config.apb2_pre.into());
}); });
while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {} while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {}
@ -303,7 +435,11 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cr().modify(|w| w.set_hsion(false)); RCC.cr().modify(|w| w.set_hsion(false));
} }
let rtc = config.ls.init(); BackupDomain::configure_ls(
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,
@ -315,6 +451,5 @@ 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,8 +1,7 @@
#[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;
pub use crate::pac::rcc::vals::Adcpres; use crate::pac::rcc::vals::{Adcpres, Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre};
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;
@ -10,6 +9,28 @@ 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 {
@ -24,13 +45,32 @@ impl From<AdcClockSource> for Ckmode {
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum AdcClockSource { pub enum AdcClockSource {
Pll(Adcpres), PllDiv1 = 1,
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,
@ -84,7 +124,6 @@ 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
@ -98,67 +137,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 (sysclk, pll_config) = get_sysclk(&config); let (Hertz(sysclk), pll_config) = get_sysclk(&config);
assert!(sysclk.0 <= 72_000_000); assert!(sysclk <= 72_000_000);
// Calculate real AHB clock // Calculate real AHB clock
let hclk = config.hclk.map(|h| h).unwrap_or(sysclk); let hclk = config.hclk.map(|h| h.0).unwrap_or(sysclk);
let hpre = match sysclk.0 / hclk.0 { let (hpre_bits, hpre_div) = match sysclk / hclk {
0 => unreachable!(), 0 => unreachable!(),
1 => Hpre::DIV1, 1 => (Hpre::DIV1, 1),
2 => Hpre::DIV2, 2 => (Hpre::DIV2, 2),
3..=5 => Hpre::DIV4, 3..=5 => (Hpre::DIV4, 4),
6..=11 => Hpre::DIV8, 6..=11 => (Hpre::DIV8, 8),
12..=39 => Hpre::DIV16, 12..=39 => (Hpre::DIV16, 16),
40..=95 => Hpre::DIV64, 40..=95 => (Hpre::DIV64, 64),
96..=191 => Hpre::DIV128, 96..=191 => (Hpre::DIV128, 128),
192..=383 => Hpre::DIV256, 192..=383 => (Hpre::DIV256, 256),
_ => Hpre::DIV512, _ => (Hpre::DIV512, 512),
}; };
let hclk = sysclk / hpre; let hclk = sysclk / hpre_div;
assert!(hclk <= Hertz(72_000_000)); assert!(hclk <= 72_000_000);
// Calculate real APB1 clock // Calculate real APB1 clock
let pclk1 = config.pclk1.unwrap_or(hclk); let pclk1 = config.pclk1.map(|p| p.0).unwrap_or(hclk);
let ppre1 = match hclk / pclk1 { let (ppre1_bits, ppre1) = match hclk / pclk1 {
0 => unreachable!(), 0 => unreachable!(),
1 => Ppre::DIV1, 1 => (Ppre::DIV1, 1),
2 => Ppre::DIV2, 2 => (Ppre::DIV2, 2),
3..=5 => Ppre::DIV4, 3..=5 => (Ppre::DIV4, 4),
6..=11 => Ppre::DIV8, 6..=11 => (Ppre::DIV8, 8),
_ => Ppre::DIV16, _ => (Ppre::DIV16, 16),
}; };
let timer_mul1 = if ppre1 == Ppre::DIV1 { 1u32 } else { 2 }; let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
let pclk1 = hclk / ppre1; let pclk1 = hclk / ppre1;
assert!(pclk1 <= Hertz(36_000_000)); assert!(pclk1 <= 36_000_000);
// Calculate real APB2 clock // Calculate real APB2 clock
let pclk2 = config.pclk2.unwrap_or(hclk); let pclk2 = config.pclk2.map(|p| p.0).unwrap_or(hclk);
let ppre2 = match hclk / pclk2 { let (ppre2_bits, ppre2) = match hclk / pclk2 {
0 => unreachable!(), 0 => unreachable!(),
1 => Ppre::DIV1, 1 => (Ppre::DIV1, 1),
2 => Ppre::DIV2, 2 => (Ppre::DIV2, 2),
3..=5 => Ppre::DIV4, 3..=5 => (Ppre::DIV4, 4),
6..=11 => Ppre::DIV8, 6..=11 => (Ppre::DIV8, 8),
_ => Ppre::DIV16, _ => (Ppre::DIV16, 16),
}; };
let timer_mul2 = if ppre2 == Ppre::DIV1 { 1u32 } else { 2 }; let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
let pclk2 = hclk / ppre2; let pclk2 = hclk / ppre2;
assert!(pclk2 <= Hertz(72_000_000)); assert!(pclk2 <= 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 <= Hertz(24_000_000) { w.set_latency(if hclk <= 24_000_000 {
Latency::WS0 Latency::WS0
} else if hclk <= Hertz(48_000_000) { } else if hclk <= 48_000_000 {
Latency::WS1 Latency::WS1
} else { } else {
Latency::WS2 Latency::WS2
}); });
if hpre != Hpre::DIV1 { if hpre_div != 1 {
w.set_hlfcya(false); w.set_hlfcya(false);
w.set_prftbe(true); w.set_prftbe(true);
} }
@ -201,9 +240,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); w.set_ppre2(ppre2_bits);
w.set_ppre1(ppre1); w.set_ppre1(ppre1_bits);
w.set_hpre(hpre); w.set_hpre(hpre_bits);
}); });
// Wait for the new prescalers to kick in // Wait for the new prescalers to kick in
@ -221,43 +260,45 @@ pub(crate) unsafe fn init(config: Config) {
}); });
#[cfg(rcc_f3)] #[cfg(rcc_f3)]
let adc = config.adc.map(|adc| match adc { let adc = config.adc.map(|adc| {
AdcClockSource::Pll(adcpres) => { if !adc.is_bus() {
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(adcpres); w.set_adc12pres(adc.into());
sysclk / adcpres Hertz(sysclk / adc as u32)
})
} 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.adc34.map(|adc| match adc { let adc34 = config.adc.map(|adc| {
AdcClockSource::Pll(adcpres) => { if !adc.is_bus() {
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_adc34pres(adcpres); w.set_adc12pres(adc.into());
sysclk / adcpres Hertz(sysclk / adc as u32)
})
} 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)]
@ -269,23 +310,21 @@ 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 * 2u32 == sysclk)); assert!((pclk2 == sysclk) || (pclk2 * 2 == sysclk));
RCC.cfgr3().modify(|w| w.set_hrtim1sw(Timsw::PLL)); RCC.cfgr3().modify(|w| w.set_hrtim1sw(Timsw::PLL));
Some(sysclk * 2u32) Some(Hertz(sysclk * 2))
} }
}; };
let rtc = config.ls.init();
set_freqs(Clocks { set_freqs(Clocks {
sys: sysclk, sys: Hertz(sysclk),
apb1: pclk1, apb1: Hertz(pclk1),
apb2: pclk2, apb2: Hertz(pclk2),
apb1_tim: pclk1 * timer_mul1, apb1_tim: Hertz(pclk1 * timer_mul1),
apb2_tim: pclk2 * timer_mul2, apb2_tim: Hertz(pclk2 * timer_mul2),
ahb1: hclk, ahb1: Hertz(hclk),
#[cfg(rcc_f3)] #[cfg(rcc_f3)]
adc: adc, adc: adc,
#[cfg(all(rcc_f3, adc3_common))] #[cfg(all(rcc_f3, adc3_common))]
@ -294,7 +333,6 @@ pub(crate) unsafe fn init(config: Config) {
adc34: None, adc34: None,
#[cfg(stm32f334)] #[cfg(stm32f334)]
hrtim: hrtim, hrtim: hrtim,
rtc,
}); });
} }
@ -383,16 +421,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: Hertz, pclk1: Hertz, pll_config: &Option<PllConfig>) -> Usbpre { fn get_usb_pre(config: &Config, sysclk: u32, pclk1: u32, 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 >= Hertz(10_000_000)); let usb_ok = config.hse.is_some() && pll_config.is_some() && (pclk1 >= 10_000_000);
match (usb_ok, sysclk) { match (usb_ok, sysclk) {
(true, Hertz(72_000_000)) => Usbpre::DIV1_5, (true, 72_000_000) => Usbpre::DIV1_5,
(true, Hertz(48_000_000)) => Usbpre::DIV1, (true, 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,11 +1,23 @@
use crate::pac::rcc::vals::{Hpre, Pllm, Plln, Pllq, Pllr, Ppre, Sw}; use core::marker::PhantomData;
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)]
@ -24,7 +36,9 @@ pub struct Config {
pub pllsai: Option<Hertz>, pub pllsai: Option<Hertz>,
pub pll48: bool, pub pll48: bool,
pub ls: super::LsConfig, pub rtc: Option<RtcClockSource>,
pub lsi: bool,
pub lse: Option<Hertz>,
} }
#[cfg(stm32f410)] #[cfg(stm32f410)]
@ -164,12 +178,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::from_bits(pllm as u8)); w.set_pllm(pllm as u8);
w.set_plln(Plln::from_bits(plln as u16)); w.set_plln(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::from_bits(pllq as u8)); w.set_pllq(pllq as u8);
w.set_pllsrc(Pllsrc::from_bits(use_hse as u8)); w.set_pllsrc(Pllsrc::from_bits(use_hse as u8));
w.set_pllr(Pllr::from_bits(0)); w.set_pllr(0);
}); });
let real_pllsysclk = vco_in * plln / sysclk_div; let real_pllsysclk = vco_in * plln / sysclk_div;
@ -183,6 +197,164 @@ 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;
@ -336,7 +508,17 @@ pub(crate) unsafe fn init(config: Config) {
}) })
}); });
let rtc = config.ls.init(); BackupDomain::configure_ls(
config.rtc.unwrap_or(RtcClockSource::NOCLOCK),
config.lsi,
config.lse.map(|_| Default::default()),
);
let rtc = match config.rtc {
Some(RtcClockSource::LSI) => Some(LSI_FREQ),
Some(RtcClockSource::LSE) => Some(config.lse.unwrap()),
_ => None,
};
set_freqs(Clocks { set_freqs(Clocks {
sys: Hertz(sysclk), sys: Hertz(sysclk),
@ -358,7 +540,8 @@ 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,12 +1,16 @@
use crate::pac::pwr::vals::Vos; use crate::pac::pwr::vals::Vos;
use crate::pac::rcc::vals::{Hpre, Pllm, Plln, Pllp, Pllq, Pllsrc, Ppre, Sw}; use crate::pac::rcc::vals::{Hpre, Ppre, Sw};
use crate::pac::{FLASH, PWR, RCC}; use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::bd::{BackupDomain, RtcClockSource};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
/// 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)]
@ -19,10 +23,14 @@ pub struct Config {
pub pclk2: Option<Hertz>, pub pclk2: Option<Hertz>,
pub pll48: bool, pub pll48: bool,
pub ls: super::LsConfig, pub rtc: Option<RtcClockSource>,
pub lsi: bool,
pub lse: Option<Hertz>,
} }
fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults { fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults {
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)));
@ -76,10 +84,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::from_bits(pllm as u8)); w.set_pllm(pllm as u8);
w.set_plln(Plln::from_bits(plln as u16)); w.set_plln(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::from_bits(pllq as u8)); w.set_pllq(pllq as u8);
w.set_pllsrc(Pllsrc::from_bits(use_hse as u8)); w.set_pllsrc(Pllsrc::from_bits(use_hse as u8));
}); });
@ -255,7 +263,17 @@ pub(crate) unsafe fn init(config: Config) {
}) })
}); });
let rtc = config.ls.init(); BackupDomain::configure_ls(
config.rtc.unwrap_or(RtcClockSource::NOCLOCK),
config.lsi,
config.lse.map(|_| Default::default()),
);
let rtc = match config.rtc {
Some(RtcClockSource::LSI) => Some(LSI_FREQ),
Some(RtcClockSource::LSE) => Some(config.lse.unwrap()),
_ => None,
};
set_freqs(Clocks { set_freqs(Clocks {
sys: Hertz(sysclk), sys: Hertz(sysclk),

View File

@ -1,8 +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::{self, Sw}; use crate::pac::rcc::vals::{self, Hsidiv, Ppre, 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;
@ -10,6 +8,9 @@ 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 {
@ -19,6 +20,33 @@ 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`
@ -32,15 +60,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: Plln, pub n: u8,
/// 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<Pllq>, pub q: Option<Pllr>,
/// The divisor for the `PLLPCLK` output, if desired /// The divisor for the `PLLPCLK` output, if desired
pub p: Option<Pllp>, pub p: Option<Pllr>,
} }
impl Default for PllConfig { impl Default for PllConfig {
@ -49,9 +77,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: Plln::MUL8, n: 8,
r: Pllr::DIV2, r: Pllr::Div2,
q: None, q: None,
p: None, p: None,
} }
@ -64,51 +92,131 @@ 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::DIV1), mux: ClockSrc::HSI16(HSI16Prescaler::NotDivided),
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) -> Hertz { pub(crate) fn init(self) -> u32 {
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), PllSrc::HSI16 => (vals::Pllsrc::HSI16, HSI_FREQ.0),
PllSrc::HSE(freq) => (vals::Pllsrc::HSE, freq), PllSrc::HSE(freq) => (vals::Pllsrc::HSE, freq.0),
}; };
let m_freq = input_freq / self.m; let m_freq = input_freq / u32::from(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.0 >= 2_660_000 && m_freq.0 <= 16_000_000); debug_assert!(m_freq >= 2_660_000 && m_freq <= 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.0 >= 64_000_000 && n_freq.0 <= 344_000_000); debug_assert!(n_freq >= 64_000_000 && n_freq <= 344_000_000);
let r_freq = n_freq / self.r; let r_freq = n_freq / u32::from(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.0 <= 64_000_000); debug_assert!(r_freq <= 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:
@ -131,16 +239,25 @@ impl PllConfig {
} }
} }
// Configure PLLCFGR // Configure PLLSYSCFGR
RCC.pllcfgr().modify(|w| { RCC.pllsyscfgr().modify(|w| {
w.set_pllr(self.r); w.set_pllr(u8::from(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)
}); });
@ -152,7 +269,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.pllcfgr().modify(|w| { RCC.pllsyscfgr().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);
@ -169,20 +286,21 @@ 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 / div, Sw::HSI) (HSI_FREQ.0 >> div.to_bits(), 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, Sw::HSE) (freq.0, Sw::HSE)
} }
ClockSrc::PLL(pll) => { ClockSrc::PLL(pll) => {
let freq = pll.init(); let freq = pll.init();
@ -192,15 +310,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() {}
(super::LSI_FREQ, Sw::LSI) (LSI_FREQ.0, 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.0 <= 24_000_000 { let target_flash_latency = if sys_clk <= 24_000_000 {
Latency::WS0 Latency::WS0
} else if sys_clk.0 <= 48_000_000 { } else if sys_clk <= 48_000_000 {
Latency::WS1 Latency::WS1
} else { } else {
Latency::WS2 Latency::WS2
@ -235,7 +353,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, config.apb_pre); let (sw, hpre, ppre) = (sw.into(), config.ahb_pre.into(), config.apb_pre.into());
RCC.cfgr().modify(|w| { RCC.cfgr().modify(|w| {
w.set_sw(sw); w.set_sw(sw);
w.set_hpre(hpre); w.set_hpre(hpre);
@ -256,28 +374,27 @@ 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 = sys_clk / config.ahb_pre; let ahb_freq = Hertz(sys_clk) / config.ahb_pre;
let (apb_freq, apb_tim_freq) = match config.apb_pre { let (apb_freq, apb_tim_freq) = match config.apb_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq), APBPrescaler::DIV1 => (ahb_freq.0, ahb_freq.0),
pre => { pre => {
let freq = ahb_freq / pre; let pre: Ppre = pre.into();
(freq, freq * 2u32) let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq.0 / pre as u32;
(freq, freq * 2)
} }
}; };
if config.low_power_run { if config.low_power_run {
assert!(sys_clk.0 <= 2_000_000); assert!(sys_clk <= 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: sys_clk, sys: Hertz(sys_clk),
ahb1: ahb_freq, ahb1: ahb_freq,
apb1: apb_freq, apb1: Hertz(apb_freq),
apb1_tim: apb_tim_freq, apb1_tim: Hertz(apb_tim_freq),
rtc,
}); });
} }

View File

@ -2,10 +2,7 @@ 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 crate::pac::rcc::vals::{ pub use super::bus::{AHBPrescaler, APBPrescaler};
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};
@ -14,6 +11,32 @@ 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 {
@ -38,6 +61,181 @@ 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
@ -63,6 +261,32 @@ 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
@ -98,8 +322,6 @@ 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.
@ -119,9 +341,8 @@ 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: Adcsel::NOCLK, adc12_clock_source: Default::default(),
adc345_clock_source: Adcsel::NOCLK, adc345_clock_source: Default::default(),
ls: Default::default(),
} }
} }
} }
@ -139,12 +360,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 HSI_FREQ.0
} }
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 freq.0
} }
}; };
@ -152,36 +373,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 * pll_config.mul_n; let internal_freq = src_freq / pll_config.prediv_m.to_div() * pll_config.mul_n.to_mul();
RCC.pllcfgr().write(|w| { RCC.pllcfgr().write(|w| {
w.set_plln(pll_config.mul_n); w.set_plln(pll_config.mul_n.into());
w.set_pllm(pll_config.prediv_m); w.set_pllm(pll_config.prediv_m.into());
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_pllp(div_p); w.set_pllpdiv(div_p.into());
w.set_pllpen(true); w.set_pllpen(true);
}); });
internal_freq / div_p Hertz(internal_freq / div_p.to_div())
}); });
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); w.set_pllq(div_q.into());
w.set_pllqen(true); w.set_pllqen(true);
}); });
internal_freq / div_q Hertz(internal_freq / div_q.to_div())
}); });
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); w.set_pllr(div_r.into());
w.set_pllren(true); w.set_pllren(true);
}); });
internal_freq / div_r Hertz(internal_freq / div_r.to_div())
}); });
// Enable the PLL // Enable the PLL
@ -201,14 +422,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, Sw::HSI16) (HSI_FREQ.0, 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, Sw::HSE) (freq.0, Sw::HSE)
} }
ClockSrc::PLL => { ClockSrc::PLL => {
assert!(pll_freq.is_some()); assert!(pll_freq.is_some());
@ -249,32 +470,35 @@ pub(crate) unsafe fn init(config: Config) {
} }
} }
(Hertz(freq), Sw::PLLRCLK) (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); w.set_hpre(config.ahb_pre.into());
w.set_ppre1(config.apb1_pre); w.set_ppre1(config.apb1_pre.into());
w.set_ppre2(config.apb2_pre); w.set_ppre2(config.apb2_pre.into());
}); });
let ahb_freq = sys_clk / config.ahb_pre; let ahb_freq: u32 = match 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 / pre; let freq = ahb_freq / apb_div(pre);
(freq, freq * 2u32) (freq, freq * 2)
} }
}; };
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 / pre; let freq = ahb_freq / apb_div(pre);
(freq, freq * 2u32) (freq, freq * 2)
} }
}; };
@ -322,40 +546,43 @@ 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().modify(|w| w.set_adc12sel(config.adc12_clock_source)); RCC.ccipr()
RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source)); .modify(|w| w.set_adc12sel(config.adc12_clock_source.adcsel()));
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 => pll_freq.as_ref().unwrap().pll_p, AdcClockSource::PllP => match &pll_freq {
AdcClockSource::SYSCLK => Some(sys_clk), Some(pll) => pll.pll_p,
_ => unreachable!(), None => None,
},
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 => pll_freq.as_ref().unwrap().pll_p, AdcClockSource::PllP => match &pll_freq {
AdcClockSource::SYSCLK => Some(sys_clk), Some(pll) => pll.pll_p,
_ => unreachable!(), None => None,
},
AdcClockSource::SysClk => Some(Hertz(sys_clk)),
}; };
if config.low_power_run { if config.low_power_run {
assert!(sys_clk <= Hertz(2_000_000)); assert!(sys_clk <= 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: sys_clk, sys: Hertz(sys_clk),
ahb1: ahb_freq, ahb1: Hertz(ahb_freq),
ahb2: ahb_freq, ahb2: Hertz(ahb_freq),
apb1: apb1_freq, apb1: Hertz(apb1_freq),
apb1_tim: apb1_tim_freq, apb1_tim: Hertz(apb1_tim_freq),
apb2: apb2_freq, apb2: Hertz(apb2_freq),
apb2_tim: apb2_tim_freq, apb2_tim: Hertz(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,15 +21,18 @@ 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);
const VCO_RANGE: RangeInclusive<Hertz> = Hertz(150_000_000)..=Hertz(420_000_000); /// LSI speed
#[cfg(any(stm32h5, pwr_h7rm0455))] pub const LSI_FREQ: Hertz = Hertz(32_000);
const VCO_WIDE_RANGE: RangeInclusive<Hertz> = Hertz(128_000_000)..=Hertz(560_000_000);
#[cfg(pwr_h7rm0468)]
const VCO_WIDE_RANGE: RangeInclusive<Hertz> = Hertz(192_000_000)..=Hertz(836_000_000);
#[cfg(any(pwr_h7rm0399, pwr_h7rm0433))]
const VCO_WIDE_RANGE: RangeInclusive<Hertz> = Hertz(192_000_000)..=Hertz(960_000_000);
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; const VCO_RANGE: RangeInclusive<u32> = 150_000_000..=420_000_000;
#[cfg(any(stm32h5, pwr_h7rm0455))]
const VCO_WIDE_RANGE: RangeInclusive<u32> = 128_000_000..=560_000_000;
#[cfg(pwr_h7rm0468)]
const VCO_WIDE_RANGE: RangeInclusive<u32> = 192_000_000..=836_000_000;
#[cfg(any(pwr_h7rm0399, pwr_h7rm0433))]
const VCO_WIDE_RANGE: RangeInclusive<u32> = 192_000_000..=960_000_000;
pub use super::bus::{AHBPrescaler, APBPrescaler};
#[derive(Clone, Copy, Eq, PartialEq)] #[derive(Clone, Copy, Eq, PartialEq)]
pub enum VoltageScale { pub enum VoltageScale {
@ -43,9 +46,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,
} }
@ -58,15 +61,6 @@ 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
@ -104,19 +98,19 @@ pub struct Pll {
#[cfg(stm32h5)] #[cfg(stm32h5)]
pub source: PllSource, pub source: PllSource,
/// PLL pre-divider (DIVM). /// PLL pre-divider (DIVM). Must be between 1 and 63.
pub prediv: PllPreDiv, pub prediv: u8,
/// PLL multiplication factor. /// PLL multiplication factor. Must be between 4 and 512.
pub mul: PllMul, pub mul: u16,
/// PLL P division factor. If None, PLL P output is disabled. /// PLL P division factor. If None, PLL P output is disabled. Must be between 1 and 128.
/// On PLL1, it must be even (in particular, it cannot be 1.) /// On PLL1, it must be even (in particular, it cannot be 1.)
pub divp: Option<PllDiv>, pub divp: Option<u16>,
/// PLL Q division factor. If None, PLL Q output is disabled. /// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128.
pub divq: Option<PllDiv>, pub divq: Option<u16>,
/// PLL R division factor. If None, PLL R output is disabled. /// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128.
pub divr: Option<PllDiv>, pub divr: Option<u16>,
} }
fn apb_div_tim(apb: &APBPrescaler, clk: Hertz, tim: TimerPrescaler) -> Hertz { fn apb_div_tim(apb: &APBPrescaler, clk: Hertz, tim: TimerPrescaler) -> Hertz {
@ -163,10 +157,6 @@ 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,
@ -191,7 +181,6 @@ 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 {
@ -199,10 +188,6 @@ 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,
@ -225,7 +210,6 @@ 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(),
} }
} }
} }
@ -464,8 +448,6 @@ pub(crate) unsafe fn init(config: Config) {
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| {
@ -543,8 +525,7 @@ pub(crate) unsafe fn init(config: Config) {
apb4, apb4,
apb1_tim, apb1_tim,
apb2_tim, apb2_tim,
adc, adc: adc,
rtc,
}); });
} }
@ -572,9 +553,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, PllPreDiv::from_bits(0))); RCC.pllckselr().write(|w| w.set_divm(num, 0));
#[cfg(stm32h5)] #[cfg(stm32h5)]
RCC.pllcfgr(num).write(|w| w.set_divm(PllPreDiv::from_bits(0))); RCC.pllcfgr(num).write(|w| w.set_divm(0));
return PllOutput { return PllOutput {
p: None, p: None,
@ -583,6 +564,9 @@ 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)]
@ -609,25 +593,31 @@ 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) { let vco_range = if VCO_RANGE.contains(&vco_clk.0) {
Pllvcosel::MEDIUMVCO Pllvcosel::MEDIUMVCO
} else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk) { } else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk.0) {
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.
// The enum value is 1 less than the divider, so check it's odd. assert!(div % 2 == 0);
assert!(div.to_bits() % 2 == 1);
} }
vco_clk / div vco_clk / div
}); });
let q = config.divq.map(|div| vco_clk / div); let q = config.divq.map(|div| {
let r = config.divr.map(|div| vco_clk / div); assert!(1 <= div && div <= 128);
vco_clk / div
});
let r = config.divr.map(|div| {
assert!(1 <= div && div <= 128);
vco_clk / div
});
#[cfg(stm32h5)] #[cfg(stm32h5)]
RCC.pllcfgr(num).write(|w| { RCC.pllcfgr(num).write(|w| {
@ -658,10 +648,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); w.set_plln(config.mul - 1);
w.set_pllp(config.divp.unwrap_or(PllDiv::DIV2)); w.set_pllp((config.divp.unwrap_or(1) - 1) as u8);
w.set_pllq(config.divq.unwrap_or(PllDiv::DIV2)); w.set_pllq((config.divq.unwrap_or(1) - 1) as u8);
w.set_pllr(config.divr.unwrap_or(PllDiv::DIV2)); w.set_pllr((config.divr.unwrap_or(1) - 1) as u8);
}); });
RCC.cr().modify(|w| w.set_pllon(num, true)); RCC.cr().modify(|w| w.set_pllon(num, true));

349
embassy-stm32/src/rcc/l0.rs Normal file
View File

@ -0,0 +1,349 @@
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

@ -1,219 +0,0 @@
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,
});
}

279
embassy-stm32/src/rcc/l1.rs Normal file
View File

@ -0,0 +1,279 @@
pub use super::bus::{AHBPrescaler, APBPrescaler};
use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
use crate::pac::{FLASH, RCC};
use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz;
/// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// LSI speed
pub const LSI_FREQ: Hertz = Hertz(32_000);
/// System clock mux source
#[derive(Clone, Copy)]
pub enum ClockSrc {
MSI(MSIRange),
PLL(PLLSource, PLLMul, PLLDiv),
HSE(Hertz),
HSI,
}
/// 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 {
HSI,
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::HSI => Pllsrc::HSI,
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,
}
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,
}
}
}
pub(crate) unsafe fn init(config: Config) {
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::HSI => {
// Enable HSI
RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
(HSI_FREQ.0, Sw::HSI)
}
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::HSI => {
// Enable HSI
RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
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)
}
};
// Set flash 64-bit access, prefetch and wait states
if sys_clk >= 16_000_000 {
FLASH.acr().write(|w| w.set_acc64(true));
FLASH.acr().modify(|w| w.set_prften(true));
FLASH.acr().modify(|w| w.set_latency(true));
}
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)
}
};
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

@ -1,25 +1,85 @@
use crate::pac::rcc::regs::Cfgr; use core::marker::PhantomData;
pub use crate::pac::rcc::vals::{
Hpre as AHBPrescaler, Msirange as MSIRange, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, use embassy_hal_internal::into_ref;
Pllr as PllRDiv, Ppre as APBPrescaler, use stm32_metapac::rcc::regs::Cfgr;
}; use stm32_metapac::rcc::vals::{Mcopre, Mcosel};
use crate::pac::rcc::vals::{Msirange, Pllsrc, Sw};
pub use super::bus::{AHBPrescaler, APBPrescaler};
use crate::gpio::sealed::AFType;
use crate::gpio::Speed;
use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw};
use crate::pac::{FLASH, RCC}; use crate::pac::{FLASH, 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);
/// System clock mux source /// System clock mux source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum ClockSrc { pub enum ClockSrc {
MSI(MSIRange), MSI(MSIRange),
PLL(PLLSource, PllRDiv, PllPreDiv, PllMul, Option<PllQDiv>), PLL(PLLSource, PLLClkDiv, PLLSrcDiv, PLLMul, Option<PLL48Div>),
HSE(Hertz), HSE(Hertz),
HSI16, 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 100 kHz
Range0,
/// Around 200 kHz
Range1,
/// Around 400 kHz
Range2,
/// Around 800 kHz
Range3,
/// Around 1 MHz
Range4,
/// Around 2 MHz
Range5,
/// Around 4 MHz (reset value)
Range6,
/// Around 8 MHz
Range7,
/// Around 16 MHz
Range8,
/// Around 24 MHz
Range9,
/// Around 32 MHz
Range10,
/// Around 48 MHz
Range11,
}
impl Default for MSIRange {
fn default() -> MSIRange {
MSIRange::Range6
}
}
pub type PLL48Div = PLLClkDiv;
pub type PLLSAI1RDiv = PLLClkDiv;
pub type PLLSAI1QDiv = PLLClkDiv;
pub type PLLSAI1PDiv = PLLClkDiv;
/// PLL divider
#[derive(Clone, Copy)]
pub enum PLLDiv {
Div2,
Div3,
Div4,
}
/// PLL clock input source /// PLL clock input source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum PLLSource { pub enum PLLSource {
@ -28,6 +88,95 @@ pub enum PLLSource {
MSI(MSIRange), MSI(MSIRange),
} }
seq_macro::seq!(N in 8..=86 {
#[derive(Clone, Copy)]
pub enum PLLMul {
#(
Mul~N,
)*
}
impl From<PLLMul> for u8 {
fn from(val: PLLMul) -> u8 {
match val {
#(
PLLMul::Mul~N => N,
)*
}
}
}
impl PLLMul {
pub fn to_mul(self) -> u32 {
match self {
#(
PLLMul::Mul~N => N,
)*
}
}
}
});
#[derive(Clone, Copy)]
pub enum PLLClkDiv {
Div2,
Div4,
Div6,
Div8,
}
impl PLLClkDiv {
pub fn to_div(self) -> u32 {
let val: u8 = self.into();
(val as u32 + 1) * 2
}
}
impl From<PLLClkDiv> for u8 {
fn from(val: PLLClkDiv) -> u8 {
match val {
PLLClkDiv::Div2 => 0b00,
PLLClkDiv::Div4 => 0b01,
PLLClkDiv::Div6 => 0b10,
PLLClkDiv::Div8 => 0b11,
}
}
}
#[derive(Clone, Copy)]
pub enum PLLSrcDiv {
Div1,
Div2,
Div3,
Div4,
Div5,
Div6,
Div7,
Div8,
}
impl PLLSrcDiv {
pub fn to_div(self) -> u32 {
let val: u8 = self.into();
val as u32 + 1
}
}
impl From<PLLSrcDiv> for u8 {
fn from(val: PLLSrcDiv) -> u8 {
match val {
PLLSrcDiv::Div1 => 0b000,
PLLSrcDiv::Div2 => 0b001,
PLLSrcDiv::Div3 => 0b010,
PLLSrcDiv::Div4 => 0b011,
PLLSrcDiv::Div5 => 0b100,
PLLSrcDiv::Div6 => 0b101,
PLLSrcDiv::Div7 => 0b110,
PLLSrcDiv::Div8 => 0b111,
}
}
}
impl From<PLLSource> for Pllsrc { impl From<PLLSource> for Pllsrc {
fn from(val: PLLSource) -> Pllsrc { fn from(val: PLLSource) -> Pllsrc {
match val { match val {
@ -38,41 +187,214 @@ impl From<PLLSource> for Pllsrc {
} }
} }
impl From<MSIRange> for Msirange {
fn from(val: MSIRange) -> Msirange {
match val {
MSIRange::Range0 => Msirange::RANGE100K,
MSIRange::Range1 => Msirange::RANGE200K,
MSIRange::Range2 => Msirange::RANGE400K,
MSIRange::Range3 => Msirange::RANGE800K,
MSIRange::Range4 => Msirange::RANGE1M,
MSIRange::Range5 => Msirange::RANGE2M,
MSIRange::Range6 => Msirange::RANGE4M,
MSIRange::Range7 => Msirange::RANGE8M,
MSIRange::Range8 => Msirange::RANGE16M,
MSIRange::Range9 => Msirange::RANGE24M,
MSIRange::Range10 => Msirange::RANGE32M,
MSIRange::Range11 => Msirange::RANGE48M,
}
}
}
impl From<MSIRange> for u32 {
fn from(val: MSIRange) -> u32 {
match val {
MSIRange::Range0 => 100_000,
MSIRange::Range1 => 200_000,
MSIRange::Range2 => 400_000,
MSIRange::Range3 => 800_000,
MSIRange::Range4 => 1_000_000,
MSIRange::Range5 => 2_000_000,
MSIRange::Range6 => 4_000_000,
MSIRange::Range7 => 8_000_000,
MSIRange::Range8 => 16_000_000,
MSIRange::Range9 => 24_000_000,
MSIRange::Range10 => 32_000_000,
MSIRange::Range11 => 48_000_000,
}
}
}
/// 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 apb1_pre: APBPrescaler, pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler, pub apb2_pre: APBPrescaler,
pub pllsai1: Option<(PllMul, PllPreDiv, Option<PllRDiv>, Option<PllQDiv>, Option<PllPDiv>)>, pub pllsai1: Option<(
PLLMul,
PLLSrcDiv,
Option<PLLSAI1RDiv>,
Option<PLLSAI1QDiv>,
Option<PLLSAI1PDiv>,
)>,
#[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
pub hsi48: bool, pub hsi48: bool,
pub ls: super::LsConfig, pub rtc_mux: RtcClockSource,
pub lse: Option<Hertz>,
pub lsi: bool,
} }
impl Default for Config { impl Default for Config {
#[inline] #[inline]
fn default() -> Config { fn default() -> Config {
Config { Config {
mux: ClockSrc::MSI(MSIRange::RANGE4M), mux: ClockSrc::MSI(MSIRange::Range6),
ahb_pre: AHBPrescaler::DIV1, ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1,
pllsai1: None, pllsai1: None,
#[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
hsi48: false, hsi48: false,
ls: Default::default(), rtc_mux: RtcClockSource::LSI,
lsi: true,
lse: None,
} }
} }
} }
pub enum McoClock {
DIV1,
DIV2,
DIV4,
DIV8,
DIV16,
}
impl McoClock {
fn into_raw(&self) -> Mcopre {
match self {
McoClock::DIV1 => Mcopre::DIV1,
McoClock::DIV2 => Mcopre::DIV2,
McoClock::DIV4 => Mcopre::DIV4,
McoClock::DIV8 => Mcopre::DIV8,
McoClock::DIV16 => Mcopre::DIV16,
}
}
}
#[derive(Copy, Clone)]
pub enum Mco1Source {
Disabled,
Lse,
Lsi,
Hse,
Hsi16,
PllClk,
SysClk,
Msi,
#[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
Hsi48,
}
impl Default for Mco1Source {
fn default() -> Self {
Self::Hsi16
}
}
pub trait McoSource {
type Raw;
fn into_raw(&self) -> Self::Raw;
}
impl McoSource for Mco1Source {
type Raw = Mcosel;
fn into_raw(&self) -> Self::Raw {
match self {
Mco1Source::Disabled => Mcosel::NOCLOCK,
Mco1Source::Lse => Mcosel::LSE,
Mco1Source::Lsi => Mcosel::LSI,
Mco1Source::Hse => Mcosel::HSE,
Mco1Source::Hsi16 => Mcosel::HSI16,
Mco1Source::PllClk => Mcosel::PLL,
Mco1Source::SysClk => Mcosel::SYSCLK,
Mco1Source::Msi => Mcosel::MSI,
#[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
Mco1Source::Hsi48 => Mcosel::HSI48,
}
}
}
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::MCO {
type Source = Mcosel;
unsafe fn apply_clock_settings(source: Self::Source, prescaler: Mcopre) {
RCC.cfgr().modify(|w| {
w.set_mcosel(source);
w.set_mcopre(prescaler);
});
match source {
Mcosel::HSI16 => {
RCC.cr().modify(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
}
#[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
Mcosel::HSI48 => {
RCC.crrcr().modify(|w| w.set_hsi48on(true));
while !RCC.crrcr().read().hsi48rdy() {}
}
_ => {}
}
}
}
impl McoInstance for peripherals::MCO {}
pub struct Mco<'d, T: McoInstance> {
phantom: PhantomData<&'d mut T>,
}
impl<'d, T: McoInstance> Mco<'d, T> {
pub fn new(
_peri: impl Peripheral<P = T> + 'd,
pin: impl Peripheral<P = impl McoPin<T>> + 'd,
source: impl McoSource<Raw = T::Source>,
prescaler: McoClock,
) -> Self {
into_ref!(pin);
critical_section::with(|_| unsafe {
T::apply_clock_settings(source.into_raw(), prescaler.into_raw());
pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
pin.set_speed(Speed::VeryHigh);
});
Self { phantom: PhantomData }
}
}
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
// Switch to MSI to prevent problems with PLL configuration. // Switch to MSI to prevent problems with PLL configuration.
if !RCC.cr().read().msion() { if !RCC.cr().read().msion() {
// Turn on MSI and configure it to 4MHz. // Turn on MSI and configure it to 4MHz.
RCC.cr().modify(|w| { RCC.cr().modify(|w| {
w.set_msirgsel(true); // MSI Range is provided by MSIRANGE[3:0]. w.set_msirgsel(true); // MSI Range is provided by MSIRANGE[3:0].
w.set_msirange(MSIRange::RANGE4M); w.set_msirange(MSIRange::default().into());
w.set_msipllen(false); w.set_msipllen(false);
w.set_msion(true) w.set_msion(true)
}); });
@ -87,68 +409,73 @@ pub(crate) unsafe fn init(config: Config) {
while RCC.cfgr().read().sws() != Sw::MSI {} while RCC.cfgr().read().sws() != Sw::MSI {}
} }
let rtc = config.ls.init(); BackupDomain::configure_ls(config.rtc_mux, config.lsi, config.lse.map(|_| Default::default()));
let (sys_clk, sw) = match config.mux { let (sys_clk, sw) = match config.mux {
ClockSrc::MSI(range) => { ClockSrc::MSI(range) => {
// Enable MSI // Enable MSI
RCC.cr().write(|w| { RCC.cr().write(|w| {
w.set_msirange(range); let bits: Msirange = range.into();
w.set_msirange(bits);
w.set_msirgsel(true); w.set_msirgsel(true);
w.set_msion(true); w.set_msion(true);
// If LSE is enabled, enable calibration of MSI if let RtcClockSource::LSE = config.rtc_mux {
w.set_msipllen(config.ls.lse.is_some()); // If LSE is enabled, enable calibration of MSI
w.set_msipllen(true);
} else {
w.set_msipllen(false);
}
}); });
while !RCC.cr().read().msirdy() {} while !RCC.cr().read().msirdy() {}
// Enable as clock source for USB, RNG if running at 48 MHz // Enable as clock source for USB, RNG if running at 48 MHz
if range == MSIRange::RANGE48M { if let MSIRange::Range11 = range {
RCC.ccipr().modify(|w| { RCC.ccipr().modify(|w| {
w.set_clk48sel(0b11); w.set_clk48sel(0b11);
}); });
} }
(msirange_to_hertz(range), Sw::MSI) (range.into(), Sw::MSI)
} }
ClockSrc::HSI16 => { ClockSrc::HSI16 => {
// Enable HSI16 // Enable HSI16
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, Sw::HSI16) (HSI_FREQ.0, 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, Sw::HSE) (freq.0, Sw::HSE)
} }
ClockSrc::PLL(src, divr, prediv, mul, divq) => { ClockSrc::PLL(src, div, prediv, mul, pll48div) => {
let src_freq = match src { let src_freq = match src {
PLLSource::HSE(freq) => { PLLSource::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 freq.0
} }
PLLSource::HSI16 => { PLLSource::HSI16 => {
// Enable HSI // Enable HSI
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 HSI_FREQ.0
} }
PLLSource::MSI(range) => { PLLSource::MSI(range) => {
// Enable MSI // Enable MSI
RCC.cr().write(|w| { RCC.cr().write(|w| {
w.set_msirange(range); let bits: Msirange = range.into();
w.set_msirange(bits);
w.set_msipllen(false); // should be turned on if LSE is started w.set_msipllen(false); // should be turned on if LSE is started
w.set_msirgsel(true); w.set_msirgsel(true);
w.set_msion(true); w.set_msion(true);
}); });
while !RCC.cr().read().msirdy() {} while !RCC.cr().read().msirdy() {}
range.into()
msirange_to_hertz(range)
} }
}; };
@ -156,28 +483,28 @@ 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 freq = src_freq / prediv * mul / divr; let freq = (src_freq / prediv.to_div() * mul.to_mul()) / div.to_div();
#[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx))] #[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx))]
assert!(freq.0 <= 120_000_000); assert!(freq <= 120_000_000);
#[cfg(not(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx)))] #[cfg(not(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx)))]
assert!(freq.0 <= 80_000_000); assert!(freq <= 80_000_000);
RCC.pllcfgr().write(move |w| { RCC.pllcfgr().write(move |w| {
w.set_plln(mul); w.set_plln(mul.into());
w.set_pllm(prediv); w.set_pllm(prediv.into());
w.set_pllr(divr); w.set_pllr(div.into());
if let Some(divq) = divq { if let Some(pll48div) = pll48div {
w.set_pllq(divq); w.set_pllq(pll48div.into());
w.set_pllqen(true); w.set_pllqen(true);
} }
w.set_pllsrc(src.into()); w.set_pllsrc(src.into());
}); });
// Enable as clock source for USB, RNG if PLL48 divisor is provided // Enable as clock source for USB, RNG if PLL48 divisor is provided
if let Some(divq) = divq { if let Some(pll48div) = pll48div {
let freq = src_freq / prediv * mul / divq; let freq = (src_freq / prediv.to_div() * mul.to_mul()) / pll48div.to_div();
assert!(freq.0 == 48_000_000); assert!(freq == 48_000_000);
RCC.ccipr().modify(|w| { RCC.ccipr().modify(|w| {
w.set_clk48sel(0b10); w.set_clk48sel(0b10);
}); });
@ -185,25 +512,25 @@ pub(crate) unsafe fn init(config: Config) {
if let Some((mul, prediv, r_div, q_div, p_div)) = config.pllsai1 { if let Some((mul, prediv, r_div, q_div, p_div)) = config.pllsai1 {
RCC.pllsai1cfgr().write(move |w| { RCC.pllsai1cfgr().write(move |w| {
w.set_plln(mul); w.set_pllsai1n(mul.into());
w.set_pllm(prediv); w.set_pllsai1m(prediv.into());
if let Some(r_div) = r_div { if let Some(r_div) = r_div {
w.set_pllr(r_div); w.set_pllsai1r(r_div.into());
w.set_pllren(true); w.set_pllsai1ren(true);
} }
if let Some(q_div) = q_div { if let Some(q_div) = q_div {
w.set_pllq(q_div); w.set_pllsai1q(q_div.into());
w.set_pllqen(true); w.set_pllsai1qen(true);
let freq = src_freq / prediv * mul / q_div; let freq = (src_freq / prediv.to_div() * mul.to_mul()) / q_div.to_div();
if freq.0 == 48_000_000 { if freq == 48_000_000 {
RCC.ccipr().modify(|w| { RCC.ccipr().modify(|w| {
w.set_clk48sel(0b1); w.set_clk48sel(0b1);
}); });
} }
} }
if let Some(p_div) = p_div { if let Some(p_div) = p_div {
w.set_pllp(p_div); w.set_pllsai1pdiv(p_div.into());
w.set_pllpen(true); w.set_pllsai1pen(true);
} }
}); });
@ -230,67 +557,63 @@ pub(crate) unsafe fn init(config: Config) {
// Set flash wait states // Set flash wait states
FLASH.acr().modify(|w| { FLASH.acr().modify(|w| {
w.set_latency(match sys_clk.0 { w.set_latency(if sys_clk <= 16_000_000 {
0..=16_000_000 => 0, 0b000
0..=32_000_000 => 1, } else if sys_clk <= 32_000_000 {
0..=48_000_000 => 2, 0b001
0..=64_000_000 => 3, } else if sys_clk <= 48_000_000 {
_ => 4, 0b010
}) } else if sys_clk <= 64_000_000 {
0b011
} else {
0b100
});
}); });
RCC.cfgr().modify(|w| { RCC.cfgr().modify(|w| {
w.set_sw(sw); w.set_sw(sw);
w.set_hpre(config.ahb_pre); w.set_hpre(config.ahb_pre.into());
w.set_ppre1(config.apb1_pre); w.set_ppre1(config.apb1_pre.into());
w.set_ppre2(config.apb2_pre); w.set_ppre2(config.apb2_pre.into());
}); });
let ahb_freq = sys_clk / config.ahb_pre; 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 { 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 / pre; let pre: Ppre = pre.into();
(freq, freq * 2u32) 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 { 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 / pre; let pre: Ppre = pre.into();
(freq, freq * 2u32) let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
} }
}; };
set_freqs(Clocks { set_freqs(Clocks {
sys: sys_clk, sys: Hertz(sys_clk),
ahb1: ahb_freq, ahb1: Hertz(ahb_freq),
ahb2: ahb_freq, ahb2: Hertz(ahb_freq),
ahb3: ahb_freq, ahb3: Hertz(ahb_freq),
apb1: apb1_freq, apb1: Hertz(apb1_freq),
apb2: apb2_freq, apb2: Hertz(apb2_freq),
apb1_tim: apb1_tim_freq, apb1_tim: Hertz(apb1_tim_freq),
apb2_tim: apb2_tim_freq, apb2_tim: Hertz(apb2_tim_freq),
rtc,
}); });
} }
fn msirange_to_hertz(range: Msirange) -> Hertz {
match range {
MSIRange::RANGE100K => Hertz(100_000),
MSIRange::RANGE200K => Hertz(200_000),
MSIRange::RANGE400K => Hertz(400_000),
MSIRange::RANGE800K => Hertz(800_000),
MSIRange::RANGE1M => Hertz(1_000_000),
MSIRange::RANGE2M => Hertz(2_000_000),
MSIRange::RANGE4M => Hertz(4_000_000),
MSIRange::RANGE8M => Hertz(8_000_000),
MSIRange::RANGE16M => Hertz(16_000_000),
MSIRange::RANGE24M => Hertz(24_000_000),
MSIRange::RANGE32M => Hertz(32_000_000),
MSIRange::RANGE48M => Hertz(48_000_000),
_ => unreachable!(),
}
}

View File

@ -1,25 +1,77 @@
use crate::pac::rcc::regs::Cfgr; use stm32_metapac::PWR;
pub use crate::pac::rcc::vals::{
Hpre as AHBPrescaler, Msirange as MSIRange, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, pub use super::bus::{AHBPrescaler, APBPrescaler};
Pllr as PllRDiv, Ppre as APBPrescaler, use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw};
}; use crate::pac::{FLASH, RCC};
use crate::pac::rcc::vals::{Msirange, Pllsrc, Sw};
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;
/// 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 {
MSI(MSIRange), MSI(MSIRange),
PLL(PLLSource, PllRDiv, PllPreDiv, PllMul, Option<PllQDiv>), PLL(PLLSource, PLLClkDiv, PLLSrcDiv, PLLMul, Option<PLL48Div>),
HSE(Hertz), HSE(Hertz),
HSI16, 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 100 kHz
Range0,
/// Around 200 kHz
Range1,
/// Around 400 kHz
Range2,
/// Around 800 kHz
Range3,
/// Around 1 MHz
Range4,
/// Around 2 MHz
Range5,
/// Around 4 MHz (reset value)
Range6,
/// Around 8 MHz
Range7,
/// Around 16 MHz
Range8,
/// Around 24 MHz
Range9,
/// Around 32 MHz
Range10,
/// Around 48 MHz
Range11,
}
impl Default for MSIRange {
fn default() -> MSIRange {
MSIRange::Range6
}
}
pub type PLL48Div = PLLClkDiv;
pub type PLLSAI1RDiv = PLLClkDiv;
pub type PLLSAI1QDiv = PLLClkDiv;
pub type PLLSAI1PDiv = PLLClkDiv;
/// PLL divider
#[derive(Clone, Copy)]
pub enum PLLDiv {
Div2,
Div3,
Div4,
}
/// PLL clock input source /// PLL clock input source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum PLLSource { pub enum PLLSource {
@ -28,6 +80,95 @@ pub enum PLLSource {
MSI(MSIRange), MSI(MSIRange),
} }
seq_macro::seq!(N in 8..=86 {
#[derive(Clone, Copy)]
pub enum PLLMul {
#(
Mul~N,
)*
}
impl From<PLLMul> for u8 {
fn from(val: PLLMul) -> u8 {
match val {
#(
PLLMul::Mul~N => N,
)*
}
}
}
impl PLLMul {
pub fn to_mul(self) -> u32 {
match self {
#(
PLLMul::Mul~N => N,
)*
}
}
}
});
#[derive(Clone, Copy)]
pub enum PLLClkDiv {
Div2,
Div4,
Div6,
Div8,
}
impl PLLClkDiv {
pub fn to_div(self) -> u32 {
let val: u8 = self.into();
(val as u32 + 1) * 2
}
}
impl From<PLLClkDiv> for u8 {
fn from(val: PLLClkDiv) -> u8 {
match val {
PLLClkDiv::Div2 => 0b00,
PLLClkDiv::Div4 => 0b01,
PLLClkDiv::Div6 => 0b10,
PLLClkDiv::Div8 => 0b11,
}
}
}
#[derive(Clone, Copy)]
pub enum PLLSrcDiv {
Div1,
Div2,
Div3,
Div4,
Div5,
Div6,
Div7,
Div8,
}
impl PLLSrcDiv {
pub fn to_div(self) -> u32 {
let val: u8 = self.into();
val as u32 + 1
}
}
impl From<PLLSrcDiv> for u8 {
fn from(val: PLLSrcDiv) -> u8 {
match val {
PLLSrcDiv::Div1 => 0b000,
PLLSrcDiv::Div2 => 0b001,
PLLSrcDiv::Div3 => 0b010,
PLLSrcDiv::Div4 => 0b011,
PLLSrcDiv::Div5 => 0b100,
PLLSrcDiv::Div6 => 0b101,
PLLSrcDiv::Div7 => 0b110,
PLLSrcDiv::Div8 => 0b111,
}
}
}
impl From<PLLSource> for Pllsrc { impl From<PLLSource> for Pllsrc {
fn from(val: PLLSource) -> Pllsrc { fn from(val: PLLSource) -> Pllsrc {
match val { match val {
@ -38,116 +179,135 @@ impl From<PLLSource> for Pllsrc {
} }
} }
impl From<MSIRange> for Msirange {
fn from(val: MSIRange) -> Msirange {
match val {
MSIRange::Range0 => Msirange::RANGE100K,
MSIRange::Range1 => Msirange::RANGE200K,
MSIRange::Range2 => Msirange::RANGE400K,
MSIRange::Range3 => Msirange::RANGE800K,
MSIRange::Range4 => Msirange::RANGE1M,
MSIRange::Range5 => Msirange::RANGE2M,
MSIRange::Range6 => Msirange::RANGE4M,
MSIRange::Range7 => Msirange::RANGE8M,
MSIRange::Range8 => Msirange::RANGE16M,
MSIRange::Range9 => Msirange::RANGE24M,
MSIRange::Range10 => Msirange::RANGE32M,
MSIRange::Range11 => Msirange::RANGE48M,
}
}
}
impl From<MSIRange> for u32 {
fn from(val: MSIRange) -> u32 {
match val {
MSIRange::Range0 => 100_000,
MSIRange::Range1 => 200_000,
MSIRange::Range2 => 400_000,
MSIRange::Range3 => 800_000,
MSIRange::Range4 => 1_000_000,
MSIRange::Range5 => 2_000_000,
MSIRange::Range6 => 4_000_000,
MSIRange::Range7 => 8_000_000,
MSIRange::Range8 => 16_000_000,
MSIRange::Range9 => 24_000_000,
MSIRange::Range10 => 32_000_000,
MSIRange::Range11 => 48_000_000,
}
}
}
/// 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 apb1_pre: APBPrescaler, pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler, pub apb2_pre: APBPrescaler,
pub pllsai1: Option<(PllMul, PllPreDiv, Option<PllRDiv>, Option<PllQDiv>, Option<PllPDiv>)>, pub pllsai1: Option<(
PLLMul,
PLLSrcDiv,
Option<PLLSAI1RDiv>,
Option<PLLSAI1QDiv>,
Option<PLLSAI1PDiv>,
)>,
pub hsi48: bool, pub hsi48: 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::MSI(MSIRange::RANGE4M), mux: ClockSrc::MSI(MSIRange::Range6),
ahb_pre: AHBPrescaler::DIV1, ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1,
pllsai1: None, pllsai1: None,
hsi48: false, hsi48: false,
ls: Default::default(),
} }
} }
} }
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
// Switch to MSI to prevent problems with PLL configuration.
if !RCC.cr().read().msion() {
// Turn on MSI and configure it to 4MHz.
RCC.cr().modify(|w| {
w.set_msirgsel(true); // MSI Range is provided by MSIRANGE[3:0].
w.set_msirange(MSIRange::RANGE4M);
w.set_msipllen(false);
w.set_msion(true)
});
// Wait until MSI is running
while !RCC.cr().read().msirdy() {}
}
if RCC.cfgr().read().sws() != Sw::MSI {
// Set MSI as a clock source, reset prescalers.
RCC.cfgr().write_value(Cfgr::default());
// Wait for clock switch status bits to change.
while RCC.cfgr().read().sws() != Sw::MSI {}
}
let rtc = config.ls.init();
PWR.cr1().modify(|w| w.set_vos(stm32_metapac::pwr::vals::Vos::RANGE0)); PWR.cr1().modify(|w| w.set_vos(stm32_metapac::pwr::vals::Vos::RANGE0));
let (sys_clk, sw) = match config.mux { let (sys_clk, sw) = match config.mux {
ClockSrc::MSI(range) => { ClockSrc::MSI(range) => {
// Enable MSI // Enable MSI
RCC.cr().write(|w| { RCC.cr().write(|w| {
w.set_msirange(range); let bits: Msirange = range.into();
w.set_msirange(bits);
w.set_msipllen(false);
w.set_msirgsel(true); w.set_msirgsel(true);
w.set_msion(true); w.set_msion(true);
// If LSE is enabled, enable calibration of MSI
w.set_msipllen(config.ls.lse.is_some());
}); });
while !RCC.cr().read().msirdy() {} while !RCC.cr().read().msirdy() {}
// Enable as clock source for USB, RNG if running at 48 MHz // Enable as clock source for USB, RNG if running at 48 MHz
if range == MSIRange::RANGE48M { if let MSIRange::Range11 = range {
RCC.ccipr1().modify(|w| { RCC.ccipr1().modify(|w| {
w.set_clk48msel(0b11); w.set_clk48msel(0b11);
}); });
} }
(msirange_to_hertz(range), Sw::MSI) (range.into(), Sw::MSI)
} }
ClockSrc::HSI16 => { ClockSrc::HSI16 => {
// Enable HSI16 // Enable HSI16
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, Sw::HSI16) (HSI_FREQ.0, 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, Sw::HSE) (freq.0, Sw::HSE)
} }
ClockSrc::PLL(src, divr, prediv, mul, divq) => { ClockSrc::PLL(src, div, prediv, mul, pll48div) => {
let src_freq = match src { let src_freq = match src {
PLLSource::HSE(freq) => { PLLSource::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 freq.0
} }
PLLSource::HSI16 => { PLLSource::HSI16 => {
// Enable HSI // Enable HSI
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 HSI_FREQ.0
} }
PLLSource::MSI(range) => { PLLSource::MSI(range) => {
// Enable MSI // Enable MSI
RCC.cr().write(|w| { RCC.cr().write(|w| {
w.set_msirange(range); let bits: Msirange = range.into();
w.set_msirange(bits);
w.set_msipllen(false); // should be turned on if LSE is started w.set_msipllen(false); // should be turned on if LSE is started
w.set_msirgsel(true); w.set_msirgsel(true);
w.set_msion(true); w.set_msion(true);
}); });
while !RCC.cr().read().msirdy() {} while !RCC.cr().read().msirdy() {}
range.into()
msirange_to_hertz(range)
} }
}; };
@ -155,23 +315,23 @@ 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 freq = src_freq / prediv * mul / divr; let freq = (src_freq / prediv.to_div() * mul.to_mul()) / div.to_div();
RCC.pllcfgr().write(move |w| { RCC.pllcfgr().write(move |w| {
w.set_plln(mul); w.set_plln(mul.into());
w.set_pllm(prediv); w.set_pllm(prediv.into());
w.set_pllr(divr); w.set_pllr(div.into());
if let Some(divq) = divq { if let Some(pll48div) = pll48div {
w.set_pllq(divq); w.set_pllq(pll48div.into());
w.set_pllqen(true); w.set_pllqen(true);
} }
w.set_pllsrc(src.into()); w.set_pllsrc(src.into());
}); });
// Enable as clock source for USB, RNG if PLL48 divisor is provided // Enable as clock source for USB, RNG if PLL48 divisor is provided
if let Some(divq) = divq { if let Some(pll48div) = pll48div {
let freq = src_freq / prediv * mul / divq; let freq = (src_freq / prediv.to_div() * mul.to_mul()) / pll48div.to_div();
assert!(freq.0 == 48_000_000); assert!(freq == 48_000_000);
RCC.ccipr1().modify(|w| { RCC.ccipr1().modify(|w| {
w.set_clk48msel(0b10); w.set_clk48msel(0b10);
}); });
@ -179,25 +339,25 @@ pub(crate) unsafe fn init(config: Config) {
if let Some((mul, prediv, r_div, q_div, p_div)) = config.pllsai1 { if let Some((mul, prediv, r_div, q_div, p_div)) = config.pllsai1 {
RCC.pllsai1cfgr().write(move |w| { RCC.pllsai1cfgr().write(move |w| {
w.set_plln(mul); w.set_pllsai1n(mul.into());
w.set_pllm(prediv); w.set_pllsai1m(prediv.into());
if let Some(r_div) = r_div { if let Some(r_div) = r_div {
w.set_pllr(r_div); w.set_pllsai1r(r_div.into());
w.set_pllren(true); w.set_pllsai1ren(true);
} }
if let Some(q_div) = q_div { if let Some(q_div) = q_div {
w.set_pllq(q_div); w.set_pllsai1q(q_div.into());
w.set_pllqen(true); w.set_pllsai1qen(true);
let freq = src_freq / prediv * mul / q_div; let freq = (src_freq / prediv.to_div() * mul.to_mul()) / q_div.to_div();
if freq.0 == 48_000_000 { if freq == 48_000_000 {
RCC.ccipr1().modify(|w| { RCC.ccipr1().modify(|w| {
w.set_clk48msel(0b1); w.set_clk48msel(0b1);
}); });
} }
} }
if let Some(p_div) = p_div { if let Some(p_div) = p_div {
w.set_pllp(p_div); w.set_pllsai1pdiv(p_div.into());
w.set_pllpen(true); w.set_pllsai1pen(true);
} }
}); });
@ -224,7 +384,7 @@ pub(crate) unsafe fn init(config: Config) {
// Set flash wait states // Set flash wait states
// VCORE Range 0 (performance), others TODO // VCORE Range 0 (performance), others TODO
FLASH.acr().modify(|w| { FLASH.acr().modify(|w| {
w.set_latency(match sys_clk.0 { w.set_latency(match sys_clk {
0..=20_000_000 => 0, 0..=20_000_000 => 0,
0..=40_000_000 => 1, 0..=40_000_000 => 1,
0..=60_000_000 => 2, 0..=60_000_000 => 2,
@ -236,56 +396,48 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cfgr().modify(|w| { RCC.cfgr().modify(|w| {
w.set_sw(sw); w.set_sw(sw);
w.set_hpre(config.ahb_pre); w.set_hpre(config.ahb_pre.into());
w.set_ppre1(config.apb1_pre); w.set_ppre1(config.apb1_pre.into());
w.set_ppre2(config.apb2_pre); w.set_ppre2(config.apb2_pre.into());
}); });
let ahb_freq = sys_clk / config.ahb_pre; 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 { 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 / pre; let pre: Ppre = pre.into();
(freq, freq * 2u32) 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 { 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 / pre; let pre: Ppre = pre.into();
(freq, freq * 2u32) let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
} }
}; };
set_freqs(Clocks { set_freqs(Clocks {
sys: sys_clk, sys: Hertz(sys_clk),
ahb1: ahb_freq, ahb1: Hertz(ahb_freq),
ahb2: ahb_freq, ahb2: Hertz(ahb_freq),
ahb3: ahb_freq, ahb3: Hertz(ahb_freq),
apb1: apb1_freq, apb1: Hertz(apb1_freq),
apb2: apb2_freq, apb2: Hertz(apb2_freq),
apb1_tim: apb1_tim_freq, apb1_tim: Hertz(apb1_tim_freq),
apb2_tim: apb2_tim_freq, apb2_tim: Hertz(apb2_tim_freq),
rtc,
}); });
} }
fn msirange_to_hertz(range: Msirange) -> Hertz {
match range {
MSIRange::RANGE100K => Hertz(100_000),
MSIRange::RANGE200K => Hertz(200_000),
MSIRange::RANGE400K => Hertz(400_000),
MSIRange::RANGE800K => Hertz(800_000),
MSIRange::RANGE1M => Hertz(1_000_000),
MSIRange::RANGE2M => Hertz(2_000_000),
MSIRange::RANGE4M => Hertz(4_000_000),
MSIRange::RANGE8M => Hertz(8_000_000),
MSIRange::RANGE16M => Hertz(16_000_000),
MSIRange::RANGE24M => Hertz(24_000_000),
MSIRange::RANGE32M => Hertz(32_000_000),
MSIRange::RANGE48M => Hertz(48_000_000),
_ => unreachable!(),
}
}

View File

@ -4,19 +4,14 @@ use embassy_hal_internal::into_ref;
use crate::gpio::sealed::AFType; use crate::gpio::sealed::AFType;
use crate::gpio::Speed; use crate::gpio::Speed;
#[cfg(not(stm32f1))] pub use crate::pac::rcc::vals::{Mco1 as Mco1Source, Mco2 as Mco2Source};
pub use crate::pac::rcc::vals::Mcopre as McoPrescaler;
#[cfg(not(any(rcc_f2, rcc_f410, rcc_f4, rcc_f7, rcc_h50, rcc_h5, rcc_h7ab, rcc_h7rm0433, rcc_h7)))]
pub use crate::pac::rcc::vals::Mcosel as McoSource;
#[cfg(any(rcc_f2, rcc_f410, rcc_f4, rcc_f7, rcc_h50, rcc_h5, rcc_h7ab, rcc_h7rm0433, rcc_h7))]
pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source};
use crate::pac::RCC; use crate::pac::RCC;
use crate::{peripherals, Peripheral}; use crate::{peripherals, Peripheral};
pub(crate) mod sealed { pub(crate) mod sealed {
pub trait McoInstance { pub trait McoInstance {
type Source; type Source;
unsafe fn apply_clock_settings(source: Self::Source, #[cfg(not(stm32f1))] prescaler: super::McoPrescaler); unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8);
} }
} }
@ -29,15 +24,9 @@ macro_rules! impl_peri {
impl sealed::McoInstance for peripherals::$peri { impl sealed::McoInstance for peripherals::$peri {
type Source = $source; type Source = $source;
unsafe fn apply_clock_settings(source: Self::Source, #[cfg(not(stm32f1))] prescaler: McoPrescaler) { unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) {
#[cfg(not(any(stm32u5, stm32wba)))] RCC.cfgr().modify(|w| {
let r = RCC.cfgr();
#[cfg(any(stm32u5, stm32wba))]
let r = RCC.cfgr1();
r.modify(|w| {
w.$set_source(source); w.$set_source(source);
#[cfg(not(stm32f1))]
w.$set_prescaler(prescaler); w.$set_prescaler(prescaler);
}); });
} }
@ -47,16 +36,8 @@ macro_rules! impl_peri {
}; };
} }
#[cfg(any(rcc_c0, rcc_g0))] impl_peri!(MCO1, Mco1Source, set_mco1, set_mco1pre);
#[allow(unused_imports)] impl_peri!(MCO2, Mco2Source, set_mco2, set_mco2pre);
use self::{McoSource as Mco1Source, McoSource as Mco2Source};
#[cfg(mco)]
impl_peri!(MCO, McoSource, set_mcosel, set_mcopre);
#[cfg(mco1)]
impl_peri!(MCO1, Mco1Source, set_mco1sel, set_mco1pre);
#[cfg(mco2)]
impl_peri!(MCO2, Mco2Source, set_mco2sel, set_mco2pre);
pub struct Mco<'d, T: McoInstance> { pub struct Mco<'d, T: McoInstance> {
phantom: PhantomData<&'d mut T>, phantom: PhantomData<&'d mut T>,
@ -64,20 +45,23 @@ pub struct Mco<'d, T: McoInstance> {
impl<'d, T: McoInstance> Mco<'d, T> { impl<'d, T: McoInstance> Mco<'d, T> {
/// Create a new MCO instance. /// Create a new MCO instance.
///
/// `prescaler` must be between 1 and 15.
pub fn new( pub fn new(
_peri: impl Peripheral<P = T> + 'd, _peri: impl Peripheral<P = T> + 'd,
pin: impl Peripheral<P = impl McoPin<T>> + 'd, pin: impl Peripheral<P = impl McoPin<T>> + 'd,
source: T::Source, source: T::Source,
#[cfg(not(stm32f1))] prescaler: McoPrescaler, prescaler: u8,
) -> Self { ) -> Self {
into_ref!(pin); into_ref!(pin);
assert!(
1 <= prescaler && prescaler <= 15,
"Mco prescaler must be between 1 and 15. Refer to the reference manual for more information."
);
critical_section::with(|_| unsafe { critical_section::with(|_| unsafe {
T::apply_clock_settings( T::apply_clock_settings(source, prescaler);
source,
#[cfg(not(stm32f1))]
prescaler,
);
pin.set_as_af(pin.af_num(), AFType::OutputPushPull); pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
pin.set_speed(Speed::VeryHigh); pin.set_speed(Speed::VeryHigh);
}); });

View File

@ -2,11 +2,14 @@
use core::mem::MaybeUninit; use core::mem::MaybeUninit;
pub use crate::rcc::bd::RtcClockSource;
use crate::time::Hertz; use crate::time::Hertz;
mod bd; pub(crate) mod bd;
mod bus;
#[cfg(any(stm32h5, stm32h7))]
mod mco; mod mco;
pub use bd::*; #[cfg(any(stm32h5, stm32h7))]
pub use mco::*; pub use mco::*;
#[cfg_attr(rcc_f0, path = "f0.rs")] #[cfg_attr(rcc_f0, path = "f0.rs")]
@ -18,8 +21,9 @@ pub use mco::*;
#[cfg_attr(rcc_c0, path = "c0.rs")] #[cfg_attr(rcc_c0, path = "c0.rs")]
#[cfg_attr(rcc_g0, path = "g0.rs")] #[cfg_attr(rcc_g0, path = "g0.rs")]
#[cfg_attr(rcc_g4, path = "g4.rs")] #[cfg_attr(rcc_g4, path = "g4.rs")]
#[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab), path = "h.rs")] #[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab), path = "h.rs")]
#[cfg_attr(any(rcc_l0, rcc_l0_v2, rcc_l1), path = "l0l1.rs")] #[cfg_attr(rcc_l0, path = "l0.rs")]
#[cfg_attr(rcc_l1, path = "l1.rs")]
#[cfg_attr(rcc_l4, path = "l4.rs")] #[cfg_attr(rcc_l4, path = "l4.rs")]
#[cfg_attr(rcc_l5, path = "l5.rs")] #[cfg_attr(rcc_l5, path = "l5.rs")]
#[cfg_attr(rcc_u5, path = "u5.rs")] #[cfg_attr(rcc_u5, path = "u5.rs")]
@ -53,9 +57,9 @@ pub struct Clocks {
pub apb2: Hertz, pub apb2: Hertz,
#[cfg(not(any(rcc_c0, rcc_g0)))] #[cfg(not(any(rcc_c0, rcc_g0)))]
pub apb2_tim: Hertz, pub apb2_tim: Hertz,
#[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab, rcc_u5))] #[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_u5))]
pub apb3: Hertz, pub apb3: Hertz,
#[cfg(any(rcc_h7, rcc_h7rm0433, rcc_h7ab))] #[cfg(any(rcc_h7, rcc_h7ab))]
pub apb4: Hertz, pub apb4: Hertz,
#[cfg(any(rcc_wba))] #[cfg(any(rcc_wba))]
pub apb7: Hertz, pub apb7: Hertz,
@ -63,44 +67,16 @@ pub struct Clocks {
// AHB // AHB
pub ahb1: Hertz, pub ahb1: Hertz,
#[cfg(any( #[cfg(any(
rcc_l4, rcc_l4, rcc_l5, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_g4, rcc_u5, rcc_wb,
rcc_l5, rcc_wba, rcc_wl5, rcc_wle
rcc_f2,
rcc_f4,
rcc_f410,
rcc_f7,
rcc_h5,
rcc_h50,
rcc_h7,
rcc_h7rm0433,
rcc_h7ab,
rcc_g4,
rcc_u5,
rcc_wb,
rcc_wba,
rcc_wl5,
rcc_wle
))] ))]
pub ahb2: Hertz, pub ahb2: Hertz,
#[cfg(any( #[cfg(any(
rcc_l4, rcc_l4, rcc_l5, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_u5, rcc_wb, rcc_wl5,
rcc_l5,
rcc_f2,
rcc_f4,
rcc_f410,
rcc_f7,
rcc_h5,
rcc_h50,
rcc_h7,
rcc_h7rm0433,
rcc_h7ab,
rcc_u5,
rcc_wb,
rcc_wl5,
rcc_wle rcc_wle
))] ))]
pub ahb3: Hertz, pub ahb3: Hertz,
#[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab, rcc_wba))] #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_wba))]
pub ahb4: Hertz, pub ahb4: Hertz,
#[cfg(any(rcc_f2, rcc_f4, rcc_f410, rcc_f7))] #[cfg(any(rcc_f2, rcc_f4, rcc_f410, rcc_f7))]
@ -112,18 +88,7 @@ pub struct Clocks {
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
pub pllsai: Option<Hertz>, pub pllsai: Option<Hertz>,
#[cfg(any( #[cfg(any(rcc_f1, rcc_f100, rcc_f1cl, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_f3, rcc_g4))]
rcc_f1,
rcc_f100,
rcc_f1cl,
rcc_h5,
rcc_h50,
rcc_h7,
rcc_h7rm0433,
rcc_h7ab,
rcc_f3,
rcc_g4
))]
pub adc: Option<Hertz>, pub adc: Option<Hertz>,
#[cfg(any(rcc_f3, rcc_g4))] #[cfg(any(rcc_f3, rcc_g4))]
@ -132,7 +97,13 @@ pub struct Clocks {
#[cfg(stm32f334)] #[cfg(stm32f334)]
pub hrtim: Option<Hertz>, pub hrtim: Option<Hertz>,
#[cfg(any(rcc_wb, rcc_f4, rcc_f410, rcc_f7))]
/// Set only if the lsi or lse is configured, indicates stop is supported
pub rtc: Option<Hertz>, pub rtc: Option<Hertz>,
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
/// Set if the hse is configured, indicates stop is not supported
pub rtc_hse: Option<Hertz>,
} }
#[cfg(feature = "low-power")] #[cfg(feature = "low-power")]
@ -160,6 +131,14 @@ pub(crate) fn clock_refcount_sub() {
/// The existence of this value indicates that the clock configuration can no longer be changed /// The existence of this value indicates that the clock configuration can no longer be changed
static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit(); static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit();
#[cfg(stm32wb)]
/// RCC initialization function
pub(crate) unsafe fn init(config: Config) {
set_freqs(compute_clocks(&config));
configure_clocks(&config);
}
/// Sets the clock frequencies /// Sets the clock frequencies
/// ///
/// Safety: Sets a mutable global. /// Safety: Sets a mutable global.

View File

@ -1,102 +1,124 @@
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange, Plldiv, Pllm, Plln, Ppre as APBPrescaler}; use stm32_metapac::rcc::vals::{Msirange, Msirgsel, Pllm, Pllsrc, Sw};
use crate::pac::rcc::vals::{Msirgsel, Pllmboost, Pllrge, Pllsrc, Sw};
use crate::pac::{FLASH, PWR, RCC}; pub use super::bus::{AHBPrescaler, APBPrescaler};
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;
/// 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);
pub use crate::pac::pwr::vals::Vos as VoltageScale; pub use crate::pac::pwr::vals::Vos as VoltageScale;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub enum ClockSrc { pub enum ClockSrc {
/// Use an internal medium speed oscillator (MSIS) as the system clock. MSI(MSIRange),
MSI(Msirange),
/// Use the external high speed clock as the system clock.
///
/// HSE clocks faster than 25 MHz require at least `VoltageScale::RANGE3`, and HSE clocks must
/// never exceed 50 MHz.
HSE(Hertz), HSE(Hertz),
/// Use the 16 MHz internal high speed oscillator as the system clock.
HSI16, HSI16,
/// Use PLL1 as the system clock. PLL1R(PllSrc, PllM, PllN, PllClkDiv),
PLL1R(PllConfig),
} }
impl Default for ClockSrc { #[derive(Clone, Copy, Debug)]
fn default() -> Self {
// The default system clock source is MSIS @ 4 MHz, per RM0456 § 11.4.9
ClockSrc::MSI(Msirange::RANGE_4MHZ)
}
}
#[derive(Clone, Copy)]
pub struct PllConfig {
/// The clock source for the PLL.
pub source: PllSrc,
/// The PLL prescaler.
///
/// The clock speed of the `source` divided by `m` must be between 4 and 16 MHz.
pub m: Pllm,
/// The PLL multiplier.
///
/// The multiplied clock `source` divided by `m` times `n` must be between 128 and 544
/// MHz. The upper limit may be lower depending on the `Config { voltage_range }`.
pub n: Plln,
/// The divider for the R output.
///
/// When used to drive the system clock, `source` divided by `m` times `n` divided by `r`
/// must not exceed 160 MHz. System clocks above 55 MHz require a non-default
/// `Config { voltage_range }`.
pub r: Plldiv,
}
impl PllConfig {
/// A configuration for HSI16 / 1 * 10 / 1 = 160 MHz
pub const fn hsi16_160mhz() -> Self {
PllConfig {
source: PllSrc::HSI16,
m: Pllm::DIV1,
n: Plln::MUL10,
r: Plldiv::DIV1,
}
}
/// A configuration for MSIS @ 48 MHz / 3 * 10 / 1 = 160 MHz
pub const fn msis_160mhz() -> Self {
PllConfig {
source: PllSrc::MSIS(Msirange::RANGE_48MHZ),
m: Pllm::DIV3,
n: Plln::MUL10,
r: Plldiv::DIV1,
}
}
}
#[derive(Clone, Copy)]
pub enum PllSrc { pub enum PllSrc {
/// Use an internal medium speed oscillator as the PLL source. MSI(MSIRange),
MSIS(Msirange),
/// Use the external high speed clock as the system PLL source.
///
/// HSE clocks faster than 25 MHz require at least `VoltageScale::RANGE3`, and HSE clocks must
/// never exceed 50 MHz.
HSE(Hertz), HSE(Hertz),
/// Use the 16 MHz internal high speed oscillator as the PLL source.
HSI16, HSI16,
} }
impl Into<Pllsrc> for PllSrc { impl Into<Pllsrc> for PllSrc {
fn into(self) -> Pllsrc { fn into(self) -> Pllsrc {
match self { match self {
PllSrc::MSIS(..) => Pllsrc::MSIS, PllSrc::MSI(..) => Pllsrc::MSIS,
PllSrc::HSE(..) => Pllsrc::HSE, PllSrc::HSE(..) => Pllsrc::HSE,
PllSrc::HSI16 => Pllsrc::HSI16, PllSrc::HSI16 => Pllsrc::HSI16,
} }
} }
} }
seq_macro::seq!(N in 2..=128 {
#[derive(Copy, Clone, Debug)]
pub enum PllClkDiv {
NotDivided,
#(
Div~N = (N-1),
)*
}
impl PllClkDiv {
fn to_div(&self) -> u8 {
match self {
PllClkDiv::NotDivided => 1,
#(
PllClkDiv::Div~N => N + 1,
)*
}
}
}
});
impl Into<u8> for PllClkDiv {
fn into(self) -> u8 {
(self as u8) + 1
}
}
seq_macro::seq!(N in 4..=512 {
#[derive(Copy, Clone, Debug)]
pub enum PllN {
NotMultiplied,
#(
Mul~N = N-1,
)*
}
impl PllN {
fn to_mul(&self) -> u16 {
match self {
PllN::NotMultiplied => 1,
#(
PllN::Mul~N => N + 1,
)*
}
}
}
});
impl Into<u16> for PllN {
fn into(self) -> u16 {
(self as u16) + 1
}
}
// Pre-division
#[derive(Copy, Clone, Debug)]
pub enum PllM {
NotDivided = 0b0000,
Div2 = 0b0001,
Div3 = 0b0010,
Div4 = 0b0011,
Div5 = 0b0100,
Div6 = 0b0101,
Div7 = 0b0110,
Div8 = 0b0111,
Div9 = 0b1000,
Div10 = 0b1001,
Div11 = 0b1010,
Div12 = 0b1011,
Div13 = 0b1100,
Div14 = 0b1101,
Div15 = 0b1110,
Div16 = 0b1111,
}
impl Into<Pllm> for PllM {
fn into(self) -> Pllm {
Pllm::from_bits(self as u8)
}
}
impl Into<Sw> for ClockSrc { impl Into<Sw> for ClockSrc {
fn into(self) -> Sw { fn into(self) -> Sw {
match self { match self {
@ -108,6 +130,62 @@ impl Into<Sw> for ClockSrc {
} }
} }
#[derive(Debug, Copy, Clone)]
pub enum MSIRange {
Range48mhz = 48_000_000,
Range24mhz = 24_000_000,
Range16mhz = 16_000_000,
Range12mhz = 12_000_000,
Range4mhz = 4_000_000,
Range2mhz = 2_000_000,
Range1_33mhz = 1_330_000,
Range1mhz = 1_000_000,
Range3_072mhz = 3_072_000,
Range1_536mhz = 1_536_000,
Range1_024mhz = 1_024_000,
Range768khz = 768_000,
Range400khz = 400_000,
Range200khz = 200_000,
Range133khz = 133_000,
Range100khz = 100_000,
}
impl Into<u32> for MSIRange {
fn into(self) -> u32 {
self as u32
}
}
impl Into<Msirange> for MSIRange {
fn into(self) -> Msirange {
match self {
MSIRange::Range48mhz => Msirange::RANGE_48MHZ,
MSIRange::Range24mhz => Msirange::RANGE_24MHZ,
MSIRange::Range16mhz => Msirange::RANGE_16MHZ,
MSIRange::Range12mhz => Msirange::RANGE_12MHZ,
MSIRange::Range4mhz => Msirange::RANGE_4MHZ,
MSIRange::Range2mhz => Msirange::RANGE_2MHZ,
MSIRange::Range1_33mhz => Msirange::RANGE_1_33MHZ,
MSIRange::Range1mhz => Msirange::RANGE_1MHZ,
MSIRange::Range3_072mhz => Msirange::RANGE_3_072MHZ,
MSIRange::Range1_536mhz => Msirange::RANGE_1_536MHZ,
MSIRange::Range1_024mhz => Msirange::RANGE_1_024MHZ,
MSIRange::Range768khz => Msirange::RANGE_768KHZ,
MSIRange::Range400khz => Msirange::RANGE_400KHZ,
MSIRange::Range200khz => Msirange::RANGE_200KHZ,
MSIRange::Range133khz => Msirange::RANGE_133KHZ,
MSIRange::Range100khz => Msirange::RANGE_100KHZ,
}
}
}
impl Default for MSIRange {
fn default() -> Self {
MSIRange::Range4mhz
}
}
#[derive(Copy, Clone)]
pub struct Config { pub struct Config {
pub mux: ClockSrc, pub mux: ClockSrc,
pub ahb_pre: AHBPrescaler, pub ahb_pre: AHBPrescaler,
@ -115,209 +193,90 @@ pub struct Config {
pub apb2_pre: APBPrescaler, pub apb2_pre: APBPrescaler,
pub apb3_pre: APBPrescaler, pub apb3_pre: APBPrescaler,
pub hsi48: bool, pub hsi48: bool,
/// The voltage range influences the maximum clock frequencies for different parts of the
/// device. In particular, system clocks exceeding 110 MHz require `RANGE1`, and system clocks
/// exceeding 55 MHz require at least `RANGE2`.
///
/// See RM0456 § 10.5.4 for a general overview and § 11.4.10 for clock source frequency limits.
pub voltage_range: VoltageScale,
pub ls: super::LsConfig,
}
impl Config {
unsafe fn init_hsi16(&self) -> Hertz {
RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
HSI_FREQ
}
unsafe fn init_hse(&self, frequency: Hertz) -> Hertz {
// Check frequency limits per RM456 § 11.4.10
match self.voltage_range {
VoltageScale::RANGE1 | VoltageScale::RANGE2 | VoltageScale::RANGE3 => {
assert!(frequency.0 <= 50_000_000);
}
VoltageScale::RANGE4 => {
assert!(frequency.0 <= 25_000_000);
}
}
// Enable HSE, and wait for it to stabilize
RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {}
frequency
}
unsafe fn init_msis(&self, range: Msirange) -> Hertz {
// Check MSI output per RM0456 § 11.4.10
match self.voltage_range {
VoltageScale::RANGE4 => {
assert!(msirange_to_hertz(range).0 <= 24_000_000);
}
_ => {}
}
// RM0456 § 11.8.2: spin until MSIS is off or MSIS is ready before setting its range
loop {
let cr = RCC.cr().read();
if cr.msison() == false || cr.msisrdy() == true {
break;
}
}
RCC.icscr1().modify(|w| {
w.set_msisrange(range);
w.set_msirgsel(Msirgsel::RCC_ICSCR1);
});
RCC.cr().write(|w| {
w.set_msipllen(false);
w.set_msison(true);
});
while !RCC.cr().read().msisrdy() {}
msirange_to_hertz(range)
}
} }
impl Default for Config { impl Default for Config {
fn default() -> Self { fn default() -> Self {
Self { Self {
mux: ClockSrc::default(), mux: ClockSrc::MSI(MSIRange::default()),
ahb_pre: AHBPrescaler::DIV1, ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1,
apb3_pre: APBPrescaler::DIV1, apb3_pre: APBPrescaler::DIV1,
hsi48: false, hsi48: false,
voltage_range: VoltageScale::RANGE3,
ls: Default::default(),
} }
} }
} }
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
// Ensure PWR peripheral clock is enabled
RCC.ahb3enr().modify(|w| {
w.set_pwren(true);
});
RCC.ahb3enr().read(); // synchronize
// Set the requested power mode
PWR.vosr().modify(|w| {
w.set_vos(config.voltage_range);
});
while !PWR.vosr().read().vosrdy() {}
let sys_clk = match config.mux { let sys_clk = match config.mux {
ClockSrc::MSI(range) => config.init_msis(range), ClockSrc::MSI(range) => {
ClockSrc::HSE(freq) => config.init_hse(freq), RCC.icscr1().modify(|w| {
ClockSrc::HSI16 => config.init_hsi16(), let bits: Msirange = range.into();
ClockSrc::PLL1R(pll) => { w.set_msisrange(bits);
// Configure the PLL source w.set_msirgsel(Msirgsel::RCC_ICSCR1);
let source_clk = match pll.source { });
PllSrc::MSIS(range) => config.init_msis(range), RCC.cr().write(|w| {
PllSrc::HSE(hertz) => config.init_hse(hertz), w.set_msipllen(false);
PllSrc::HSI16 => config.init_hsi16(), w.set_msison(true);
});
while !RCC.cr().read().msisrdy() {}
range.into()
}
ClockSrc::HSE(freq) => {
RCC.cr().write(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {}
freq.0
}
ClockSrc::HSI16 => {
RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
HSI_FREQ.0
}
ClockSrc::PLL1R(src, m, n, div) => {
let freq = match src {
PllSrc::MSI(_) => {
// TODO: enable MSI
MSIRange::default().into()
}
PllSrc::HSE(hertz) => {
// TODO: enable HSE
hertz.0
}
PllSrc::HSI16 => {
RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
HSI_FREQ.0
}
}; };
// Calculate the reference clock, which is the source divided by m // disable
let reference_clk = source_clk / pll.m;
// Check limits per RM0456 § 11.4.6
assert!(Hertz::mhz(4) <= reference_clk && reference_clk <= Hertz::mhz(16));
// Calculate the PLL1 VCO clock and PLL1 R output clock
let pll1_clk = reference_clk * pll.n;
let pll1r_clk = pll1_clk / pll.r;
// Check system clock per RM0456 § 11.4.9
assert!(pll1r_clk <= Hertz::mhz(160));
// Check PLL clocks per RM0456 § 11.4.10
match config.voltage_range {
VoltageScale::RANGE1 => {
assert!(pll1_clk >= Hertz::mhz(128) && pll1_clk <= Hertz::mhz(544));
assert!(pll1r_clk <= Hertz::mhz(208));
}
VoltageScale::RANGE2 => {
assert!(pll1_clk >= Hertz::mhz(128) && pll1_clk <= Hertz::mhz(544));
assert!(pll1r_clk <= Hertz::mhz(110));
}
VoltageScale::RANGE3 => {
assert!(pll1_clk >= Hertz::mhz(128) && pll1_clk <= Hertz::mhz(330));
assert!(pll1r_clk <= Hertz::mhz(55));
}
VoltageScale::RANGE4 => {
panic!("PLL is unavailable in voltage range 4");
}
}
// § 10.5.4: if we're targeting >= 55 MHz, we must configure PLL1MBOOST to a prescaler
// value that results in an output between 4 and 16 MHz for the PWR EPOD boost
let mboost = if pll1r_clk >= Hertz::mhz(55) {
// source_clk can be up to 50 MHz, so there's just a few cases:
if source_clk > Hertz::mhz(32) {
// Divide by 4, giving EPOD 8-12.5 MHz
Pllmboost::DIV4
} else if source_clk > Hertz::mhz(16) {
// Divide by 2, giving EPOD 8-16 MHz
Pllmboost::DIV2
} else {
// Bypass, giving EPOD 4-16 MHz
Pllmboost::DIV1
}
} else {
// Nothing to do
Pllmboost::DIV1
};
// Disable the PLL, and wait for it to disable
RCC.cr().modify(|w| w.set_pllon(0, false)); RCC.cr().modify(|w| w.set_pllon(0, false));
while RCC.cr().read().pllrdy(0) {} while RCC.cr().read().pllrdy(0) {}
// Configure the PLL let vco = freq * n as u8 as u32;
let pll_ck = vco / (div as u8 as u32 + 1);
RCC.pll1cfgr().write(|w| { RCC.pll1cfgr().write(|w| {
// Configure PLL1 source and prescaler w.set_pllm(m.into());
w.set_pllsrc(pll.source.into()); w.set_pllsrc(src.into());
w.set_pllm(pll.m);
// Configure PLL1 input frequncy range
let input_range = if reference_clk <= Hertz::mhz(8) {
Pllrge::FREQ_4TO8MHZ
} else {
Pllrge::FREQ_8TO16MHZ
};
w.set_pllrge(input_range);
// Set the prescaler for PWR EPOD
w.set_pllmboost(mboost);
// Enable PLL1R output
w.set_pllren(true); w.set_pllren(true);
}); });
// Configure the PLL divisors
RCC.pll1divr().modify(|w| { RCC.pll1divr().modify(|w| {
// Set the VCO multiplier w.set_pllr(div.to_div());
w.set_plln(pll.n); w.set_plln(n.to_mul());
// Set the R output divisor
w.set_pllr(pll.r);
}); });
// Do we need the EPOD booster to reach the target clock speed per § 10.5.4? // Enable PLL
if pll1r_clk >= Hertz::mhz(55) {
// Enable the booster
PWR.vosr().modify(|w| {
w.set_boosten(true);
});
while !PWR.vosr().read().boostrdy() {}
}
// Enable the PLL
RCC.cr().modify(|w| w.set_pllon(0, true)); RCC.cr().modify(|w| w.set_pllon(0, true));
while !RCC.cr().read().pllrdy(0) {} while !RCC.cr().read().pllrdy(0) {}
pll1r_clk pll_ck
} }
}; };
@ -326,18 +285,20 @@ pub(crate) unsafe fn init(config: Config) {
while !RCC.cr().read().hsi48rdy() {} while !RCC.cr().read().hsi48rdy() {}
} }
// The clock source is ready // TODO make configurable
// Calculate and set the flash wait states let power_vos = VoltageScale::RANGE3;
let wait_states = match config.voltage_range {
// states and programming delay
let wait_states = match power_vos {
// VOS 1 range VCORE 1.26V - 1.40V // VOS 1 range VCORE 1.26V - 1.40V
VoltageScale::RANGE1 => { VoltageScale::RANGE1 => {
if sys_clk.0 < 32_000_000 { if sys_clk < 32_000_000 {
0 0
} else if sys_clk.0 < 64_000_000 { } else if sys_clk < 64_000_000 {
1 1
} else if sys_clk.0 < 96_000_000 { } else if sys_clk < 96_000_000 {
2 2
} else if sys_clk.0 < 128_000_000 { } else if sys_clk < 128_000_000 {
3 3
} else { } else {
4 4
@ -345,11 +306,11 @@ pub(crate) unsafe fn init(config: Config) {
} }
// VOS 2 range VCORE 1.15V - 1.26V // VOS 2 range VCORE 1.15V - 1.26V
VoltageScale::RANGE2 => { VoltageScale::RANGE2 => {
if sys_clk.0 < 30_000_000 { if sys_clk < 30_000_000 {
0 0
} else if sys_clk.0 < 60_000_000 { } else if sys_clk < 60_000_000 {
1 1
} else if sys_clk.0 < 90_000_000 { } else if sys_clk < 90_000_000 {
2 2
} else { } else {
3 3
@ -357,9 +318,9 @@ pub(crate) unsafe fn init(config: Config) {
} }
// VOS 3 range VCORE 1.05V - 1.15V // VOS 3 range VCORE 1.05V - 1.15V
VoltageScale::RANGE3 => { VoltageScale::RANGE3 => {
if sys_clk.0 < 24_000_000 { if sys_clk < 24_000_000 {
0 0
} else if sys_clk.0 < 48_000_000 { } else if sys_clk < 48_000_000 {
1 1
} else { } else {
2 2
@ -367,104 +328,80 @@ pub(crate) unsafe fn init(config: Config) {
} }
// VOS 4 range VCORE 0.95V - 1.05V // VOS 4 range VCORE 0.95V - 1.05V
VoltageScale::RANGE4 => { VoltageScale::RANGE4 => {
if sys_clk.0 < 12_000_000 { if sys_clk < 12_000_000 {
0 0
} else { } else {
1 1
} }
} }
}; };
FLASH.acr().modify(|w| { FLASH.acr().modify(|w| {
w.set_latency(wait_states); w.set_latency(wait_states);
}); });
// Switch the system clock source
RCC.cfgr1().modify(|w| { RCC.cfgr1().modify(|w| {
w.set_sw(config.mux.into()); w.set_sw(config.mux.into());
}); });
// RM0456 § 11.4.9 specifies maximum bus frequencies per voltage range, but the maximum bus
// frequency for each voltage range exactly matches the maximum permitted PLL output frequency.
// Given that:
//
// 1. Any bus frequency can never exceed the system clock frequency;
// 2. We checked the PLL output frequency if we're using it as a system clock;
// 3. The maximum HSE frequencies at each voltage range are lower than the bus limits, and
// we checked the HSE frequency if configured as a system clock; and
// 4. The maximum frequencies from the other clock sources are lower than the lowest bus
// frequency limit
//
// ...then we do not need to perform additional bus-related frequency checks.
// Configure the bus prescalers
RCC.cfgr2().modify(|w| { RCC.cfgr2().modify(|w| {
w.set_hpre(config.ahb_pre); w.set_hpre(config.ahb_pre.into());
w.set_ppre1(config.apb1_pre); w.set_ppre1(config.apb1_pre.into());
w.set_ppre2(config.apb2_pre); w.set_ppre2(config.apb2_pre.into());
});
RCC.cfgr3().modify(|w| {
w.set_ppre3(config.apb3_pre);
}); });
let ahb_freq = sys_clk / config.ahb_pre; RCC.cfgr3().modify(|w| {
w.set_ppre3(config.apb3_pre.into());
});
let ahb_freq: u32 = match config.ahb_pre {
AHBPrescaler::DIV1 => sys_clk,
pre => {
let pre: u8 = pre.into();
let pre = 1 << (pre as u32 - 7);
sys_clk / 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 / pre; let pre: u8 = pre.into();
(freq, freq * 2u32) let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
} }
}; };
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 / pre; let pre: u8 = pre.into();
(freq, freq * 2u32) let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
} }
}; };
let (apb3_freq, _apb3_tim_freq) = match config.apb3_pre { let (apb3_freq, _apb3_tim_freq) = match config.apb3_pre {
APBPrescaler::DIV1 => (ahb_freq, ahb_freq), APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
pre => { pre => {
let freq = ahb_freq / pre; let pre: u8 = pre.into();
(freq, freq * 2u32) let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
} }
}; };
let rtc = config.ls.init();
set_freqs(Clocks { set_freqs(Clocks {
sys: sys_clk, sys: Hertz(sys_clk),
ahb1: ahb_freq, ahb1: Hertz(ahb_freq),
ahb2: ahb_freq, ahb2: Hertz(ahb_freq),
ahb3: ahb_freq, ahb3: Hertz(ahb_freq),
apb1: apb1_freq, apb1: Hertz(apb1_freq),
apb2: apb2_freq, apb2: Hertz(apb2_freq),
apb3: apb3_freq, apb3: Hertz(apb3_freq),
apb1_tim: apb1_tim_freq, apb1_tim: Hertz(apb1_tim_freq),
apb2_tim: apb2_tim_freq, apb2_tim: Hertz(apb2_tim_freq),
rtc,
}); });
} }
fn msirange_to_hertz(range: Msirange) -> Hertz {
match range {
Msirange::RANGE_48MHZ => Hertz(48_000_000),
Msirange::RANGE_24MHZ => Hertz(24_000_000),
Msirange::RANGE_16MHZ => Hertz(16_000_000),
Msirange::RANGE_12MHZ => Hertz(12_000_000),
Msirange::RANGE_4MHZ => Hertz(4_000_000),
Msirange::RANGE_2MHZ => Hertz(2_000_000),
Msirange::RANGE_1_33MHZ => Hertz(1_330_000),
Msirange::RANGE_1MHZ => Hertz(1_000_000),
Msirange::RANGE_3_072MHZ => Hertz(3_072_000),
Msirange::RANGE_1_536MHZ => Hertz(1_536_000),
Msirange::RANGE_1_024MHZ => Hertz(1_024_000),
Msirange::RANGE_768KHZ => Hertz(768_000),
Msirange::RANGE_400KHZ => Hertz(400_000),
Msirange::RANGE_200KHZ => Hertz(200_000),
Msirange::RANGE_133KHZ => Hertz(133_000),
Msirange::RANGE_100KHZ => Hertz(100_000),
}
}

View File

@ -1,45 +1,118 @@
pub use crate::pac::rcc::vals::{ pub use super::bus::{AHBPrescaler, APBPrescaler};
Hpre as AHBPrescaler, Hsepre as HsePrescaler, Pllm, Plln, Pllp, Pllq, Pllr, Pllsrc as PllSource, use crate::rcc::bd::{BackupDomain, RtcClockSource};
Ppre as APBPrescaler, Sw as Sysclk, use crate::rcc::Clocks;
}; use crate::time::{khz, mhz, Hertz};
use crate::rcc::{set_freqs, Clocks};
use crate::time::{mhz, Hertz}; /// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
/// and with the addition of the init function to configure a system clock.
/// Only the basic setup using the HSE and HSI clocks are supported as of now.
/// 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 HsePrescaler {
NotDivided,
Div2,
}
impl From<HsePrescaler> for bool {
fn from(value: HsePrescaler) -> Self {
match value {
HsePrescaler::NotDivided => false,
HsePrescaler::Div2 => true,
}
}
}
pub struct Hse { pub struct Hse {
pub prediv: HsePrescaler, pub prediv: HsePrescaler,
pub frequency: Hertz, pub frequency: Hertz,
} }
/// System clock mux source
#[derive(Clone, Copy, PartialEq)]
pub enum Sysclk {
/// MSI selected as sysclk
MSI,
/// HSI selected as sysclk
HSI,
/// HSE selected as sysclk
HSE,
/// PLL selected as sysclk
Pll,
}
impl From<Sysclk> for u8 {
fn from(value: Sysclk) -> Self {
match value {
Sysclk::MSI => 0b00,
Sysclk::HSI => 0b01,
Sysclk::HSE => 0b10,
Sysclk::Pll => 0b11,
}
}
}
#[derive(Clone, Copy, PartialEq)]
pub enum PllSource {
Hsi,
Msi,
Hse,
}
impl From<PllSource> for u8 {
fn from(value: PllSource) -> Self {
match value {
PllSource::Msi => 0b01,
PllSource::Hsi => 0b10,
PllSource::Hse => 0b11,
}
}
}
pub enum Pll48Source {
PllSai,
Pll,
Msi,
Hsi48,
}
pub struct PllMux { pub struct PllMux {
/// Source clock selection. /// Source clock selection.
pub source: PllSource, pub source: PllSource,
/// PLL pre-divider (DIVM). Must be between 1 and 63. /// PLL pre-divider (DIVM). Must be between 1 and 63.
pub prediv: Pllm, pub prediv: u8,
} }
pub struct Pll { pub struct Pll {
/// PLL multiplication factor. Must be between 4 and 512. /// PLL multiplication factor. Must be between 4 and 512.
pub mul: Plln, pub mul: u16,
/// 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. Must be between 1 and 128.
/// 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<Pllp>, pub divp: Option<u16>,
/// 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. Must be between 1 and 128.
pub divq: Option<Pllq>, pub divq: Option<u16>,
/// 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. Must be between 1 and 128.
pub divr: Option<Pllr>, pub divr: Option<u16>,
} }
/// Clocks configutation /// Clocks configutation
pub struct Config { pub struct Config {
pub hse: Option<Hse>, pub hse: Option<Hse>,
pub lse: Option<Hertz>,
pub lsi: bool,
pub sys: Sysclk, pub sys: Sysclk,
pub mux: Option<PllMux>, pub mux: Option<PllMux>,
pub pll48: Option<Pll48Source>,
pub rtc: Option<RtcClockSource>,
pub pll: Option<Pll>, pub pll: Option<Pll>,
pub pllsai: Option<Pll>, pub pllsai: Option<Pll>,
@ -49,28 +122,28 @@ pub struct Config {
pub ahb3_pre: AHBPrescaler, pub ahb3_pre: AHBPrescaler,
pub apb1_pre: APBPrescaler, pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler, pub apb2_pre: APBPrescaler,
pub ls: super::LsConfig,
} }
pub const WPAN_DEFAULT: Config = Config { pub const WPAN_DEFAULT: Config = Config {
hse: Some(Hse { hse: Some(Hse {
frequency: mhz(32), frequency: mhz(32),
prediv: HsePrescaler::DIV1, prediv: HsePrescaler::NotDivided,
}), }),
sys: Sysclk::PLL, lse: Some(khz(32)),
sys: Sysclk::Pll,
mux: Some(PllMux { mux: Some(PllMux {
source: PllSource::HSE, source: PllSource::Hse,
prediv: Pllm::DIV2, prediv: 2,
}), }),
pll48: None,
ls: super::LsConfig::default_lse(), rtc: Some(RtcClockSource::LSE),
lsi: false,
pll: Some(Pll { pll: Some(Pll {
mul: Plln::MUL12, mul: 12,
divp: Some(Pllp::DIV3), divp: Some(3),
divq: Some(Pllq::DIV4), divq: Some(4),
divr: Some(Pllr::DIV3), divr: Some(3),
}), }),
pllsai: None, pllsai: None,
@ -86,12 +159,14 @@ impl Default for Config {
fn default() -> Config { fn default() -> Config {
Config { Config {
hse: None, hse: None,
sys: Sysclk::HSI16, lse: None,
sys: Sysclk::HSI,
mux: None, mux: None,
pll48: None,
pll: None, pll: None,
pllsai: None, pllsai: None,
rtc: None,
ls: Default::default(), lsi: false,
ahb1_pre: AHBPrescaler::DIV1, ahb1_pre: AHBPrescaler::DIV1,
ahb2_pre: AHBPrescaler::DIV1, ahb2_pre: AHBPrescaler::DIV1,
@ -102,15 +177,16 @@ impl Default for Config {
} }
} }
#[cfg(stm32wb)] pub(crate) fn compute_clocks(config: &Config) -> Clocks {
/// RCC initialization function let hse_clk = config.hse.as_ref().map(|hse| match hse.prediv {
pub(crate) unsafe fn init(config: Config) { HsePrescaler::NotDivided => hse.frequency,
let hse_clk = config.hse.as_ref().map(|hse| hse.frequency / hse.prediv); HsePrescaler::Div2 => hse.frequency / 2u32,
});
let mux_clk = config.mux.as_ref().map(|pll_mux| { let mux_clk = config.mux.as_ref().map(|pll_mux| {
(match pll_mux.source { (match pll_mux.source {
PllSource::HSE => hse_clk.unwrap(), PllSource::Hse => hse_clk.unwrap(),
PllSource::HSI16 => HSI_FREQ, PllSource::Hsi => HSI_FREQ,
_ => unreachable!(), _ => unreachable!(),
} / pll_mux.prediv) } / pll_mux.prediv)
}); });
@ -130,19 +206,44 @@ pub(crate) unsafe fn init(config: Config) {
let sys_clk = match config.sys { let sys_clk = match config.sys {
Sysclk::HSE => hse_clk.unwrap(), Sysclk::HSE => hse_clk.unwrap(),
Sysclk::HSI16 => HSI_FREQ, Sysclk::HSI => HSI_FREQ,
Sysclk::PLL => pll_r.unwrap(), Sysclk::Pll => pll_r.unwrap(),
_ => unreachable!(), _ => unreachable!(),
}; };
let ahb1_clk = sys_clk / config.ahb1_pre; let ahb1_clk = match config.ahb1_pre {
let ahb2_clk = sys_clk / config.ahb2_pre; AHBPrescaler::DIV1 => sys_clk,
let ahb3_clk = sys_clk / config.ahb3_pre; pre => {
let pre: u8 = pre.into();
let pre = 1u32 << (pre as u32 - 7);
sys_clk / pre
}
};
let ahb2_clk = match config.ahb2_pre {
AHBPrescaler::DIV1 => sys_clk,
pre => {
let pre: u8 = pre.into();
let pre = 1u32 << (pre as u32 - 7);
sys_clk / pre
}
};
let ahb3_clk = match config.ahb3_pre {
AHBPrescaler::DIV1 => sys_clk,
pre => {
let pre: u8 = pre.into();
let pre = 1u32 << (pre as u32 - 7);
sys_clk / pre
}
};
let (apb1_clk, apb1_tim_clk) = match config.apb1_pre { let (apb1_clk, apb1_tim_clk) = match config.apb1_pre {
APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk), APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk),
pre => { pre => {
let freq = ahb1_clk / pre; let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb1_clk / pre as u32;
(freq, freq * 2u32) (freq, freq * 2u32)
} }
}; };
@ -150,20 +251,43 @@ pub(crate) unsafe fn init(config: Config) {
let (apb2_clk, apb2_tim_clk) = match config.apb2_pre { let (apb2_clk, apb2_tim_clk) = match config.apb2_pre {
APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk), APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk),
pre => { pre => {
let freq = ahb1_clk / pre; let pre: u8 = pre.into();
let pre: u8 = 1 << (pre - 3);
let freq = ahb1_clk / pre as u32;
(freq, freq * 2u32) (freq, freq * 2u32)
} }
}; };
let rtc_clk = match config.rtc {
Some(RtcClockSource::LSI) => Some(LSI_FREQ),
Some(RtcClockSource::LSE) => Some(config.lse.unwrap()),
_ => None,
};
Clocks {
sys: sys_clk,
ahb1: ahb1_clk,
ahb2: ahb2_clk,
ahb3: ahb3_clk,
apb1: apb1_clk,
apb2: apb2_clk,
apb1_tim: apb1_tim_clk,
apb2_tim: apb2_tim_clk,
rtc: rtc_clk,
rtc_hse: None,
}
}
pub(crate) fn configure_clocks(config: &Config) {
let rcc = crate::pac::RCC; let rcc = crate::pac::RCC;
let needs_hsi = if let Some(pll_mux) = &config.mux { let needs_hsi = if let Some(pll_mux) = &config.mux {
pll_mux.source == PllSource::HSI16 pll_mux.source == PllSource::Hsi
} else { } else {
false false
}; };
if needs_hsi || config.sys == Sysclk::HSI16 { if needs_hsi || config.sys == Sysclk::HSI {
rcc.cr().modify(|w| { rcc.cr().modify(|w| {
w.set_hsion(true); w.set_hsion(true);
}); });
@ -173,12 +297,16 @@ pub(crate) unsafe fn init(config: Config) {
rcc.cfgr().modify(|w| w.set_stopwuck(true)); rcc.cfgr().modify(|w| w.set_stopwuck(true));
let rtc = config.ls.init(); BackupDomain::configure_ls(
config.rtc.unwrap_or(RtcClockSource::NOCLOCK),
config.lsi,
config.lse.map(|_| Default::default()),
);
match &config.hse { match &config.hse {
Some(hse) => { Some(hse) => {
rcc.cr().modify(|w| { rcc.cr().modify(|w| {
w.set_hsepre(hse.prediv); w.set_hsepre(hse.prediv.into());
w.set_hseon(true); w.set_hseon(true);
}); });
@ -200,18 +328,18 @@ pub(crate) unsafe fn init(config: Config) {
match &config.pll { match &config.pll {
Some(pll) => { Some(pll) => {
rcc.pllcfgr().modify(|w| { rcc.pllcfgr().modify(|w| {
w.set_plln(pll.mul); w.set_plln(pll.mul as u8);
pll.divp.map(|divp| { pll.divp.map(|divp| {
w.set_pllpen(true); w.set_pllpen(true);
w.set_pllp(divp) w.set_pllp((divp - 1) as u8)
}); });
pll.divq.map(|divq| { pll.divq.map(|divq| {
w.set_pllqen(true); w.set_pllqen(true);
w.set_pllq(divq) w.set_pllq((divq - 1) as u8)
}); });
pll.divr.map(|divr| { pll.divr.map(|divr| {
w.set_pllren(true); // w.set_pllren(true);
w.set_pllr(divr); w.set_pllr((divr - 1) as u8);
}); });
}); });
@ -224,25 +352,13 @@ pub(crate) unsafe fn init(config: Config) {
rcc.cfgr().modify(|w| { rcc.cfgr().modify(|w| {
w.set_sw(config.sys.into()); w.set_sw(config.sys.into());
w.set_hpre(config.ahb1_pre); w.set_hpre(config.ahb1_pre.into());
w.set_ppre1(config.apb1_pre); w.set_ppre1(config.apb1_pre.into());
w.set_ppre2(config.apb2_pre); w.set_ppre2(config.apb2_pre.into());
}); });
rcc.extcfgr().modify(|w| { rcc.extcfgr().modify(|w| {
w.set_c2hpre(config.ahb2_pre); w.set_c2hpre(config.ahb2_pre.into());
w.set_shdhpre(config.ahb3_pre); w.set_shdhpre(config.ahb3_pre.into());
}); });
set_freqs(Clocks {
sys: sys_clk,
ahb1: ahb1_clk,
ahb2: ahb2_clk,
ahb3: ahb3_clk,
apb1: apb1_clk,
apb2: apb2_clk,
apb1_tim: apb1_tim_clk,
apb2_tim: apb2_tim_clk,
rtc,
})
} }

View File

@ -7,6 +7,9 @@ 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);
pub use crate::pac::pwr::vals::Vos as VoltageScale; pub use crate::pac::pwr::vals::Vos as VoltageScale;
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler};
@ -25,7 +28,7 @@ pub enum PllSrc {
impl Into<Pllsrc> for PllSrc { impl Into<Pllsrc> for PllSrc {
fn into(self) -> Pllsrc { fn into(self) -> Pllsrc {
match self { match self {
PllSrc::HSE(..) => Pllsrc::HSE, PllSrc::HSE(..) => Pllsrc::HSE32,
PllSrc::HSI16 => Pllsrc::HSI16, PllSrc::HSI16 => Pllsrc::HSI16,
} }
} }
@ -34,19 +37,19 @@ impl Into<Pllsrc> for PllSrc {
impl Into<Sw> for ClockSrc { impl Into<Sw> for ClockSrc {
fn into(self) -> Sw { fn into(self) -> Sw {
match self { match self {
ClockSrc::HSE(..) => Sw::HSE, ClockSrc::HSE(..) => Sw::HSE32,
ClockSrc::HSI16 => Sw::HSI16, ClockSrc::HSI16 => Sw::HSI16,
} }
} }
} }
#[derive(Copy, Clone)]
pub struct Config { pub struct Config {
pub mux: ClockSrc, pub mux: ClockSrc,
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 apb7_pre: APBPrescaler, pub apb7_pre: APBPrescaler,
pub ls: super::LsConfig,
} }
impl Default for Config { impl Default for Config {
@ -57,7 +60,6 @@ impl Default for Config {
apb1_pre: APBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1,
apb7_pre: APBPrescaler::DIV1, apb7_pre: APBPrescaler::DIV1,
ls: Default::default(),
} }
} }
} }
@ -106,13 +108,13 @@ pub(crate) unsafe fn init(config: Config) {
}); });
RCC.cfgr2().modify(|w| { RCC.cfgr2().modify(|w| {
w.set_hpre(config.ahb_pre); w.set_hpre(config.ahb_pre.into());
w.set_ppre1(config.apb1_pre); w.set_ppre1(config.apb1_pre.into());
w.set_ppre2(config.apb2_pre); w.set_ppre2(config.apb2_pre.into());
}); });
RCC.cfgr3().modify(|w| { RCC.cfgr3().modify(|w| {
w.set_ppre7(config.apb7_pre); w.set_ppre7(config.apb7_pre.into());
}); });
let ahb_freq = sys_clk / config.ahb_pre; let ahb_freq = sys_clk / config.ahb_pre;
@ -138,8 +140,6 @@ pub(crate) unsafe fn init(config: Config) {
} }
}; };
let rtc = config.ls.init();
set_freqs(Clocks { set_freqs(Clocks {
sys: sys_clk, sys: sys_clk,
ahb1: ahb_freq, ahb1: ahb_freq,
@ -150,6 +150,5 @@ pub(crate) unsafe fn init(config: Config) {
apb7: apb7_freq, apb7: apb7_freq,
apb1_tim: apb1_tim_freq, apb1_tim: apb1_tim_freq,
apb2_tim: apb2_tim_freq, apb2_tim: apb2_tim_freq,
rtc,
}); });
} }

View File

@ -1,27 +1,136 @@
pub use super::bus::{AHBPrescaler, APBPrescaler};
pub use crate::pac::pwr::vals::Vos as VoltageScale; pub use crate::pac::pwr::vals::Vos as VoltageScale;
use crate::pac::rcc::vals::Sw; use crate::pac::rcc::vals::Adcsel;
pub use crate::pac::rcc::vals::{
Adcsel as AdcClockSource, Hpre as AHBPrescaler, Msirange as MSIRange, Pllm, Plln, Pllp, Pllq, Pllr,
Pllsrc as PllSource, Ppre as APBPrescaler,
};
use crate::pac::{FLASH, RCC}; use crate::pac::{FLASH, 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;
/// Most of clock setup is copied from stm32l0xx-hal, and adopted to the generated PAC,
/// and with the addition of the init function to configure a system clock.
/// Only the basic setup using the HSE and HSI clocks are supported as of now.
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000); pub const HSI_FREQ: Hertz = Hertz(16_000_000);
/// HSE speed /// LSI speed
pub const HSE_FREQ: Hertz = Hertz(32_000_000); pub const LSI_FREQ: Hertz = Hertz(32_000);
/// HSE32 speed
pub const HSE32_FREQ: Hertz = Hertz(32_000_000);
/// System clock mux source /// System clock mux source
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum ClockSrc { pub enum ClockSrc {
MSI(MSIRange), MSI(MSIRange),
HSE, HSE32,
HSI16, HSI16,
} }
#[derive(Clone, Copy, PartialOrd, PartialEq)]
pub enum MSIRange {
/// Around 100 kHz
Range0,
/// Around 200 kHz
Range1,
/// Around 400 kHz
Range2,
/// Around 800 kHz
Range3,
/// Around 1 MHz
Range4,
/// Around 2 MHz
Range5,
/// Around 4 MHz (reset value)
Range6,
/// Around 8 MHz
Range7,
/// Around 16 MHz
Range8,
/// Around 24 MHz
Range9,
/// Around 32 MHz
Range10,
/// Around 48 MHz
Range11,
}
impl MSIRange {
fn freq(&self) -> u32 {
match self {
MSIRange::Range0 => 100_000,
MSIRange::Range1 => 200_000,
MSIRange::Range2 => 400_000,
MSIRange::Range3 => 800_000,
MSIRange::Range4 => 1_000_000,
MSIRange::Range5 => 2_000_000,
MSIRange::Range6 => 4_000_000,
MSIRange::Range7 => 8_000_000,
MSIRange::Range8 => 16_000_000,
MSIRange::Range9 => 24_000_000,
MSIRange::Range10 => 32_000_000,
MSIRange::Range11 => 48_000_000,
}
}
fn vos(&self) -> VoltageScale {
if self > &MSIRange::Range8 {
VoltageScale::RANGE1
} else {
VoltageScale::RANGE2
}
}
}
impl Default for MSIRange {
fn default() -> MSIRange {
MSIRange::Range6
}
}
impl Into<u8> for MSIRange {
fn into(self) -> u8 {
match self {
MSIRange::Range0 => 0b0000,
MSIRange::Range1 => 0b0001,
MSIRange::Range2 => 0b0010,
MSIRange::Range3 => 0b0011,
MSIRange::Range4 => 0b0100,
MSIRange::Range5 => 0b0101,
MSIRange::Range6 => 0b0110,
MSIRange::Range7 => 0b0111,
MSIRange::Range8 => 0b1000,
MSIRange::Range9 => 0b1001,
MSIRange::Range10 => 0b1010,
MSIRange::Range11 => 0b1011,
}
}
}
#[derive(Clone, Copy)]
pub enum AdcClockSource {
HSI16,
PLLPCLK,
SYSCLK,
}
impl AdcClockSource {
pub fn adcsel(&self) -> Adcsel {
match self {
AdcClockSource::HSI16 => Adcsel::HSI16,
AdcClockSource::PLLPCLK => Adcsel::PLLPCLK,
AdcClockSource::SYSCLK => Adcsel::SYSCLK,
}
}
}
impl Default for AdcClockSource {
fn default() -> Self {
Self::HSI16
}
}
/// Clocks configutation /// Clocks configutation
pub struct Config { pub struct Config {
pub mux: ClockSrc, pub mux: ClockSrc,
@ -29,60 +138,91 @@ pub struct Config {
pub shd_ahb_pre: AHBPrescaler, pub shd_ahb_pre: AHBPrescaler,
pub apb1_pre: APBPrescaler, pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler, pub apb2_pre: APBPrescaler,
pub rtc_mux: RtcClockSource,
pub lse: Option<Hertz>,
pub lsi: bool,
pub adc_clock_source: AdcClockSource, pub adc_clock_source: AdcClockSource,
pub ls: super::LsConfig,
} }
impl Default for Config { impl Default for Config {
#[inline] #[inline]
fn default() -> Config { fn default() -> Config {
Config { Config {
mux: ClockSrc::MSI(MSIRange::RANGE4M), mux: ClockSrc::MSI(MSIRange::default()),
ahb_pre: AHBPrescaler::DIV1, ahb_pre: AHBPrescaler::DIV1,
shd_ahb_pre: AHBPrescaler::DIV1, shd_ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1,
adc_clock_source: AdcClockSource::HSI16, rtc_mux: RtcClockSource::LSI,
ls: Default::default(), lsi: true,
lse: None,
adc_clock_source: AdcClockSource::default(),
} }
} }
} }
#[repr(u8)]
pub enum Lsedrv {
Low = 0,
MediumLow = 1,
MediumHigh = 2,
High = 3,
}
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
let (sys_clk, sw, vos) = match config.mux { let (sys_clk, sw, vos) = match config.mux {
ClockSrc::HSI16 => (HSI_FREQ, Sw::HSI16, VoltageScale::RANGE2), ClockSrc::HSI16 => (HSI_FREQ.0, 0x01, VoltageScale::RANGE2),
ClockSrc::HSE => (HSE_FREQ, Sw::HSE, VoltageScale::RANGE1), ClockSrc::HSE32 => (HSE32_FREQ.0, 0x02, VoltageScale::RANGE1),
ClockSrc::MSI(range) => (msirange_to_hertz(range), Sw::MSI, msirange_to_vos(range)), ClockSrc::MSI(range) => (range.freq(), 0x00, range.vos()),
}; };
let ahb_freq = sys_clk / config.ahb_pre; let ahb_freq: u32 = match config.ahb_pre {
let shd_ahb_freq = sys_clk / config.shd_ahb_pre; AHBPrescaler::DIV1 => sys_clk,
pre => {
let pre: u8 = pre.into();
let pre = 1 << (pre as u32 - 7);
sys_clk / pre
}
};
let shd_ahb_freq: u32 = match config.shd_ahb_pre {
AHBPrescaler::DIV1 => sys_clk,
pre => {
let pre: u8 = pre.into();
let pre = 1 << (pre as u32 - 7);
sys_clk / 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 / pre; let pre: u8 = pre.into();
(freq, freq * 2u32) let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
} }
}; };
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 / pre; let pre: u8 = pre.into();
(freq, freq * 2u32) let pre: u8 = 1 << (pre - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
} }
}; };
// Adjust flash latency // Adjust flash latency
let flash_clk_src_freq = shd_ahb_freq; let flash_clk_src_freq: u32 = shd_ahb_freq;
let ws = match vos { let ws = match vos {
VoltageScale::RANGE1 => match flash_clk_src_freq.0 { VoltageScale::RANGE1 => match flash_clk_src_freq {
0..=18_000_000 => 0b000, 0..=18_000_000 => 0b000,
18_000_001..=36_000_000 => 0b001, 18_000_001..=36_000_000 => 0b001,
_ => 0b010, _ => 0b010,
}, },
VoltageScale::RANGE2 => match flash_clk_src_freq.0 { VoltageScale::RANGE2 => match flash_clk_src_freq {
0..=6_000_000 => 0b000, 0..=6_000_000 => 0b000,
6_000_001..=12_000_000 => 0b001, 6_000_001..=12_000_000 => 0b001,
_ => 0b010, _ => 0b010,
@ -96,14 +236,17 @@ pub(crate) unsafe fn init(config: Config) {
while FLASH.acr().read().latency() != ws {} while FLASH.acr().read().latency() != ws {}
// Enables the LSI if configured
BackupDomain::configure_ls(config.rtc_mux, config.lsi, config.lse.map(|_| Default::default()));
match config.mux { match config.mux {
ClockSrc::HSI16 => { ClockSrc::HSI16 => {
// Enable HSI16 // Enable HSI16
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() {}
} }
ClockSrc::HSE => { ClockSrc::HSE32 => {
// Enable HSE // Enable HSE32
RCC.cr().write(|w| { RCC.cr().write(|w| {
w.set_hsebyppwr(true); w.set_hsebyppwr(true);
w.set_hseon(true); w.set_hseon(true);
@ -115,70 +258,49 @@ pub(crate) unsafe fn init(config: Config) {
assert!(!cr.msion() || cr.msirdy()); assert!(!cr.msion() || cr.msirdy());
RCC.cr().write(|w| { RCC.cr().write(|w| {
w.set_msirgsel(true); w.set_msirgsel(true);
w.set_msirange(range); w.set_msirange(range.into());
w.set_msion(true); w.set_msion(true);
// If LSE is enabled, enable calibration of MSI if let RtcClockSource::LSE = config.rtc_mux {
w.set_msipllen(config.ls.lse.is_some()); // If LSE is enabled, enable calibration of MSI
w.set_msipllen(true);
} else {
w.set_msipllen(false);
}
}); });
while !RCC.cr().read().msirdy() {} while !RCC.cr().read().msirdy() {}
} }
} }
RCC.extcfgr().modify(|w| { RCC.extcfgr().modify(|w| {
w.set_shdhpre(config.shd_ahb_pre); if config.shd_ahb_pre == AHBPrescaler::DIV1 {
w.set_shdhpre(0);
} else {
w.set_shdhpre(config.shd_ahb_pre.into());
}
}); });
RCC.cfgr().modify(|w| { RCC.cfgr().modify(|w| {
w.set_sw(sw.into()); w.set_sw(sw.into());
w.set_hpre(config.ahb_pre); w.set_hpre(config.ahb_pre);
w.set_ppre1(config.apb1_pre); w.set_ppre1(config.apb1_pre.into());
w.set_ppre2(config.apb2_pre); w.set_ppre2(config.apb2_pre.into());
}); });
// ADC clock MUX // ADC clock MUX
RCC.ccipr().modify(|w| w.set_adcsel(config.adc_clock_source)); RCC.ccipr().modify(|w| w.set_adcsel(config.adc_clock_source.adcsel()));
// TODO: switch voltage range // TODO: switch voltage range
let rtc = config.ls.init();
set_freqs(Clocks { set_freqs(Clocks {
sys: sys_clk, sys: Hertz(sys_clk),
ahb1: ahb_freq, ahb1: Hertz(ahb_freq),
ahb2: ahb_freq, ahb2: Hertz(ahb_freq),
ahb3: shd_ahb_freq, ahb3: Hertz(shd_ahb_freq),
apb1: apb1_freq, apb1: Hertz(apb1_freq),
apb2: apb2_freq, apb2: Hertz(apb2_freq),
apb3: shd_ahb_freq, apb3: Hertz(shd_ahb_freq),
apb1_tim: apb1_tim_freq, apb1_tim: Hertz(apb1_tim_freq),
apb2_tim: apb2_tim_freq, apb2_tim: Hertz(apb2_tim_freq),
rtc,
}); });
} }
fn msirange_to_hertz(range: MSIRange) -> Hertz {
match range {
MSIRange::RANGE100K => Hertz(100_000),
MSIRange::RANGE200K => Hertz(200_000),
MSIRange::RANGE400K => Hertz(400_000),
MSIRange::RANGE800K => Hertz(800_000),
MSIRange::RANGE1M => Hertz(1_000_000),
MSIRange::RANGE2M => Hertz(2_000_000),
MSIRange::RANGE4M => Hertz(4_000_000),
MSIRange::RANGE8M => Hertz(8_000_000),
MSIRange::RANGE16M => Hertz(16_000_000),
MSIRange::RANGE24M => Hertz(24_000_000),
MSIRange::RANGE32M => Hertz(32_000_000),
MSIRange::RANGE48M => Hertz(48_000_000),
_ => unreachable!(),
}
}
fn msirange_to_vos(range: MSIRange) -> VoltageScale {
if range.to_bits() > MSIRange::RANGE16M.to_bits() {
VoltageScale::RANGE1
} else {
VoltageScale::RANGE2
}
}

View File

@ -13,7 +13,6 @@ use crate::{interrupt, pac, peripherals, Peripheral};
static RNG_WAKER: AtomicWaker = AtomicWaker::new(); static RNG_WAKER: AtomicWaker = AtomicWaker::new();
#[derive(Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error { pub enum Error {
SeedError, SeedError,

View File

@ -10,6 +10,7 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::blocking_mutex::Mutex; use embassy_sync::blocking_mutex::Mutex;
pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError};
pub use crate::rcc::RtcClockSource;
use crate::time::Hertz; use crate::time::Hertz;
/// refer to AN4759 to compare features of RTC2 and RTC3 /// refer to AN4759 to compare features of RTC2 and RTC3
@ -92,50 +93,21 @@ impl RtcTimeProvider {
/// ///
/// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`].
pub fn now(&self) -> Result<DateTime, RtcError> { pub fn now(&self) -> Result<DateTime, RtcError> {
// For RM0433 we use BYPSHAD=1 to work around errata ES0392 2.19.1 let r = RTC::regs();
#[cfg(rcc_h7rm0433)] let tr = r.tr().read();
loop { let second = bcd2_to_byte((tr.st(), tr.su()));
let r = RTC::regs(); let minute = bcd2_to_byte((tr.mnt(), tr.mnu()));
let ss = r.ssr().read().ss(); let hour = bcd2_to_byte((tr.ht(), tr.hu()));
let dr = r.dr().read(); // Reading either RTC_SSR or RTC_TR locks the values in the higher-order
let tr = r.tr().read(); // calendar shadow registers until RTC_DR is read.
let dr = r.dr().read();
// If an RTCCLK edge occurs during read we may see inconsistent values let weekday = dr.wdu();
// so read ssr again and see if it has changed. (see RM0433 Rev 7 46.3.9) let day = bcd2_to_byte((dr.dt(), dr.du()));
let ss_after = r.ssr().read().ss(); let month = bcd2_to_byte((dr.mt() as u8, dr.mu()));
if ss == ss_after { let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16;
let second = bcd2_to_byte((tr.st(), tr.su()));
let minute = bcd2_to_byte((tr.mnt(), tr.mnu()));
let hour = bcd2_to_byte((tr.ht(), tr.hu()));
let weekday = dr.wdu(); self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime)
let day = bcd2_to_byte((dr.dt(), dr.du()));
let month = bcd2_to_byte((dr.mt() as u8, dr.mu()));
let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16;
return self::datetime::datetime(year, month, day, weekday, hour, minute, second)
.map_err(RtcError::InvalidDateTime);
}
}
#[cfg(not(rcc_h7rm0433))]
{
let r = RTC::regs();
let tr = r.tr().read();
let second = bcd2_to_byte((tr.st(), tr.su()));
let minute = bcd2_to_byte((tr.mnt(), tr.mnu()));
let hour = bcd2_to_byte((tr.ht(), tr.hu()));
// Reading either RTC_SSR or RTC_TR locks the values in the higher-order
// calendar shadow registers until RTC_DR is read.
let dr = r.dr().read();
let weekday = dr.wdu();
let day = bcd2_to_byte((dr.dt(), dr.du()));
let month = bcd2_to_byte((dr.mt() as u8, dr.mu()));
let year = bcd2_to_byte((dr.yt(), dr.yu())) as u16 + 1970_u16;
self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime)
}
} }
} }
@ -183,7 +155,7 @@ impl Default for RtcCalibrationCyclePeriod {
impl Rtc { impl Rtc {
pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self { pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self {
#[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] #[cfg(any(rcc_wle, rcc_wl5, rcc_g4, rcc_g0, rtc_v2l4, rtc_v2wb))]
<RTC as crate::rcc::sealed::RccPeripheral>::enable(); <RTC as crate::rcc::sealed::RccPeripheral>::enable();
let mut this = Self { let mut this = Self {
@ -203,8 +175,19 @@ impl Rtc {
} }
fn frequency() -> Hertz { fn frequency() -> Hertz {
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
let freqs = unsafe { crate::rcc::get_freqs() }; let freqs = unsafe { crate::rcc::get_freqs() };
freqs.rtc.unwrap()
// Load the clock frequency from the rcc mod, if supported
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
match freqs.rtc {
Some(hertz) => hertz,
None => freqs.rtc_hse.unwrap(),
}
// Assume the default value, if not supported
#[cfg(not(any(rcc_wb, rcc_f4, rcc_f410)))]
Hertz(32_768)
} }
/// Acquire a [`RtcTimeProvider`] instance. /// Acquire a [`RtcTimeProvider`] instance.

View File

@ -157,8 +157,6 @@ impl super::Rtc {
w.set_fmt(stm32_metapac::rtc::vals::Fmt::TWENTY_FOUR_HOUR); w.set_fmt(stm32_metapac::rtc::vals::Fmt::TWENTY_FOUR_HOUR);
w.set_osel(Osel::DISABLED); w.set_osel(Osel::DISABLED);
w.set_pol(Pol::HIGH); w.set_pol(Pol::HIGH);
#[cfg(rcc_h7rm0433)]
w.set_bypshad(true);
}); });
rtc.prer().modify(|w| { rtc.prer().modify(|w| {

View File

@ -11,7 +11,7 @@ use crate::pac::sai::{vals, Sai as Regs};
use crate::rcc::RccPeripheral; use crate::rcc::RccPeripheral;
use crate::{peripherals, Peripheral}; use crate::{peripherals, Peripheral};
#[derive(Debug, PartialEq, Eq)] #[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error { pub enum Error {
NotATransmitter, NotATransmitter,

View File

@ -15,7 +15,7 @@ use crate::rcc::RccPeripheral;
use crate::time::Hertz; use crate::time::Hertz;
use crate::{peripherals, Peripheral}; use crate::{peripherals, Peripheral};
#[derive(Debug, PartialEq, Eq)] #[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error { pub enum Error {
Framing, Framing,

View File

@ -77,10 +77,3 @@ impl Div<u8> for Hertz {
self / (rhs as u32) self / (rhs as u32)
} }
} }
impl Div<Hertz> for Hertz {
type Output = u32;
fn div(self, rhs: Hertz) -> Self::Output {
self.0 / rhs.0
}
}

View File

@ -122,46 +122,6 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
} }
} }
impl<'d, T: ComplementaryCaptureCompare16bitInstance> embedded_hal_02::Pwm for ComplementaryPwm<'d, T> {
type Channel = Channel;
type Time = Hertz;
type Duty = u16;
fn disable(&mut self, channel: Self::Channel) {
self.inner.enable_complementary_channel(channel, false);
self.inner.enable_channel(channel, false);
}
fn enable(&mut self, channel: Self::Channel) {
self.inner.enable_channel(channel, true);
self.inner.enable_complementary_channel(channel, true);
}
fn get_period(&self) -> Self::Time {
self.inner.get_frequency().into()
}
fn get_duty(&self, channel: Self::Channel) -> Self::Duty {
self.inner.get_compare_value(channel)
}
fn get_max_duty(&self) -> Self::Duty {
self.inner.get_max_compare_value() + 1
}
fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) {
assert!(duty <= self.get_max_duty());
self.inner.set_compare_value(channel, duty)
}
fn set_period<P>(&mut self, period: P)
where
P: Into<Self::Time>,
{
self.inner.set_frequency(period.into());
}
}
fn compute_dead_time_value(value: u16) -> (Ckd, u8) { fn compute_dead_time_value(value: u16) -> (Ckd, u8) {
/* /*
Dead-time = T_clk * T_dts * T_dtg Dead-time = T_clk * T_dts * T_dtg

View File

@ -70,16 +70,6 @@ pub(crate) mod sealed {
fn set_autoreload_preload(&mut self, enable: vals::Arpe) { fn set_autoreload_preload(&mut self, enable: vals::Arpe) {
Self::regs().cr1().modify(|r| r.set_arpe(enable)); Self::regs().cr1().modify(|r| r.set_arpe(enable));
} }
fn get_frequency(&self) -> Hertz {
let timer_f = Self::frequency();
let regs = Self::regs();
let arr = regs.arr().read().arr();
let psc = regs.psc().read().psc();
timer_f / arr / (psc + 1)
}
} }
pub trait GeneralPurpose16bitInstance: Basic16bitInstance { pub trait GeneralPurpose16bitInstance: Basic16bitInstance {
@ -113,16 +103,6 @@ pub(crate) mod sealed {
regs.egr().write(|r| r.set_ug(true)); regs.egr().write(|r| r.set_ug(true));
regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
} }
fn get_frequency(&self) -> Hertz {
let timer_f = Self::frequency();
let regs = Self::regs_gp32();
let arr = regs.arr().read().arr();
let psc = regs.psc().read().psc();
timer_f / arr / (psc + 1)
}
} }
pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { pub trait AdvancedControlInstance: GeneralPurpose16bitInstance {
@ -203,10 +183,6 @@ pub(crate) mod sealed {
fn get_max_compare_value(&self) -> u16 { fn get_max_compare_value(&self) -> u16 {
Self::regs_gp16().arr().read().arr() Self::regs_gp16().arr().read().arr()
} }
fn get_compare_value(&self, channel: Channel) -> u16 {
Self::regs_gp16().ccr(channel.raw()).read().ccr()
}
} }
pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance { pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance {
@ -243,10 +219,6 @@ pub(crate) mod sealed {
fn get_max_compare_value(&self) -> u32 { fn get_max_compare_value(&self) -> u32 {
Self::regs_gp32().arr().read().arr() Self::regs_gp32().arr().read().arr()
} }
fn get_compare_value(&self, channel: Channel) -> u32 {
Self::regs_gp32().ccr(channel.raw()).read().ccr()
}
} }
} }

View File

@ -109,41 +109,3 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
self.inner.set_output_polarity(channel, polarity); self.inner.set_output_polarity(channel, polarity);
} }
} }
impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> {
type Channel = Channel;
type Time = Hertz;
type Duty = u16;
fn disable(&mut self, channel: Self::Channel) {
self.inner.enable_channel(channel, false);
}
fn enable(&mut self, channel: Self::Channel) {
self.inner.enable_channel(channel, true);
}
fn get_period(&self) -> Self::Time {
self.inner.get_frequency().into()
}
fn get_duty(&self, channel: Self::Channel) -> Self::Duty {
self.inner.get_compare_value(channel)
}
fn get_max_duty(&self) -> Self::Duty {
self.inner.get_max_compare_value() + 1
}
fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) {
assert!(duty <= self.get_max_duty());
self.inner.set_compare_value(channel, duty)
}
fn set_period<P>(&mut self, period: P)
where
P: Into<Self::Time>,
{
self.inner.set_frequency(period.into());
}
}

View File

@ -35,7 +35,7 @@ futures-util = { version = "0.3.17", default-features = false }
critical-section = "1.1" critical-section = "1.1"
heapless = "0.7.5" heapless = "0.7.5"
cfg-if = "1.0.0" cfg-if = "1.0.0"
embedded-io-async = { version = "0.6.0", optional = true } embedded-io-async = { version = "0.5.0", optional = true }
[dev-dependencies] [dev-dependencies]
futures-executor = { version = "0.3.17", features = [ "thread-pool" ] } futures-executor = { version = "0.3.17", features = [ "thread-pool" ] }

View File

@ -35,8 +35,8 @@ embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["de
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true } embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"], optional = true }
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "msos-descriptor",], optional = true } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "msos-descriptor",], optional = true }
embedded-io = { version = "0.6.0", features = ["defmt-03"] } embedded-io = { version = "0.5.0", features = ["defmt-03"] }
embedded-io-async = { version = "0.6.0", optional = true, features = ["defmt-03"] } embedded-io-async = { version = "0.5.0", optional = true, features = ["defmt-03"] }
embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"], optional = true } embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"], optional = true }
lora-phy = { version = "2", optional = true } lora-phy = { version = "2", optional = true }
lorawan-device = { version = "0.11.0", default-features = false, features = ["async", "external-lora-phy"], optional = true } lorawan-device = { version = "0.11.0", default-features = false, features = ["async", "external-lora-phy"], optional = true }

View File

@ -37,7 +37,7 @@ embassy-net = { version = "0.1.0", path = "../../embassy-net", features = [
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = [ embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = [
"defmt", "defmt",
] } ] }
embedded-io-async = { version = "0.6.0" } embedded-io-async = { version = "0.5.0" }
defmt = "0.3" defmt = "0.3"
defmt-rtt = "0.4" defmt-rtt = "0.4"

View File

@ -45,7 +45,7 @@ usbd-hid = "0.6.1"
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" } embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" }
embedded-hal-async = "1.0.0-rc.1" embedded-hal-async = "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"] }
embedded-io-async = { version = "0.6.0", features = ["defmt-03"] } embedded-io-async = { version = "0.5.0", features = ["defmt-03"] }
embedded-storage = { version = "0.3" } embedded-storage = { version = "0.3" }
static_cell = { version = "1.1", features = ["nightly"]} static_cell = { version = "1.1", features = ["nightly"]}
log = "0.4" log = "0.4"

View File

@ -11,8 +11,8 @@ embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["lo
embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "nightly", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] } embassy-net = { version = "0.1.0", path = "../../embassy-net", features=[ "std", "nightly", "log", "medium-ethernet", "medium-ip", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6"] }
embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" } embassy-net-tuntap = { version = "0.1.0", path = "../../embassy-net-tuntap" }
embassy-net-ppp = { version = "0.1.0", path = "../../embassy-net-ppp", features = ["log"]} embassy-net-ppp = { version = "0.1.0", path = "../../embassy-net-ppp", features = ["log"]}
embedded-io-async = { version = "0.6.0" } embedded-io-async = { version = "0.5.0" }
embedded-io-adapters = { version = "0.6.0", features = ["futures-03"] } embedded-io-adapters = { version = "0.5.0", features = ["futures-03"] }
critical-section = { version = "1.1", features = ["std"] } critical-section = { version = "1.1", features = ["std"] }
smoltcp = { version = "0.10.0", features = ["dns-max-server-count-4"] } smoltcp = { version = "0.10.0", features = ["dns-max-server-count-4"] }

View File

@ -7,7 +7,7 @@ use core::convert::TryFrom;
use defmt::*; use defmt::*;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::rcc::{ use embassy_stm32::rcc::{
APBPrescaler, ClockSrc, HSEConfig, HSESrc, PLLConfig, PLLMul, PLLPDiv, PLLPreDiv, PLLQDiv, PLLSrc, APBPrescaler, ClockSrc, HSEConfig, HSESrc, PLL48Div, PLLConfig, PLLMainDiv, PLLMul, PLLPreDiv, PLLSrc,
}; };
use embassy_stm32::time::Hertz; use embassy_stm32::time::Hertz;
use embassy_stm32::Config; use embassy_stm32::Config;
@ -32,9 +32,9 @@ async fn main(_spawner: Spawner) {
// 1 MHz PLL input * 240 = 240 MHz PLL VCO // 1 MHz PLL input * 240 = 240 MHz PLL VCO
mul: unwrap!(PLLMul::try_from(240)), mul: unwrap!(PLLMul::try_from(240)),
// 240 MHz PLL VCO / 2 = 120 MHz main PLL output // 240 MHz PLL VCO / 2 = 120 MHz main PLL output
p_div: PLLPDiv::DIV2, main_div: PLLMainDiv::Div2,
// 240 MHz PLL VCO / 5 = 48 MHz PLL48 output // 240 MHz PLL VCO / 5 = 48 MHz PLL48 output
q_div: PLLQDiv::DIV5, pll48_div: unwrap!(PLL48Div::try_from(5)),
}; };
// System clock comes from PLL (= the 120 MHz main PLL output) // System clock comes from PLL (= the 120 MHz main PLL output)
config.rcc.mux = ClockSrc::PLL; config.rcc.mux = ClockSrc::PLL;

View File

@ -6,7 +6,7 @@ use defmt::info;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::adc::{Adc, SampleTime};
use embassy_stm32::peripherals::ADC1; use embassy_stm32::peripherals::ADC1;
use embassy_stm32::rcc::{AdcClockSource, Adcpres}; use embassy_stm32::rcc::AdcClockSource;
use embassy_stm32::time::mhz; use embassy_stm32::time::mhz;
use embassy_stm32::{adc, bind_interrupts, Config}; use embassy_stm32::{adc, bind_interrupts, Config};
use embassy_time::{Delay, Duration, Timer}; use embassy_time::{Delay, Duration, Timer};
@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) -> ! {
config.rcc.hclk = Some(mhz(64)); config.rcc.hclk = Some(mhz(64));
config.rcc.pclk1 = Some(mhz(32)); config.rcc.pclk1 = Some(mhz(32));
config.rcc.pclk2 = Some(mhz(64)); config.rcc.pclk2 = Some(mhz(64));
config.rcc.adc = Some(AdcClockSource::Pll(Adcpres::DIV1)); config.rcc.adc = Some(AdcClockSource::PllDiv1);
let mut p = embassy_stm32::init(config); let mut p = embassy_stm32::init(config);

View File

@ -5,9 +5,9 @@
use defmt::info; use defmt::info;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::adc::{Adc, SampleTime};
use embassy_stm32::opamp::{OpAmp, OpAmpGain}; use embassy_stm32::opamp::OpAmp;
use embassy_stm32::peripherals::ADC2; use embassy_stm32::peripherals::ADC2;
use embassy_stm32::rcc::{AdcClockSource, Adcpres}; use embassy_stm32::rcc::AdcClockSource;
use embassy_stm32::time::mhz; use embassy_stm32::time::mhz;
use embassy_stm32::{adc, bind_interrupts, Config}; use embassy_stm32::{adc, bind_interrupts, Config};
use embassy_time::{Delay, Duration, Timer}; use embassy_time::{Delay, Duration, Timer};
@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) -> ! {
config.rcc.hclk = Some(mhz(64)); config.rcc.hclk = Some(mhz(64));
config.rcc.pclk1 = Some(mhz(32)); config.rcc.pclk1 = Some(mhz(32));
config.rcc.pclk2 = Some(mhz(64)); config.rcc.pclk2 = Some(mhz(64));
config.rcc.adc = Some(AdcClockSource::Pll(Adcpres::DIV1)); config.rcc.adc = Some(AdcClockSource::PllDiv1);
let mut p = embassy_stm32::init(config); let mut p = embassy_stm32::init(config);
@ -39,7 +39,7 @@ async fn main(_spawner: Spawner) -> ! {
let mut vrefint = adc.enable_vref(&mut Delay); let mut vrefint = adc.enable_vref(&mut Delay);
let mut temperature = adc.enable_temperature(); let mut temperature = adc.enable_temperature();
let mut buffer = opamp.buffer_for(&mut p.PA7, OpAmpGain::Mul1); let mut buffer = opamp.buffer_for(&mut p.PA7);
loop { loop {
let vref = adc.read(&mut vrefint).await; let vref = adc.read(&mut vrefint).await;

View File

@ -19,8 +19,8 @@ defmt-rtt = "0.4"
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
cortex-m-rt = "0.7.0" cortex-m-rt = "0.7.0"
embedded-hal = "0.2.6" embedded-hal = "0.2.6"
embedded-io = { version = "0.6.0" } embedded-io = { version = "0.5.0" }
embedded-io-async = { version = "0.6.0" } embedded-io-async = { version = "0.5.0" }
panic-probe = { version = "0.3", features = ["print-defmt"] } panic-probe = { version = "0.3", features = ["print-defmt"] }
futures = { version = "0.3.17", default-features = false, features = ["async-await"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
heapless = { version = "0.7.5", default-features = false } heapless = { version = "0.7.5", default-features = false }

View File

@ -58,8 +58,9 @@ async fn main(spawner: Spawner) -> ! {
p.PG13, p.PG13,
p.PB13, p.PB13,
p.PG11, p.PG11,
GenericSMI::new(0), GenericSMI::new(),
mac_addr, mac_addr,
0,
); );
let config = embassy_net::Config::dhcpv4(Default::default()); let config = embassy_net::Config::dhcpv4(Default::default());

View File

@ -5,7 +5,7 @@
use defmt::*; use defmt::*;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::gpio::{Level, Output, Speed};
use embassy_stm32::rcc::{Mco, Mco1Source, Mco2Source, McoPrescaler}; use embassy_stm32::rcc::{Mco, Mco1Source, Mco2Source, McoClock};
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
@ -14,8 +14,8 @@ async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default()); let p = embassy_stm32::init(Default::default());
info!("Hello World!"); info!("Hello World!");
let _mco1 = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, McoPrescaler::DIV1); let _mco1 = Mco::new(p.MCO1, p.PA8, Mco1Source::Hsi, McoClock::DIV1);
let _mco2 = Mco::new(p.MCO2, p.PC9, Mco2Source::PLL, McoPrescaler::DIV4); let _mco2 = Mco::new(p.MCO2, p.PC9, Mco2Source::Pll, McoClock::DIV4);
let mut led = Output::new(p.PB7, Level::High, Speed::Low); let mut led = Output::new(p.PB7, Level::High, Speed::Low);
loop { loop {

View File

@ -5,14 +5,16 @@
use chrono::{NaiveDate, NaiveDateTime}; use chrono::{NaiveDate, NaiveDateTime};
use defmt::*; use defmt::*;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_stm32::rtc::{Rtc, RtcClockSource, RtcConfig};
use embassy_stm32::Config; use embassy_stm32::Config;
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let config = Config::default(); let mut config = Config::default();
config.rcc.lsi = true;
config.rcc.rtc = Option::Some(RtcClockSource::LSI);
let p = embassy_stm32::init(config); let p = embassy_stm32::init(config);
info!("Hello World!"); info!("Hello World!");

View File

@ -11,7 +11,7 @@ embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["de
embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] } embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] }
embedded-io-async = { version = "0.6.0" } embedded-io-async = { version = "0.5.0" }
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
defmt = "0.3" defmt = "0.3"

View File

@ -59,8 +59,9 @@ async fn main(spawner: Spawner) -> ! {
p.PG13, p.PG13,
p.PB13, p.PB13,
p.PG11, p.PG11,
GenericSMI::new(0), GenericSMI::new(),
mac_addr, mac_addr,
0,
); );
let config = embassy_net::Config::dhcpv4(Default::default()); let config = embassy_net::Config::dhcpv4(Default::default());

View File

@ -16,15 +16,15 @@ async fn main(_spawner: Spawner) {
config.rcc.pll = Some(Pll { config.rcc.pll = Some(Pll {
source: PllSrc::HSI16, source: PllSrc::HSI16,
prediv_m: PllM::DIV4, prediv_m: PllM::Div4,
mul_n: PllN::MUL85, mul_n: PllN::Mul85,
div_p: None, div_p: None,
div_q: None, div_q: None,
// Main system clock at 170 MHz // Main system clock at 170 MHz
div_r: Some(PllR::DIV2), div_r: Some(PllR::Div2),
}); });
config.rcc.adc12_clock_source = AdcClockSource::SYSCLK; config.rcc.adc12_clock_source = AdcClockSource::SysClk;
config.rcc.mux = ClockSrc::PLL; config.rcc.mux = ClockSrc::PLL;
let mut p = embassy_stm32::init(config); let mut p = embassy_stm32::init(config);

View File

@ -15,12 +15,12 @@ async fn main(_spawner: Spawner) {
config.rcc.pll = Some(Pll { config.rcc.pll = Some(Pll {
source: PllSrc::HSI16, source: PllSrc::HSI16,
prediv_m: PllM::DIV4, prediv_m: PllM::Div4,
mul_n: PllN::MUL85, mul_n: PllN::Mul85,
div_p: None, div_p: None,
div_q: None, div_q: None,
// Main system clock at 170 MHz // Main system clock at 170 MHz
div_r: Some(PllR::DIV2), div_r: Some(PllR::Div2),
}); });
config.rcc.mux = ClockSrc::PLL; config.rcc.mux = ClockSrc::PLL;

View File

@ -25,16 +25,16 @@ async fn main(_spawner: Spawner) {
// Change this to `false` to use the HSE clock source for the USB. This example assumes an 8MHz HSE. // Change this to `false` to use the HSE clock source for the USB. This example assumes an 8MHz HSE.
const USE_HSI48: bool = true; const USE_HSI48: bool = true;
let pllq_div = if USE_HSI48 { None } else { Some(PllQ::DIV6) }; let pllq_div = if USE_HSI48 { None } else { Some(PllQ::Div6) };
config.rcc.pll = Some(Pll { config.rcc.pll = Some(Pll {
source: PllSrc::HSE(Hertz(8_000_000)), source: PllSrc::HSE(Hertz(8_000_000)),
prediv_m: PllM::DIV2, prediv_m: PllM::Div2,
mul_n: PllN::MUL72, mul_n: PllN::Mul72,
div_p: None, div_p: None,
div_q: pllq_div, div_q: pllq_div,
// Main system clock at 144 MHz // Main system clock at 144 MHz
div_r: Some(PllR::DIV2), div_r: Some(PllR::Div2),
}); });
config.rcc.mux = ClockSrc::PLL; config.rcc.mux = ClockSrc::PLL;

View File

@ -11,7 +11,7 @@ embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["de
embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] }
embedded-io-async = { version = "0.6.0" } embedded-io-async = { version = "0.5.0" }
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
defmt = "0.3" defmt = "0.3"
@ -22,7 +22,7 @@ cortex-m-rt = "0.7.0"
embedded-hal = "0.2.6" embedded-hal = "0.2.6"
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" } 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-nal-async = { version = "0.6.0" } embedded-nal-async = { version = "0.5.0" }
panic-probe = { version = "0.3", features = ["print-defmt"] } panic-probe = { version = "0.3", features = ["print-defmt"] }
futures = { version = "0.3.17", default-features = false, features = ["async-await"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
heapless = { version = "0.7.5", default-features = false } heapless = { version = "0.7.5", default-features = false }

View File

@ -9,9 +9,7 @@ use embassy_net::{Ipv4Address, Stack, StackResources};
use embassy_stm32::eth::generic_smi::GenericSMI; use embassy_stm32::eth::generic_smi::GenericSMI;
use embassy_stm32::eth::{Ethernet, PacketQueue}; use embassy_stm32::eth::{Ethernet, PacketQueue};
use embassy_stm32::peripherals::ETH; use embassy_stm32::peripherals::ETH;
use embassy_stm32::rcc::{ use embassy_stm32::rcc::{AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllSource, Sysclk, VoltageScale};
AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllDiv, PllMul, PllPreDiv, PllSource, Sysclk, VoltageScale,
};
use embassy_stm32::rng::Rng; use embassy_stm32::rng::Rng;
use embassy_stm32::time::Hertz; use embassy_stm32::time::Hertz;
use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config};
@ -44,10 +42,10 @@ async fn main(spawner: Spawner) -> ! {
}); });
config.rcc.pll1 = Some(Pll { config.rcc.pll1 = Some(Pll {
source: PllSource::Hse, source: PllSource::Hse,
prediv: PllPreDiv::DIV2, prediv: 2,
mul: PllMul::MUL125, mul: 125,
divp: Some(PllDiv::DIV2), divp: Some(2),
divq: Some(PllDiv::DIV2), divq: Some(2),
divr: None, divr: None,
}); });
config.rcc.ahb_pre = AHBPrescaler::DIV1; config.rcc.ahb_pre = AHBPrescaler::DIV1;
@ -80,8 +78,9 @@ async fn main(spawner: Spawner) -> ! {
p.PG13, p.PG13,
p.PB15, p.PB15,
p.PG11, p.PG11,
GenericSMI::new(0), GenericSMI::new(),
mac_addr, mac_addr,
0,
); );
let config = embassy_net::Config::dhcpv4(Default::default()); let config = embassy_net::Config::dhcpv4(Default::default());

View File

@ -4,9 +4,7 @@
use defmt::{panic, *}; use defmt::{panic, *};
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::rcc::{ use embassy_stm32::rcc::{AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllSource, Sysclk, VoltageScale};
AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllDiv, PllMul, PllPreDiv, PllSource, Sysclk, VoltageScale,
};
use embassy_stm32::time::Hertz; use embassy_stm32::time::Hertz;
use embassy_stm32::usb::{Driver, Instance}; use embassy_stm32::usb::{Driver, Instance};
use embassy_stm32::{bind_interrupts, pac, peripherals, usb, Config}; use embassy_stm32::{bind_interrupts, pac, peripherals, usb, Config};
@ -31,9 +29,9 @@ async fn main(_spawner: Spawner) {
}); });
config.rcc.pll1 = Some(Pll { config.rcc.pll1 = Some(Pll {
source: PllSource::Hse, source: PllSource::Hse,
prediv: PllPreDiv::DIV2, prediv: 2,
mul: PllMul::MUL125, mul: 125,
divp: Some(PllDiv::DIV2), // 250mhz divp: Some(2), // 250mhz
divq: None, divq: None,
divr: None, divr: None,
}); });

View File

@ -6,12 +6,12 @@ license = "MIT OR Apache-2.0"
[dependencies] [dependencies]
# Change stm32h743bi to your chip name, if necessary. # Change stm32h743bi to your chip name, if necessary.
embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "time-driver-any", "exti", "memory-x", "unstable-pac", "unstable-traits", "chrono"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h743bi", "time-driver-any", "exti", "memory-x", "unstable-pac", "unstable-traits"] }
embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] }
embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] }
embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] }
embedded-io-async = { version = "0.6.0" } embedded-io-async = { version = "0.5.0" }
embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
defmt = "0.3" defmt = "0.3"
@ -22,7 +22,7 @@ cortex-m-rt = "0.7.0"
embedded-hal = "0.2.6" embedded-hal = "0.2.6"
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" } 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-nal-async = { version = "0.6.0" } embedded-nal-async = { version = "0.5.0" }
panic-probe = { version = "0.3", features = ["print-defmt"] } panic-probe = { version = "0.3", features = ["print-defmt"] }
futures = { version = "0.3.17", default-features = false, features = ["async-await"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
heapless = { version = "0.7.5", default-features = false } heapless = { version = "0.7.5", default-features = false }
@ -32,7 +32,6 @@ micromath = "2.0.0"
stm32-fmc = "0.3.0" stm32-fmc = "0.3.0"
embedded-storage = "0.3.0" embedded-storage = "0.3.0"
static_cell = { version = "1.1", features = ["nightly"]} static_cell = { version = "1.1", features = ["nightly"]}
chrono = { version = "^0.4", default-features = false }
# cargo build/run # cargo build/run
[profile.dev] [profile.dev]

View File

@ -18,16 +18,16 @@ async fn main(_spawner: Spawner) {
config.rcc.csi = true; config.rcc.csi = true;
config.rcc.pll_src = PllSource::Hsi; config.rcc.pll_src = PllSource::Hsi;
config.rcc.pll1 = Some(Pll { config.rcc.pll1 = Some(Pll {
prediv: PllPreDiv::DIV4, prediv: 4,
mul: PllMul::MUL50, mul: 50,
divp: Some(PllDiv::DIV2), divp: Some(2),
divq: Some(PllDiv::DIV8), // SPI1 cksel defaults to pll1_q divq: Some(8), // SPI1 cksel defaults to pll1_q
divr: None, divr: None,
}); });
config.rcc.pll2 = Some(Pll { config.rcc.pll2 = Some(Pll {
prediv: PllPreDiv::DIV4, prediv: 4,
mul: PllMul::MUL50, mul: 50,
divp: Some(PllDiv::DIV8), // 100mhz divp: Some(8), // 100mhz
divq: None, divq: None,
divr: None, divr: None,
}); });

View File

@ -6,7 +6,7 @@ use embassy_executor::Spawner;
use embassy_stm32::dcmi::{self, *}; use embassy_stm32::dcmi::{self, *};
use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::gpio::{Level, Output, Speed};
use embassy_stm32::i2c::I2c; use embassy_stm32::i2c::I2c;
use embassy_stm32::rcc::{Mco, Mco1Source, McoPrescaler}; use embassy_stm32::rcc::{Mco, Mco1Source};
use embassy_stm32::time::khz; use embassy_stm32::time::khz;
use embassy_stm32::{bind_interrupts, i2c, peripherals, Config}; use embassy_stm32::{bind_interrupts, i2c, peripherals, Config};
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
@ -32,10 +32,10 @@ async fn main(_spawner: Spawner) {
config.rcc.csi = true; config.rcc.csi = true;
config.rcc.pll_src = PllSource::Hsi; config.rcc.pll_src = PllSource::Hsi;
config.rcc.pll1 = Some(Pll { config.rcc.pll1 = Some(Pll {
prediv: PllPreDiv::DIV4, prediv: 4,
mul: PllMul::MUL50, mul: 50,
divp: Some(PllDiv::DIV2), divp: Some(2),
divq: Some(PllDiv::DIV8), // 100mhz divq: Some(8), // 100mhz
divr: None, divr: None,
}); });
config.rcc.sys = Sysclk::Pll1P; // 400 Mhz config.rcc.sys = Sysclk::Pll1P; // 400 Mhz
@ -49,7 +49,7 @@ async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(config); let p = embassy_stm32::init(config);
defmt::info!("Hello World!"); defmt::info!("Hello World!");
let mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, McoPrescaler::DIV3); let mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, 3);
let mut led = Output::new(p.PE3, Level::High, Speed::Low); let mut led = Output::new(p.PE3, Level::High, Speed::Low);
let cam_i2c = I2c::new( let cam_i2c = I2c::new(
@ -184,7 +184,7 @@ mod ov7725 {
const CAM_ADDR: u8 = 0x21; const CAM_ADDR: u8 = 0x21;
#[derive(Format, PartialEq, Eq)] #[derive(Format)]
pub enum Error<I2cError: Format> { pub enum Error<I2cError: Format> {
I2c(I2cError), I2c(I2cError),
} }

View File

@ -20,16 +20,16 @@ fn main() -> ! {
config.rcc.csi = true; config.rcc.csi = true;
config.rcc.pll_src = PllSource::Hsi; config.rcc.pll_src = PllSource::Hsi;
config.rcc.pll1 = Some(Pll { config.rcc.pll1 = Some(Pll {
prediv: PllPreDiv::DIV4, prediv: 4,
mul: PllMul::MUL50, mul: 50,
divp: Some(PllDiv::DIV2), divp: Some(2),
divq: Some(PllDiv::DIV8), // 100mhz divq: Some(8), // SPI1 cksel defaults to pll1_q
divr: None, divr: None,
}); });
config.rcc.pll2 = Some(Pll { config.rcc.pll2 = Some(Pll {
prediv: PllPreDiv::DIV4, prediv: 4,
mul: PllMul::MUL50, mul: 50,
divp: Some(PllDiv::DIV8), // 100mhz divp: Some(8), // 100mhz
divq: None, divq: None,
divr: None, divr: None,
}); });

View File

@ -28,16 +28,16 @@ async fn main(spawner: Spawner) {
config.rcc.csi = true; config.rcc.csi = true;
config.rcc.pll_src = PllSource::Hsi; config.rcc.pll_src = PllSource::Hsi;
config.rcc.pll1 = Some(Pll { config.rcc.pll1 = Some(Pll {
prediv: PllPreDiv::DIV4, prediv: 4,
mul: PllMul::MUL50, mul: 50,
divp: Some(PllDiv::DIV2), divp: Some(2),
divq: Some(PllDiv::DIV8), // 100mhz divq: Some(8), // SPI1 cksel defaults to pll1_q
divr: None, divr: None,
}); });
config.rcc.pll2 = Some(Pll { config.rcc.pll2 = Some(Pll {
prediv: PllPreDiv::DIV4, prediv: 4,
mul: PllMul::MUL50, mul: 50,
divp: Some(PllDiv::DIV8), // 100mhz divp: Some(8), // 100mhz
divq: None, divq: None,
divr: None, divr: None,
}); });

View File

@ -39,9 +39,9 @@ async fn main(spawner: Spawner) -> ! {
config.rcc.hsi48 = true; // needed for RNG config.rcc.hsi48 = true; // needed for RNG
config.rcc.pll_src = PllSource::Hsi; config.rcc.pll_src = PllSource::Hsi;
config.rcc.pll1 = Some(Pll { config.rcc.pll1 = Some(Pll {
prediv: PllPreDiv::DIV4, prediv: 4,
mul: PllMul::MUL50, mul: 50,
divp: Some(PllDiv::DIV2), divp: Some(2),
divq: None, divq: None,
divr: None, divr: None,
}); });
@ -77,8 +77,9 @@ async fn main(spawner: Spawner) -> ! {
p.PG13, p.PG13,
p.PB13, p.PB13,
p.PG11, p.PG11,
GenericSMI::new(0), GenericSMI::new(),
mac_addr, mac_addr,
0,
); );
let config = embassy_net::Config::dhcpv4(Default::default()); let config = embassy_net::Config::dhcpv4(Default::default());

View File

@ -40,9 +40,9 @@ async fn main(spawner: Spawner) -> ! {
config.rcc.hsi48 = true; // needed for RNG config.rcc.hsi48 = true; // needed for RNG
config.rcc.pll_src = PllSource::Hsi; config.rcc.pll_src = PllSource::Hsi;
config.rcc.pll1 = Some(Pll { config.rcc.pll1 = Some(Pll {
prediv: PllPreDiv::DIV4, prediv: 4,
mul: PllMul::MUL50, mul: 50,
divp: Some(PllDiv::DIV2), divp: Some(2),
divq: None, divq: None,
divr: None, divr: None,
}); });
@ -78,8 +78,9 @@ async fn main(spawner: Spawner) -> ! {
p.PG13, p.PG13,
p.PB13, p.PB13,
p.PG11, p.PG11,
GenericSMI::new(0), GenericSMI::new(),
mac_addr, mac_addr,
0,
); );
let config = embassy_net::Config::dhcpv4(Default::default()); let config = embassy_net::Config::dhcpv4(Default::default());

View File

@ -18,10 +18,10 @@ async fn main(_spawner: Spawner) {
config.rcc.csi = true; config.rcc.csi = true;
config.rcc.pll_src = PllSource::Hsi; config.rcc.pll_src = PllSource::Hsi;
config.rcc.pll1 = Some(Pll { config.rcc.pll1 = Some(Pll {
prediv: PllPreDiv::DIV4, prediv: 4,
mul: PllMul::MUL50, mul: 50,
divp: Some(PllDiv::DIV2), divp: Some(2),
divq: Some(PllDiv::DIV8), // 100mhz divq: Some(8), // 100mhz
divr: None, divr: None,
}); });
config.rcc.sys = Sysclk::Pll1P; // 400 Mhz config.rcc.sys = Sysclk::Pll1P; // 400 Mhz

View File

@ -22,10 +22,10 @@ async fn main(_spawner: Spawner) {
config.rcc.hsi48 = true; // needed for RNG config.rcc.hsi48 = true; // needed for RNG
config.rcc.pll_src = PllSource::Hsi; config.rcc.pll_src = PllSource::Hsi;
config.rcc.pll1 = Some(Pll { config.rcc.pll1 = Some(Pll {
prediv: PllPreDiv::DIV4, prediv: 4,
mul: PllMul::MUL50, mul: 50,
divp: Some(PllDiv::DIV2), divp: Some(2),
divq: Some(PllDiv::DIV8), // 100mhz divq: Some(8), // 100 Mhz
divr: None, divr: None,
}); });
config.rcc.sys = Sysclk::Pll1P; // 400 Mhz config.rcc.sys = Sysclk::Pll1P; // 400 Mhz

View File

@ -5,7 +5,7 @@
use defmt::*; use defmt::*;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::gpio::{Level, Output, Speed};
use embassy_stm32::rcc::{Mco, Mco1Source, McoPrescaler}; use embassy_stm32::rcc::{Mco, Mco1Source};
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
@ -16,7 +16,7 @@ async fn main(_spawner: Spawner) {
let mut led = Output::new(p.PB14, Level::High, Speed::Low); let mut led = Output::new(p.PB14, Level::High, Speed::Low);
let _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, McoPrescaler::DIV8); let _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, 8);
loop { loop {
info!("high"); info!("high");

View File

@ -21,9 +21,9 @@ async fn main(_spawner: Spawner) {
config.rcc.csi = true; config.rcc.csi = true;
config.rcc.pll_src = PllSource::Hsi; config.rcc.pll_src = PllSource::Hsi;
config.rcc.pll1 = Some(Pll { config.rcc.pll1 = Some(Pll {
prediv: PllPreDiv::DIV4, prediv: 4,
mul: PllMul::MUL50, mul: 50,
divp: Some(PllDiv::DIV2), divp: Some(2),
divq: None, divq: None,
divr: None, divr: None,
}); });

View File

@ -1,37 +0,0 @@
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use chrono::{NaiveDate, NaiveDateTime};
use defmt::*;
use embassy_executor::Spawner;
use embassy_stm32::rcc::LsConfig;
use embassy_stm32::rtc::{Rtc, RtcConfig};
use embassy_stm32::Config;
use embassy_time::{Duration, Timer};
use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let mut config = Config::default();
config.rcc.ls = LsConfig::default_lse();
let p = embassy_stm32::init(config);
info!("Hello World!");
let now = NaiveDate::from_ymd_opt(2020, 5, 15)
.unwrap()
.and_hms_opt(10, 30, 15)
.unwrap();
let mut rtc = Rtc::new(p.RTC, RtcConfig::default());
info!("Got RTC! {:?}", now.timestamp());
rtc.set_datetime(now.into()).expect("datetime not set");
// In reality the delay would be much longer
Timer::after(Duration::from_millis(20000)).await;
let then: NaiveDateTime = rtc.now().unwrap().into();
info!("Got RTC! {:?}", then.timestamp());
}

View File

@ -22,10 +22,10 @@ async fn main(_spawner: Spawner) -> ! {
config.rcc.csi = true; config.rcc.csi = true;
config.rcc.pll_src = PllSource::Hsi; config.rcc.pll_src = PllSource::Hsi;
config.rcc.pll1 = Some(Pll { config.rcc.pll1 = Some(Pll {
prediv: PllPreDiv::DIV4, prediv: 4,
mul: PllMul::MUL50, mul: 50,
divp: Some(PllDiv::DIV2), divp: Some(2),
divq: Some(PllDiv::DIV4), // default clock chosen by SDMMCSEL. 200 Mhz divq: Some(4), // default clock chosen by SDMMCSEL. 200 Mhz
divr: None, divr: None,
}); });
config.rcc.sys = Sysclk::Pll1P; // 400 Mhz config.rcc.sys = Sysclk::Pll1P; // 400 Mhz

View File

@ -44,10 +44,10 @@ fn main() -> ! {
config.rcc.csi = true; config.rcc.csi = true;
config.rcc.pll_src = PllSource::Hsi; config.rcc.pll_src = PllSource::Hsi;
config.rcc.pll1 = Some(Pll { config.rcc.pll1 = Some(Pll {
prediv: PllPreDiv::DIV4, prediv: 4,
mul: PllMul::MUL50, mul: 50,
divp: Some(PllDiv::DIV2), divp: Some(2),
divq: Some(PllDiv::DIV8), // used by SPI3. 100Mhz. divq: Some(4), // used by SPI3. 100Mhz.
divr: None, divr: None,
}); });
config.rcc.sys = Sysclk::Pll1P; // 400 Mhz config.rcc.sys = Sysclk::Pll1P; // 400 Mhz

View File

@ -40,10 +40,10 @@ fn main() -> ! {
config.rcc.csi = true; config.rcc.csi = true;
config.rcc.pll_src = PllSource::Hsi; config.rcc.pll_src = PllSource::Hsi;
config.rcc.pll1 = Some(Pll { config.rcc.pll1 = Some(Pll {
prediv: PllPreDiv::DIV4, prediv: 4,
mul: PllMul::MUL50, mul: 50,
divp: Some(PllDiv::DIV2), divp: Some(2),
divq: Some(PllDiv::DIV8), // used by SPI3. 100Mhz. divq: Some(4), // used by SPI3. 100Mhz.
divr: None, divr: None,
}); });
config.rcc.sys = Sysclk::Pll1P; // 400 Mhz config.rcc.sys = Sysclk::Pll1P; // 400 Mhz

View File

@ -28,9 +28,9 @@ async fn main(_spawner: Spawner) {
config.rcc.hsi48 = true; // needed for USB config.rcc.hsi48 = true; // needed for USB
config.rcc.pll_src = PllSource::Hsi; config.rcc.pll_src = PllSource::Hsi;
config.rcc.pll1 = Some(Pll { config.rcc.pll1 = Some(Pll {
prediv: PllPreDiv::DIV4, prediv: 4,
mul: PllMul::MUL50, mul: 50,
divp: Some(PllDiv::DIV2), divp: Some(2),
divq: None, divq: None,
divr: None, divr: None,
}); });

View File

@ -24,8 +24,8 @@ defmt = "0.3"
defmt-rtt = "0.4" defmt-rtt = "0.4"
embedded-storage = "0.3.0" embedded-storage = "0.3.0"
embedded-io = { version = "0.6.0" } embedded-io = { version = "0.5.0" }
embedded-io-async = { version = "0.6.0", optional = true } embedded-io-async = { version = "0.5.0", optional = true }
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
cortex-m-rt = "0.7.0" cortex-m-rt = "0.7.0"

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