diff --git a/ci.sh b/ci.sh index af98d6ed..c246e6a9 100755 --- a/ci.sh +++ b/ci.sh @@ -1,9 +1,12 @@ #!/bin/bash -set -euo pipefail +set -eo pipefail export RUSTFLAGS=-Dwarnings export DEFMT_LOG=trace,embassy_hal_internal=debug,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info +if [[ -z "${CARGO_TARGET_DIR}" ]]; then + export CARGO_TARGET_DIR=target_ci +fi TARGET=$(rustc -vV | sed -n 's|host: ||p') @@ -36,7 +39,7 @@ cargo batch \ --- build --release --manifest-path embassy-time/Cargo.toml --target thumbv6m-none-eabi --features nightly,defmt,defmt-timestamp-uptime,tick-hz-32_768,generic-queue-8 \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv4,medium-ethernet \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet \ - --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,nightly \ + --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,dhcpv4,medium-ethernet,nightly,dhcpv4-hostname \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ieee802154 \ --- build --release --manifest-path embassy-net/Cargo.toml --target thumbv7em-none-eabi --features defmt,tcp,udp,dns,proto-ipv6,medium-ethernet,medium-ieee802154 \ @@ -66,49 +69,68 @@ cargo batch \ --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly \ --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,intrinsics \ --- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features nightly,qspi-as-gpio \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,unstable-traits \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,unstable-traits \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,unstable-traits \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,time-driver-any,unstable-traits \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,time-driver-any \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,time-driver-any \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,time-driver-any,unstable-traits \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f410tb,defmt,exti,time-driver-any,unstable-traits \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f411ce,defmt,exti,time-driver-any,unstable-traits \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f413vh,defmt,exti,time-driver-any,unstable-traits \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,unstable-traits,embedded-sdmmc \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f730i8,defmt,exti,time-driver-any,unstable-traits \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,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 embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f401ve,defmt,exti,time-driver-any,unstable-traits \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f405zg,defmt,exti,time-driver-any,unstable-traits \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f407zg,defmt,exti,time-driver-any,unstable-traits \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f401ve,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f405zg,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f407zg,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f410tb,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f411ce,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f412zg,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f413vh,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f415zg,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f417zg,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f423zh,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f427zi,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,unstable-traits,embedded-sdmmc,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f437zi,log,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f439zi,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f446ze,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f469zi,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f479zi,defmt,exti,time-driver-any,unstable-traits,embedded-sdmmc,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f730i8,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h753zi,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h735zg,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l422cb,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wb15cc,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l072cz,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l041f6,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l073cz,defmt,exti,time-driver-any,unstable-traits,low-power,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f398ve,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f378cc,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32g0c1ve,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f217zg,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,stm32l552ze,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32wl54jc-cm0p,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wle5jb,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32g474pe,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f107vc,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f103re,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f100c4,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32h503rb,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32h562ag,defmt,exti,time-driver-any,unstable-traits,time \ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features ''\ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log' \ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \ @@ -178,12 +200,19 @@ cargo batch \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4a6zg --out-dir out/tests/stm32l4a6zg \ --- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features 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/nrf52840-dk/wifi_esp_hosted_perf + +rm out/tests/stm32wb55rg/wpan_mac +rm out/tests/stm32wb55rg/wpan_ble +rm out/tests/stm32f207zg/eth if [[ -z "${TELEPROBE_TOKEN-}" ]]; then echo No teleprobe token found, skipping running HIL tests diff --git a/ci_stable.sh b/ci_stable.sh index 4ee5f410..1fe4e3a1 100755 --- a/ci_stable.sh +++ b/ci_stable.sh @@ -40,33 +40,38 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585zi,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55vy,defmt,exti,time-driver-any,unstable-traits \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55cc-cm4,defmt,exti,time-driver-any,unstable-traits \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4r9zi,defmt,exti,time-driver-any,unstable-traits \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303vc,defmt,exti,time-driver-any,unstable-traits \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any,unstable-traits \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any,unstable-traits \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,time-driver-any \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,time-driver-any,unstable-traits \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,time-driver-any \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,time-driver-any,unstable-traits \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any,unstable-traits \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,time-driver-any \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,time-driver-any,unstable-traits \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any,unstable-traits \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,unstable-traits \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,unstable-traits \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any,unstable-traits \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any \ - --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,unstable-traits \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g473cc,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32g491re,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585zi,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55vy,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55cc-cm4,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4r9zi,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f303vc,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f411ce,defmt,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f410tb,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32f429zi,log,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l476vg,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l072cz,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32f217zg,defmt,exti,time-driver-any,unstable-traits,time \ --- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --no-default-features --out-dir out/examples/nrf52840 --bin raw_spawn \ --- build --release --manifest-path examples/stm32l0/Cargo.toml --target thumbv6m-none-eabi --no-default-features --out-dir out/examples/stm32l0 --bin raw_spawn \ diff --git a/cyw43/Cargo.toml b/cyw43/Cargo.toml index dae7419c..d7bba6b6 100644 --- a/cyw43/Cargo.toml +++ b/cyw43/Cargo.toml @@ -11,11 +11,10 @@ log = ["dep:log"] firmware-logs = [] [dependencies] -embassy-time = { version = "0.1.3", path = "../embassy-time"} +embassy-time = { version = "0.1.4", path = "../embassy-time"} embassy-sync = { version = "0.3.0", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"} -atomic-polyfill = "0.1.5" defmt = { version = "0.3", optional = true } log = { version = "0.4.17", optional = true } diff --git a/docs/modules/ROOT/examples/basic/Cargo.toml b/docs/modules/ROOT/examples/basic/Cargo.toml index e94358a9..527ce2ed 100644 --- a/docs/modules/ROOT/examples/basic/Cargo.toml +++ b/docs/modules/ROOT/examples/basic/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-executor = { version = "0.3.0", path = "../../../../../embassy-executor", features = ["defmt", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] } -embassy-time = { version = "0.1.0", path = "../../../../../embassy-time", features = ["defmt", "nightly"] } +embassy-time = { version = "0.1.4", path = "../../../../../embassy-time", features = ["defmt", "nightly"] } embassy-nrf = { version = "0.1.0", path = "../../../../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "nightly"] } defmt = "0.3" diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index 261a3c19..ee559a82 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -1,6 +1,6 @@ * xref:getting_started.adoc[Getting started] ** xref:basic_application.adoc[Basic application] -** xref:layer_by_layer.adoc[Layer by Layer] +* xref:layer_by_layer.adoc[Bare metal to async] * xref:runtime.adoc[Executor] * xref:hal.adoc[HAL] ** xref:nrf.adoc[nRF] @@ -9,4 +9,4 @@ * xref:examples.adoc[Examples] * xref:developer.adoc[Developer] -** xref:developer_stm32.adoc[Developer: STM32] \ No newline at end of file +** xref:developer_stm32.adoc[Developer: STM32] diff --git a/docs/modules/ROOT/pages/getting_started.adoc b/docs/modules/ROOT/pages/getting_started.adoc index 881e449b..2c6f4b1e 100644 --- a/docs/modules/ROOT/pages/getting_started.adoc +++ b/docs/modules/ROOT/pages/getting_started.adoc @@ -3,7 +3,7 @@ So you want to try Embassy, great! To get started, there are a few tools you need to install: * link:https://rustup.rs/[rustup] - the Rust toolchain is needed to compile Rust code. -* link:https://crates.io/crates/probe-run[probe-run] - to flash the firmware on your device. If you already have other tools like `OpenOCD` setup, you can use that as well. +* link:https://crates.io/crates/probe-rs[probe-rs] - to flash the firmware on your device. If you already have other tools like `OpenOCD` setup, you can use that as well. If you don't have any supported board, don't worry: you can also run embassy on your PC using the `std` examples. @@ -30,6 +30,10 @@ Embassy supports many microcontroller families, but the easiest ways to get star * link:https://www.raspberrypi.com/products/raspberry-pi-pico/[Raspberry Pi Pico] +=== ESP32 + +* link:https://github.com/esp-rs/esp-rust-board[ESP32C3] + == Running an example First you need to clone the [github repository]; @@ -38,7 +42,6 @@ First you need to clone the [github repository]; ---- git clone https://github.com/embassy-rs/embassy.git cd embassy -git submodule update --init ---- You can run an example by opening a terminal and entering the following commands: diff --git a/docs/modules/ROOT/pages/hal.adoc b/docs/modules/ROOT/pages/hal.adoc index de4ab33b..b1382e8e 100644 --- a/docs/modules/ROOT/pages/hal.adoc +++ b/docs/modules/ROOT/pages/hal.adoc @@ -7,4 +7,6 @@ Embassy provides HALs for several microcontroller families: * `embassy-rp` for the Raspberry Pi RP2040 microcontrollers These HALs implement async/await functionality for most peripherals while also implementing the -async traits in `embedded-hal-async`. You can also use these HALs with another executor. +async traits in `embedded-hal` and `embedded-hal-async`. You can also use these HALs with another executor. + +For the ESP32 series, there is an link:https://github.com/esp-rs/esp-hal[esp-hal] which you can use. diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc index 805a1e70..c6dead46 100644 --- a/docs/modules/ROOT/pages/index.adoc +++ b/docs/modules/ROOT/pages/index.adoc @@ -17,13 +17,26 @@ The Embassy project consists of several crates that you can use together or inde * **Hardware Abstraction Layers** - HALs implement safe, idiomatic Rust APIs to use the hardware capabilities, so raw register manipulation is not needed. The Embassy project maintains HALs for select hardware, but you can still use HALs from other projects with Embassy. ** link:https://docs.embassy.dev/embassy-stm32/[embassy-stm32], for all STM32 microcontroller families. ** link:https://docs.embassy.dev/embassy-nrf/[embassy-nrf], for the Nordic Semiconductor nRF52, nRF53, nRF91 series. +** link:https://docs.embassy.dev/embassy-rp/[embassy-rp], for the Raspberry Pi RP2040 microcontroller. +** link:https://github.com/esp-rs[esp-rs], for the Espressif Systems ESP32 series of chips. ++ +NOTE: A common question is if one can use the Embassy HALs standalone. Yes, it is possible! There are no dependency on the executor within the HALs. You can even use them without async, +as they implement both the link:https://github.com/rust-embedded/embedded-hal[Embedded HAL] blocking and async traits. -* **Networking** - The link:https://docs.embassy.dev/embassy-net/[embassy-net] network stack implements extensive networking functionality, including Ethernet, IP, TCP, UDP, ICMP and DHCP. Async drastically simplifies managing timeouts and serving multiple connections concurrently. +* **Networking** - The link:https://docs.embassy.dev/embassy-net/[embassy-net] network stack implements extensive networking functionality, including Ethernet, IP, TCP, UDP, ICMP and DHCP. Async drastically simplifies managing timeouts and serving multiple connections concurrently. Several drivers for WiFi and Ethernet chips can be found. * **Bluetooth** - The link:https://github.com/embassy-rs/nrf-softdevice[nrf-softdevice] crate provides Bluetooth Low Energy 4.x and 5.x support for nRF52 microcontrollers. -* **LoRa** - link:https://docs.embassy.dev/embassy-lora/[embassy-lora] supports LoRa networking on STM32WL wireless microcontrollers and Semtech SX127x transceivers. +* **LoRa** - link:https://github.com/embassy-rs/lora-phy[lora-phy] and link:https://docs.embassy.dev/embassy-lora/[embassy-lora] supports LoRa networking on a wide range of LoRa radios, fully integrated with a Rust link:https://github.com/ivajloip/rust-lorawan[LoRaWAN] implementation. * **USB** - link:https://docs.embassy.dev/embassy-usb/[embassy-usb] implements a device-side USB stack. Implementations for common classes such as USB serial (CDC ACM) and USB HID are available, and a rich builder API allows building your own. * **Bootloader and DFU** - link:https://github.com/embassy-rs/embassy/tree/master/embassy-boot[embassy-boot] is a lightweight bootloader supporting firmware application upgrades in a power-fail-safe way, with trial boots and rollbacks. + +== Resources + +For more reading material on async Rust and Embassy: + +* link:https://tweedegolf.nl/en/blog/65/async-rust-vs-rtos-showdown[Comparsion of FreeRTOS and Embassy] +* link:https://dev.to/apollolabsbin/series/20707[Tutorials] +* link:https://blog.drogue.io/firmware-updates-part-1/[Firmware Updates with Embassy] diff --git a/docs/modules/ROOT/pages/layer_by_layer.adoc b/docs/modules/ROOT/pages/layer_by_layer.adoc index a78a64a9..1d7bdc89 100644 --- a/docs/modules/ROOT/pages/layer_by_layer.adoc +++ b/docs/modules/ROOT/pages/layer_by_layer.adoc @@ -1,4 +1,4 @@ -= Embassy layer by layer += From bare metal to async Rust If you're new to Embassy, it can be overwhelming to grasp all the terminology and concepts. This guide aims to clarify the different layers in Embassy, which problem each layer solves for the application writer. @@ -8,8 +8,7 @@ The application we'll write is a simple 'push button, blink led' application, wh == PAC version -The PAC is the lowest API for accessing peripherals and registers, if you don't count reading/writing directly to memory addresses. It provides distinct types -to make accessing peripheral registers easier, but it does not prevent you from writing unsafe code. +The PAC is the lowest API for accessing peripherals and registers, if you don't count reading/writing directly to memory addresses. It provides distinct types to make accessing peripheral registers easier, but it does not prevent you from writing unsafe code. Writing an application using the PAC directly is therefore not recommended, but if the functionality you want to use is not exposed in the upper layers, that's what you need to use. diff --git a/docs/modules/ROOT/pages/nrf.adoc b/docs/modules/ROOT/pages/nrf.adoc index 10fe54b4..1706087a 100644 --- a/docs/modules/ROOT/pages/nrf.adoc +++ b/docs/modules/ROOT/pages/nrf.adoc @@ -8,7 +8,7 @@ The nRF timer driver operates at 32768 Hz by default. == Peripherals -The following peripherals have a HAL implementation at present: +The following peripherals have a HAL implementation at present * PWM * SPIM @@ -23,3 +23,7 @@ The following peripherals have a HAL implementation at present: * UARTE * TWIM * SAADC + +== Bluetooth + +For bluetooth, you can use the link:https://github.com/embassy-rs/nrf-softdevice[nrf-softdevice] crate. diff --git a/docs/modules/ROOT/pages/runtime.adoc b/docs/modules/ROOT/pages/runtime.adoc index 5096f5a4..cb8afef2 100644 --- a/docs/modules/ROOT/pages/runtime.adoc +++ b/docs/modules/ROOT/pages/runtime.adoc @@ -10,7 +10,7 @@ The Embassy executor is an async/await executor designed for embedded usage alon * No busy-loop polling: CPU sleeps when there's no work to do, using interrupts or `WFE/SEV`. * Efficient polling: a wake will only poll the woken task, not all of them. * Fair: a task can't monopolize CPU time even if it's constantly being woken. All other tasks get a chance to run before a given task gets polled for the second time. -* Creating multiple executor instances is supported, to run tasks with multiple priority levels. This allows higher-priority tasks to preempt lower-priority tasks. +* Creating multiple executor instances is supported, to run tasks at different priority levels. This allows higher-priority tasks to preempt lower-priority tasks. == Executor diff --git a/embassy-embedded-hal/Cargo.toml b/embassy-embedded-hal/Cargo.toml index 62a95ed9..040e2356 100644 --- a/embassy-embedded-hal/Cargo.toml +++ b/embassy-embedded-hal/Cargo.toml @@ -21,7 +21,7 @@ default = ["time"] [dependencies] embassy-futures = { version = "0.1.0", path = "../embassy-futures", optional = true } embassy-sync = { version = "0.3.0", path = "../embassy-sync" } -embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true } +embassy-time = { version = "0.1.4", path = "../embassy-time", optional = true } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [ "unproven", ] } diff --git a/embassy-embedded-hal/src/flash/partition/mod.rs b/embassy-embedded-hal/src/flash/partition/mod.rs index a12e49ce..42c8a308 100644 --- a/embassy-embedded-hal/src/flash/partition/mod.rs +++ b/embassy-embedded-hal/src/flash/partition/mod.rs @@ -11,7 +11,7 @@ pub use asynch::Partition; pub use blocking::BlockingPartition; /// Partition error -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { /// The requested flash area is outside the partition diff --git a/embassy-embedded-hal/src/lib.rs b/embassy-embedded-hal/src/lib.rs index 8872b3d6..ee964e40 100644 --- a/embassy-embedded-hal/src/lib.rs +++ b/embassy-embedded-hal/src/lib.rs @@ -1,5 +1,5 @@ #![cfg_attr(not(feature = "std"), no_std)] -#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections, try_blocks))] +#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, try_blocks))] #![warn(missing_docs)] //! Utilities to use `embedded-hal` traits with Embassy. diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml index 35944625..4869bf3e 100644 --- a/embassy-executor/Cargo.toml +++ b/embassy-executor/Cargo.toml @@ -59,7 +59,7 @@ rtos-trace = { version = "0.1.2", optional = true } futures-util = { version = "0.3.17", default-features = false } embassy-macros = { version = "0.2.1", path = "../embassy-macros" } -embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true} +embassy-time = { version = "0.1.4", path = "../embassy-time", optional = true} atomic-polyfill = "1.0.1" critical-section = "1.1" static_cell = "1.1" diff --git a/embassy-hal-internal/README.md b/embassy-hal-internal/README.md index d6539701..6b060d1c 100644 --- a/embassy-hal-internal/README.md +++ b/embassy-hal-internal/README.md @@ -1,4 +1,4 @@ -# embassy-macros +# embassy-hal-internal An [Embassy](https://embassy.dev) project. diff --git a/embassy-hal-internal/src/interrupt.rs b/embassy-hal-internal/src/interrupt.rs index b970aa2c..19dabcf6 100644 --- a/embassy-hal-internal/src/interrupt.rs +++ b/embassy-hal-internal/src/interrupt.rs @@ -4,6 +4,7 @@ use core::sync::atomic::{compiler_fence, Ordering}; use cortex_m::interrupt::InterruptNumber; use cortex_m::peripheral::NVIC; +use critical_section::CriticalSection; /// Generate a standard `mod interrupt` for a HAL. #[macro_export] @@ -91,6 +92,12 @@ macro_rules! interrupt_mod { fn set_priority(prio: crate::interrupt::Priority) { Self::IRQ.set_priority(prio) } + + /// Set the interrupt priority with an already-acquired critical section + #[inline] + fn set_priority_with_cs(cs: critical_section::CriticalSection, prio: crate::interrupt::Priority) { + Self::IRQ.set_priority_with_cs(cs, prio) + } } $( @@ -195,10 +202,29 @@ pub unsafe trait InterruptExt: InterruptNumber + Copy { /// Set the interrupt priority. #[inline] fn set_priority(self, prio: Priority) { - critical_section::with(|_| unsafe { + unsafe { let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(()); - nvic.set_priority(self, prio.into()) - }) + + // On thumbv6, set_priority must do a RMW to change 8bit in a 32bit reg. + #[cfg(armv6m)] + critical_section::with(|_| nvic.set_priority(self, prio.into())); + // On thumbv7+, set_priority does an atomic 8bit write, so no CS needed. + #[cfg(not(armv6m))] + nvic.set_priority(self, prio.into()); + } + } + + /// Set the interrupt priority with an already-acquired critical section + /// + /// Equivalent to `set_priority`, except you pass a `CriticalSection` to prove + /// you've already acquired a critical section. This prevents acquiring another + /// one, which saves code size. + #[inline] + fn set_priority_with_cs(self, _cs: CriticalSection, prio: Priority) { + unsafe { + let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(()); + nvic.set_priority(self, prio.into()); + } } } diff --git a/embassy-hal-internal/src/lib.rs b/embassy-hal-internal/src/lib.rs index 3640ea18..f3d59e58 100644 --- a/embassy-hal-internal/src/lib.rs +++ b/embassy-hal-internal/src/lib.rs @@ -10,7 +10,6 @@ pub mod drop; mod macros; mod peripheral; pub mod ratio; -pub mod ring_buffer; pub use peripheral::{Peripheral, PeripheralRef}; #[cfg(feature = "cortex-m")] diff --git a/embassy-hal-internal/src/macros.rs b/embassy-hal-internal/src/macros.rs index 0eea4b66..97df3895 100644 --- a/embassy-hal-internal/src/macros.rs +++ b/embassy-hal-internal/src/macros.rs @@ -48,17 +48,23 @@ macro_rules! peripherals_struct { ///Returns all the peripherals *once* #[inline] pub(crate) fn take() -> Self { + critical_section::with(Self::take_with_cs) + } + ///Returns all the peripherals *once* + #[inline] + pub(crate) fn take_with_cs(_cs: critical_section::CriticalSection) -> Self { #[no_mangle] static mut _EMBASSY_DEVICE_PERIPHERALS: bool = false; - critical_section::with(|_| unsafe { + // safety: OK because we're inside a CS. + unsafe { if _EMBASSY_DEVICE_PERIPHERALS { panic!("init called more than once!") } _EMBASSY_DEVICE_PERIPHERALS = true; Self::steal() - }) + } } } diff --git a/embassy-hal-internal/src/ring_buffer.rs b/embassy-hal-internal/src/ring_buffer.rs deleted file mode 100644 index fcad68bb..00000000 --- a/embassy-hal-internal/src/ring_buffer.rs +++ /dev/null @@ -1,136 +0,0 @@ -pub struct RingBuffer<'a> { - buf: &'a mut [u8], - start: usize, - end: usize, - empty: bool, -} - -impl<'a> RingBuffer<'a> { - pub fn new(buf: &'a mut [u8]) -> Self { - Self { - buf, - start: 0, - end: 0, - empty: true, - } - } - - pub fn push_buf(&mut self) -> &mut [u8] { - if self.start == self.end && !self.empty { - trace!(" ringbuf: push_buf empty"); - return &mut self.buf[..0]; - } - - let n = if self.start <= self.end { - self.buf.len() - self.end - } else { - self.start - self.end - }; - - trace!(" ringbuf: push_buf {:?}..{:?}", self.end, self.end + n); - &mut self.buf[self.end..self.end + n] - } - - pub fn push(&mut self, n: usize) { - trace!(" ringbuf: push {:?}", n); - if n == 0 { - return; - } - - self.end = self.wrap(self.end + n); - self.empty = false; - } - - pub fn pop_buf(&mut self) -> &mut [u8] { - if self.empty { - trace!(" ringbuf: pop_buf empty"); - return &mut self.buf[..0]; - } - - let n = if self.end <= self.start { - self.buf.len() - self.start - } else { - self.end - self.start - }; - - trace!(" ringbuf: pop_buf {:?}..{:?}", self.start, self.start + n); - &mut self.buf[self.start..self.start + n] - } - - pub fn pop(&mut self, n: usize) { - trace!(" ringbuf: pop {:?}", n); - if n == 0 { - return; - } - - self.start = self.wrap(self.start + n); - self.empty = self.start == self.end; - } - - pub fn is_full(&self) -> bool { - self.start == self.end && !self.empty - } - - pub fn is_empty(&self) -> bool { - self.empty - } - - pub fn clear(&mut self) { - self.start = 0; - self.end = 0; - self.empty = true; - } - - fn wrap(&self, n: usize) -> usize { - assert!(n <= self.buf.len()); - if n == self.buf.len() { - 0 - } else { - n - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn push_pop() { - let mut b = [0; 4]; - let mut rb = RingBuffer::new(&mut b); - let buf = rb.push_buf(); - assert_eq!(4, buf.len()); - buf[0] = 1; - buf[1] = 2; - buf[2] = 3; - buf[3] = 4; - rb.push(4); - - let buf = rb.pop_buf(); - assert_eq!(4, buf.len()); - assert_eq!(1, buf[0]); - rb.pop(1); - - let buf = rb.pop_buf(); - assert_eq!(3, buf.len()); - assert_eq!(2, buf[0]); - rb.pop(1); - - let buf = rb.pop_buf(); - assert_eq!(2, buf.len()); - assert_eq!(3, buf[0]); - rb.pop(1); - - let buf = rb.pop_buf(); - assert_eq!(1, buf.len()); - assert_eq!(4, buf[0]); - rb.pop(1); - - let buf = rb.pop_buf(); - assert_eq!(0, buf.len()); - - let buf = rb.push_buf(); - assert_eq!(4, buf.len()); - } -} diff --git a/embassy-lora/Cargo.toml b/embassy-lora/Cargo.toml index 88f815cd..6cdacd9c 100644 --- a/embassy-lora/Cargo.toml +++ b/embassy-lora/Cargo.toml @@ -20,7 +20,7 @@ defmt = ["dep:defmt", "lorawan-device/defmt"] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true } +embassy-time = { version = "0.1.4", path = "../embassy-time", optional = true } embassy-sync = { version = "0.3.0", path = "../embassy-sync" } embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", default-features = false, optional = true } embedded-hal-async = { version = "=1.0.0-rc.1" } diff --git a/embassy-lora/src/lib.rs b/embassy-lora/src/lib.rs index c23d1d0d..0a9cea16 100644 --- a/embassy-lora/src/lib.rs +++ b/embassy-lora/src/lib.rs @@ -1,5 +1,5 @@ #![no_std] -#![feature(async_fn_in_trait, impl_trait_projections)] +#![feature(async_fn_in_trait)] //! embassy-lora holds LoRa-specific functionality. pub(crate) mod fmt; diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml index 8de8eade..b93716d0 100644 --- a/embassy-net-adin1110/Cargo.toml +++ b/embassy-net-adin1110/Cargo.toml @@ -17,7 +17,7 @@ embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" } embedded-hal-async = { version = "=1.0.0-rc.1" } embedded-hal-bus = { version = "=0.1.0-rc.1", features = ["async"] } embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" } -embassy-time = { version = "0.1.3" } +embassy-time = { version = "0.1.4", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } bitfield = "0.14.0" diff --git a/embassy-net-enc28j60/Cargo.toml b/embassy-net-enc28j60/Cargo.toml index 161d055c..e50fd0e6 100644 --- a/embassy-net-enc28j60/Cargo.toml +++ b/embassy-net-enc28j60/Cargo.toml @@ -11,7 +11,7 @@ edition = "2021" embedded-hal = { version = "1.0.0-rc.1" } embedded-hal-async = { version = "=1.0.0-rc.1" } embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } -embassy-time = { version = "0.1.3", path = "../embassy-time" } +embassy-time = { version = "0.1.4", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } defmt = { version = "0.3", optional = true } diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml index 54cd8859..a0f53c6a 100644 --- a/embassy-net-esp-hosted/Cargo.toml +++ b/embassy-net-esp-hosted/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -embassy-time = { version = "0.1.3", path = "../embassy-time" } +embassy-time = { version = "0.1.4", path = "../embassy-time" } embassy-sync = { version = "0.3.0", path = "../embassy-sync"} embassy-futures = { version = "0.1.0", path = "../embassy-futures"} embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"} diff --git a/embassy-net-ppp/Cargo.toml b/embassy-net-ppp/Cargo.toml index da09f780..453da436 100644 --- a/embassy-net-ppp/Cargo.toml +++ b/embassy-net-ppp/Cargo.toml @@ -15,7 +15,7 @@ log = ["dep:log", "ppproto/log"] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -embedded-io-async = { version = "0.5.0" } +embedded-io-async = { version = "0.6.0" } embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } ppproto = { version = "0.1.2"} diff --git a/embassy-net-ppp/src/lib.rs b/embassy-net-ppp/src/lib.rs index 66496ee0..54a98c95 100644 --- a/embassy-net-ppp/src/lib.rs +++ b/embassy-net-ppp/src/lib.rs @@ -11,7 +11,7 @@ use core::mem::MaybeUninit; use embassy_futures::select::{select, Either}; use embassy_net_driver_channel as ch; use embassy_net_driver_channel::driver::LinkState; -use embedded_io_async::{BufRead, Write, WriteAllError}; +use embedded_io_async::{BufRead, Write}; use ppproto::pppos::{BufferFullError, PPPoS, PPPoSAction}; pub use ppproto::{Config, Ipv4Status}; @@ -49,23 +49,12 @@ pub enum RunError { Read(E), /// Writing to the serial port failed. Write(E), - /// Writing to the serial port wrote zero bytes, indicating it can't accept more data. - WriteZero, /// Writing to the serial got EOF. Eof, /// PPP protocol was terminated by the peer Terminated, } -impl From> for RunError { - fn from(value: WriteAllError) -> Self { - match value { - WriteAllError::Other(e) => Self::Write(e), - WriteAllError::WriteZero => Self::WriteZero, - } - } -} - impl<'d> Runner<'d> { /// You must call this in a background task for the driver to operate. /// @@ -125,7 +114,7 @@ impl<'d> Runner<'d> { buf[..pkt.len()].copy_from_slice(pkt); rx_chan.rx_done(pkt.len()); } - PPPoSAction::Transmit(n) => rw.write_all(&tx_buf[..n]).await?, + PPPoSAction::Transmit(n) => rw.write_all(&tx_buf[..n]).await.map_err(RunError::Write)?, } let status = ppp.status(); @@ -148,7 +137,7 @@ impl<'d> Runner<'d> { } Either::Second(pkt) => { match ppp.send(pkt, &mut tx_buf) { - Ok(n) => rw.write_all(&tx_buf[..n]).await?, + Ok(n) => rw.write_all(&tx_buf[..n]).await.map_err(RunError::Write)?, Err(BufferFullError) => unreachable!(), } tx_chan.tx_done(); diff --git a/embassy-net-wiznet/Cargo.toml b/embassy-net-wiznet/Cargo.toml index afa0d5cd..31836e1d 100644 --- a/embassy-net-wiznet/Cargo.toml +++ b/embassy-net-wiznet/Cargo.toml @@ -11,7 +11,7 @@ edition = "2021" embedded-hal = { version = "1.0.0-rc.1" } embedded-hal-async = { version = "=1.0.0-rc.1" } embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" } -embassy-time = { version = "0.1.3", path = "../embassy-time" } +embassy-time = { version = "0.1.4", path = "../embassy-time" } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } defmt = { version = "0.3", optional = true } diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 8aca92a6..8fcbef83 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -33,6 +33,7 @@ udp = ["smoltcp/socket-udp"] tcp = ["smoltcp/socket-tcp"] dns = ["smoltcp/socket-dns", "smoltcp/proto-dns"] dhcpv4 = ["proto-ipv4", "medium-ethernet", "smoltcp/socket-dhcpv4"] +dhcpv4-hostname = ["dhcpv4"] proto-ipv4 = ["smoltcp/proto-ipv4"] proto-ipv6 = ["smoltcp/proto-ipv6"] medium-ethernet = ["smoltcp/medium-ethernet"] @@ -51,9 +52,9 @@ smoltcp = { version = "0.10.0", default-features = false, features = [ ] } embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } -embassy-time = { version = "0.1.3", path = "../embassy-time" } +embassy-time = { version = "0.1.4", path = "../embassy-time" } embassy-sync = { version = "0.3.0", path = "../embassy-sync" } -embedded-io-async = { version = "0.5.0", optional = true } +embedded-io-async = { version = "0.6.0", optional = true } managed = { version = "0.8.0", default-features = false, features = [ "map" ] } heapless = { version = "0.7.5", default-features = false } @@ -62,5 +63,4 @@ generic-array = { version = "0.14.4", default-features = false } stable_deref_trait = { version = "1.2.0", default-features = false } futures = { version = "0.3.17", default-features = false, features = [ "async-await" ] } atomic-pool = "1.0" -embedded-nal-async = { version = "0.5.0", optional = true } -atomic-polyfill = { version = "1.0" } +embedded-nal-async = { version = "0.6.0", optional = true } diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 0d7ac47a..a0ad33c6 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -1,5 +1,5 @@ #![cfg_attr(not(feature = "std"), no_std)] -#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections))] +#![cfg_attr(feature = "nightly", feature(async_fn_in_trait))] #![warn(missing_docs)] #![doc = include_str!("../README.md")] @@ -39,7 +39,7 @@ use smoltcp::socket::dhcpv4::{self, RetryConfig}; pub use smoltcp::wire::EthernetAddress; #[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154", feature = "medium-ip"))] pub use smoltcp::wire::HardwareAddress; -#[cfg(feature = "udp")] +#[cfg(any(feature = "udp", feature = "tcp"))] pub use smoltcp::wire::IpListenEndpoint; #[cfg(feature = "medium-ieee802154")] pub use smoltcp::wire::{Ieee802154Address, Ieee802154Frame}; @@ -56,12 +56,22 @@ const LOCAL_PORT_MIN: u16 = 1025; const LOCAL_PORT_MAX: u16 = 65535; #[cfg(feature = "dns")] const MAX_QUERIES: usize = 4; +#[cfg(feature = "dhcpv4-hostname")] +const MAX_HOSTNAME_LEN: usize = 32; /// Memory resources needed for a network stack. pub struct StackResources { sockets: [SocketStorage<'static>; SOCK], #[cfg(feature = "dns")] queries: [Option; MAX_QUERIES], + #[cfg(feature = "dhcpv4-hostname")] + hostname: core::cell::UnsafeCell, +} + +#[cfg(feature = "dhcpv4-hostname")] +struct HostnameResources { + option: smoltcp::wire::DhcpOption<'static>, + data: [u8; MAX_HOSTNAME_LEN], } impl StackResources { @@ -73,6 +83,11 @@ impl StackResources { sockets: [SocketStorage::EMPTY; SOCK], #[cfg(feature = "dns")] queries: [INIT; MAX_QUERIES], + #[cfg(feature = "dhcpv4-hostname")] + hostname: core::cell::UnsafeCell::new(HostnameResources { + option: smoltcp::wire::DhcpOption { kind: 0, data: &[] }, + data: [0; MAX_HOSTNAME_LEN], + }), } } } @@ -104,6 +119,7 @@ pub struct StaticConfigV6 { /// DHCP configuration. #[cfg(feature = "dhcpv4")] #[derive(Debug, Clone, PartialEq, Eq)] +#[non_exhaustive] pub struct DhcpConfig { /// Maximum lease duration. /// @@ -120,6 +136,9 @@ pub struct DhcpConfig { pub server_port: u16, /// Client port. This is almost always 68. Do not change unless you know what you're doing. pub client_port: u16, + /// Our hostname. This will be sent to the DHCP server as Option 12. + #[cfg(feature = "dhcpv4-hostname")] + pub hostname: Option>, } #[cfg(feature = "dhcpv4")] @@ -131,6 +150,8 @@ impl Default for DhcpConfig { ignore_naks: Default::default(), server_port: smoltcp::wire::DHCP_SERVER_PORT, client_port: smoltcp::wire::DHCP_CLIENT_PORT, + #[cfg(feature = "dhcpv4-hostname")] + hostname: None, } } } @@ -232,6 +253,8 @@ struct Inner { dns_socket: SocketHandle, #[cfg(feature = "dns")] dns_waker: WakerRegistration, + #[cfg(feature = "dhcpv4-hostname")] + hostname: &'static mut core::cell::UnsafeCell, } pub(crate) struct SocketStack { @@ -307,6 +330,8 @@ impl Stack { )), #[cfg(feature = "dns")] dns_waker: WakerRegistration::new(), + #[cfg(feature = "dhcpv4-hostname")] + hostname: &mut resources.hostname, }; #[cfg(feature = "proto-ipv4")] @@ -484,7 +509,10 @@ impl Stack { self.with_mut(|s, i| { let socket = s.sockets.get_mut::(i.dns_socket); match socket.start_query(s.iface.context(), name, qtype) { - Ok(handle) => Poll::Ready(Ok(handle)), + Ok(handle) => { + s.waker.wake(); + Poll::Ready(Ok(handle)) + } Err(dns::StartQueryError::NoFreeSlot) => { i.dns_waker.register(cx.waker()); Poll::Pending @@ -673,6 +701,25 @@ impl Inner { socket.set_max_lease_duration(c.max_lease_duration.map(crate::time::duration_to_smoltcp)); socket.set_ports(c.server_port, c.client_port); socket.set_retry_config(c.retry_config); + + socket.set_outgoing_options(&[]); + #[cfg(feature = "dhcpv4-hostname")] + if let Some(h) = c.hostname { + // safety: we just did set_outgoing_options([]) so we know the socket is no longer holding a reference. + let hostname = unsafe { &mut *self.hostname.get() }; + + // create data + // safety: we know the buffer lives forever, new borrows the StackResources for 'static. + // also we won't modify it until next call to this function. + hostname.data[..h.len()].copy_from_slice(h.as_bytes()); + let data: &[u8] = &hostname.data[..h.len()]; + let data: &'static [u8] = unsafe { core::mem::transmute(data) }; + + // set the option. + hostname.option = smoltcp::wire::DhcpOption { data, kind: 12 }; + socket.set_outgoing_options(core::slice::from_ref(&hostname.option)); + } + socket.reset(); } _ => { diff --git a/embassy-net/src/tcp.rs b/embassy-net/src/tcp.rs index a12fd382..b5615cb6 100644 --- a/embassy-net/src/tcp.rs +++ b/embassy-net/src/tcp.rs @@ -579,11 +579,10 @@ mod embedded_io_impls { /// TCP client compatible with `embedded-nal-async` traits. #[cfg(feature = "nightly")] pub mod client { - use core::cell::UnsafeCell; + use core::cell::{Cell, UnsafeCell}; use core::mem::MaybeUninit; use core::ptr::NonNull; - use atomic_polyfill::{AtomicBool, Ordering}; use embedded_nal_async::IpAddr; use super::*; @@ -702,15 +701,13 @@ pub mod client { } } - unsafe impl Sync for TcpClientState {} - struct Pool { - used: [AtomicBool; N], + used: [Cell; N], data: [UnsafeCell>; N], } impl Pool { - const VALUE: AtomicBool = AtomicBool::new(false); + const VALUE: Cell = Cell::new(false); const UNINIT: UnsafeCell> = UnsafeCell::new(MaybeUninit::uninit()); const fn new() -> Self { @@ -724,7 +721,9 @@ pub mod client { impl Pool { fn alloc(&self) -> Option> { for n in 0..N { - if self.used[n].swap(true, Ordering::SeqCst) == false { + // this can't race because Pool is not Sync. + if !self.used[n].get() { + self.used[n].set(true); let p = self.data[n].get() as *mut T; return Some(unsafe { NonNull::new_unchecked(p) }); } @@ -738,7 +737,7 @@ pub mod client { let n = p.as_ptr().offset_from(origin); assert!(n >= 0); assert!((n as usize) < N); - self.used[n as usize].store(false, Ordering::SeqCst); + self.used[n as usize].set(false); } } } diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 3c706b47..bd96bc15 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml @@ -94,7 +94,7 @@ _gpio-p1 = [] _nrf52832_anomaly_109 = [] [dependencies] -embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true } +embassy-time = { version = "0.1.4", path = "../embassy-time", optional = true } embassy-sync = { version = "0.3.0", path = "../embassy-sync" } embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-3"] } embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } @@ -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-1 = { package = "embedded-hal", version = "=1.0.0-rc.1", optional = true} embedded-hal-async = { version = "=1.0.0-rc.1", optional = true} -embedded-io = { version = "0.5.0" } -embedded-io-async = { version = "0.5.0", optional = true } +embedded-io = { version = "0.6.0" } +embedded-io-async = { version = "0.6.0", optional = true } defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 9c4b6569..2cc83d74 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -1,5 +1,5 @@ #![no_std] -#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections))] +#![cfg_attr(feature = "nightly", feature(async_fn_in_trait))] #![doc = include_str!("../README.md")] #![warn(missing_docs)] diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 1147286f..02b11e19 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -60,7 +60,7 @@ unstable-traits = ["embedded-hal-1", "embedded-hal-nb"] [dependencies] embassy-sync = { version = "0.3.0", path = "../embassy-sync" } -embassy-time = { version = "0.1.3", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] } +embassy-time = { version = "0.1.4", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } @@ -75,8 +75,8 @@ cortex-m = "0.7.6" critical-section = "1.1" futures = { version = "0.3.17", default-features = false, features = ["async-await"] } chrono = { version = "0.4", default-features = false, optional = true } -embedded-io = { version = "0.5.0" } -embedded-io-async = { version = "0.5.0", optional = true } +embedded-io = { version = "0.6.0" } +embedded-io-async = { version = "0.6.0", optional = true } embedded-storage = { version = "0.3" } embedded-storage-async = { version = "0.4.0", optional = true } rand_core = "0.6.4" diff --git a/embassy-rp/src/bootsel.rs b/embassy-rp/src/bootsel.rs new file mode 100644 index 00000000..540255ae --- /dev/null +++ b/embassy-rp/src/bootsel.rs @@ -0,0 +1,83 @@ +//! Boot Select button +//! +//! The RP2040 rom supports a BOOTSEL button that is used to enter the USB bootloader +//! if held during reset. To avoid wasting GPIO pins, the button is multiplexed onto +//! the CS pin of the QSPI flash, but that makes it somewhat expensive and complicated +//! to utilize outside of the rom's bootloader. +//! +//! This module provides functionality to poll BOOTSEL from an embassy application. + +use crate::flash::in_ram; + +impl crate::peripherals::BOOTSEL { + /// Polls the BOOTSEL button. Returns true if the button is pressed. + /// + /// Polling isn't cheap, as this function waits for core 1 to finish it's current + /// task and for any DMAs from flash to complete + pub fn is_pressed(&mut self) -> bool { + let mut cs_status = Default::default(); + + unsafe { in_ram(|| cs_status = ram_helpers::read_cs_status()) }.expect("Must be called from Core 0"); + + // bootsel is active low, so invert + !cs_status.infrompad() + } +} + +mod ram_helpers { + use rp_pac::io::regs::GpioStatus; + + /// Temporally reconfigures the CS gpio and returns the GpioStatus. + + /// This function runs from RAM so it can disable flash XIP. + /// + /// # Safety + /// + /// The caller must ensure flash is idle and will remain idle. + /// This function must live in ram. It uses inline asm to avoid any + /// potential calls to ABI functions that might be in flash. + #[inline(never)] + #[link_section = ".data.ram_func"] + #[cfg(target_arch = "arm")] + pub unsafe fn read_cs_status() -> GpioStatus { + let result: u32; + + // Magic value, used as both OEOVER::DISABLE and delay loop counter + let magic = 0x2000; + + core::arch::asm!( + ".equiv GPIO_STATUS, 0x0", + ".equiv GPIO_CTRL, 0x4", + + "ldr {orig_ctrl}, [{cs_gpio}, $GPIO_CTRL]", + + // The BOOTSEL pulls the flash's CS line low though a 1K resistor. + // this is weak enough to avoid disrupting normal operation. + // But, if we disable CS's output drive and allow it to float... + "str {val}, [{cs_gpio}, $GPIO_CTRL]", + + // ...then wait for the state to settle... + "1:", // ~4000 cycle delay loop + "subs {val}, #8", + "bne 1b", + + // ...we can read the current state of bootsel + "ldr {val}, [{cs_gpio}, $GPIO_STATUS]", + + // Finally, restore CS to normal operation so XIP can continue + "str {orig_ctrl}, [{cs_gpio}, $GPIO_CTRL]", + + cs_gpio = in(reg) rp_pac::IO_QSPI.gpio(1).as_ptr(), + orig_ctrl = out(reg) _, + val = inout(reg) magic => result, + options(nostack), + ); + + core::mem::transmute(result) + } + + #[cfg(not(target_arch = "arm"))] + pub unsafe fn read_cs_status() -> GpioStatus { + unimplemented!() + } +} diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs index 1c1c2449..8fb5542f 100644 --- a/embassy-rp/src/flash.rs +++ b/embassy-rp/src/flash.rs @@ -131,7 +131,7 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI let len = to - from; - unsafe { self.in_ram(|| ram_helpers::flash_range_erase(from, len))? }; + unsafe { in_ram(|| ram_helpers::flash_range_erase(from, len))? }; Ok(()) } @@ -156,7 +156,7 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI let unaligned_offset = offset as usize - start; - unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf))? } + unsafe { in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf))? } } let remaining_len = bytes.len() - start_padding; @@ -174,12 +174,12 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI if bytes.as_ptr() as usize >= 0x2000_0000 { let aligned_data = &bytes[start_padding..end_padding]; - unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, aligned_data))? } + unsafe { in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, aligned_data))? } } else { for chunk in bytes[start_padding..end_padding].chunks_exact(PAGE_SIZE) { let mut ram_buf = [0xFF_u8; PAGE_SIZE]; ram_buf.copy_from_slice(chunk); - unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, &ram_buf))? } + unsafe { in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, &ram_buf))? } aligned_offset += PAGE_SIZE; } } @@ -194,47 +194,15 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI let unaligned_offset = end_offset - (PAGE_SIZE - rem_offset); - unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf))? } + unsafe { in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf))? } } Ok(()) } - /// Make sure to uphold the contract points with rp2040-flash. - /// - interrupts must be disabled - /// - DMA must not access flash memory - unsafe fn in_ram(&mut self, operation: impl FnOnce()) -> Result<(), Error> { - // Make sure we're running on CORE0 - let core_id: u32 = pac::SIO.cpuid().read(); - if core_id != 0 { - return Err(Error::InvalidCore); - } - - // Make sure CORE1 is paused during the entire duration of the RAM function - crate::multicore::pause_core1(); - - critical_section::with(|_| { - // Wait for all DMA channels in flash to finish before ram operation - const SRAM_LOWER: u32 = 0x2000_0000; - for n in 0..crate::dma::CHANNEL_COUNT { - let ch = crate::pac::DMA.ch(n); - while ch.read_addr().read() < SRAM_LOWER && ch.ctrl_trig().read().busy() {} - } - // Wait for completion of any background reads - while pac::XIP_CTRL.stream_ctr().read().0 > 0 {} - - // Run our flash operation in RAM - operation(); - }); - - // Resume CORE1 execution - crate::multicore::resume_core1(); - Ok(()) - } - /// Read SPI flash unique ID pub fn blocking_unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> { - unsafe { self.in_ram(|| ram_helpers::flash_unique_id(uid))? }; + unsafe { in_ram(|| ram_helpers::flash_unique_id(uid))? }; Ok(()) } @@ -242,7 +210,7 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI pub fn blocking_jedec_id(&mut self) -> Result { let mut jedec = None; unsafe { - self.in_ram(|| { + in_ram(|| { jedec.replace(ram_helpers::flash_jedec_id()); })?; }; @@ -871,6 +839,38 @@ mod ram_helpers { } } +/// Make sure to uphold the contract points with rp2040-flash. +/// - interrupts must be disabled +/// - DMA must not access flash memory +pub(crate) unsafe fn in_ram(operation: impl FnOnce()) -> Result<(), Error> { + // Make sure we're running on CORE0 + let core_id: u32 = pac::SIO.cpuid().read(); + if core_id != 0 { + return Err(Error::InvalidCore); + } + + // Make sure CORE1 is paused during the entire duration of the RAM function + crate::multicore::pause_core1(); + + critical_section::with(|_| { + // Wait for all DMA channels in flash to finish before ram operation + const SRAM_LOWER: u32 = 0x2000_0000; + for n in 0..crate::dma::CHANNEL_COUNT { + let ch = crate::pac::DMA.ch(n); + while ch.read_addr().read() < SRAM_LOWER && ch.ctrl_trig().read().busy() {} + } + // Wait for completion of any background reads + while pac::XIP_CTRL.stream_ctr().read().0 > 0 {} + + // Run our flash operation in RAM + operation(); + }); + + // Resume CORE1 execution + crate::multicore::resume_core1(); + Ok(()) +} + mod sealed { pub trait Instance {} pub trait Mode {} diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index ad9d4262..ee7e03e9 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -97,6 +97,12 @@ impl<'d, T: Pin> Input<'d, T> { Self { pin } } + /// Set the pin's Schmitt trigger. + #[inline] + pub fn set_schmitt(&mut self, enable: bool) { + self.pin.set_schmitt(enable) + } + #[inline] pub fn is_high(&self) -> bool { self.pin.is_high() @@ -216,7 +222,6 @@ fn IO_IRQ_QSPI() { #[must_use = "futures do nothing unless you `.await` or poll them"] struct InputFuture<'a, T: Pin> { pin: PeripheralRef<'a, T>, - level: InterruptTrigger, } impl<'d, T: Pin> InputFuture<'d, T> { @@ -243,7 +248,6 @@ impl<'d, T: Pin> InputFuture<'d, T> { .inte((pin.pin() / 8) as usize) .write_set(|w| match level { InterruptTrigger::LevelHigh => { - trace!("InputFuture::new enable LevelHigh for pin {}", pin.pin()); w.set_level_high(pin_group, true); } InterruptTrigger::LevelLow => { @@ -261,7 +265,7 @@ impl<'d, T: Pin> InputFuture<'d, T> { } }); - Self { pin, level } + Self { pin } } } @@ -297,14 +301,8 @@ impl<'d, T: Pin> Future for InputFuture<'d, T> { && !inte.level_high(pin_group) && !inte.level_low(pin_group) { - trace!( - "{:?} for pin {} was cleared, return Poll::Ready", - self.level, - self.pin.pin() - ); return Poll::Ready(()); } - trace!("InputFuture::poll return Poll::Pending"); Poll::Pending } } @@ -326,6 +324,18 @@ impl<'d, T: Pin> Output<'d, T> { Self { pin } } + /// Set the pin's drive strength. + #[inline] + pub fn set_drive_strength(&mut self, strength: Drive) { + self.pin.set_drive_strength(strength) + } + + // Set the pin's slew rate. + #[inline] + pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { + self.pin.set_slew_rate(slew_rate) + } + /// Set the output as high. #[inline] pub fn set_high(&mut self) { @@ -386,6 +396,18 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { Self { pin } } + /// Set the pin's drive strength. + #[inline] + pub fn set_drive_strength(&mut self, strength: Drive) { + self.pin.set_drive_strength(strength) + } + + // Set the pin's slew rate. + #[inline] + pub fn set_slew_rate(&mut self, slew_rate: SlewRate) { + self.pin.set_slew_rate(slew_rate) + } + /// Set the output as high. #[inline] pub fn set_high(&mut self) { @@ -541,6 +563,14 @@ impl<'d, T: Pin> Flex<'d, T> { }); } + /// Set the pin's Schmitt trigger. + #[inline] + pub fn set_schmitt(&mut self, enable: bool) { + self.pin.pad_ctrl().modify(|w| { + w.set_schmitt(enable); + }); + } + /// Put the pin into input mode. /// /// The pull setting is left unchanged. diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs index c358682c..4fe4b27e 100644 --- a/embassy-rp/src/i2c.rs +++ b/embassy-rp/src/i2c.rs @@ -6,13 +6,12 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; use pac::i2c; -use crate::gpio::sealed::Pin; use crate::gpio::AnyPin; use crate::interrupt::typelevel::{Binding, Interrupt}; use crate::{interrupt, pac, peripherals, Peripheral}; /// I2C error abort reason -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum AbortReason { /// A bus operation was not acknowledged, e.g. due to the addressed device @@ -27,7 +26,7 @@ pub enum AbortReason { } /// I2C error -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { /// I2C abort with error @@ -295,13 +294,24 @@ impl<'d, T: Instance> I2c<'d, T, Async> { pub async fn read_async(&mut self, addr: u16, buffer: &mut [u8]) -> Result<(), Error> { Self::setup(addr)?; - self.read_async_internal(buffer, false, true).await + self.read_async_internal(buffer, true, true).await } pub async fn write_async(&mut self, addr: u16, bytes: impl IntoIterator) -> Result<(), Error> { Self::setup(addr)?; self.write_async_internal(bytes, true).await } + + pub async fn write_read_async( + &mut self, + addr: u16, + bytes: impl IntoIterator, + 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 { @@ -318,6 +328,22 @@ impl interrupt::typelevel::Handler for InterruptHandl } } +pub(crate) fn set_up_i2c_pin<'d, P, T>(pin: &P) +where + P: core::ops::Deref, + T: crate::gpio::Pin, +{ + pin.gpio().ctrl().write(|w| w.set_funcsel(3)); + pin.pad_ctrl().write(|w| { + w.set_schmitt(true); + w.set_slewfast(false); + w.set_ie(true); + w.set_od(false); + w.set_pue(true); + w.set_pde(false); + }); +} + impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { fn new_inner( _peri: impl Peripheral

+ 'd, @@ -355,23 +381,8 @@ impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { p.ic_rx_tl().write(|w| w.set_rx_tl(0)); // Configure SCL & SDA pins - scl.gpio().ctrl().write(|w| w.set_funcsel(3)); - sda.gpio().ctrl().write(|w| w.set_funcsel(3)); - - scl.pad_ctrl().write(|w| { - w.set_schmitt(true); - w.set_ie(true); - w.set_od(false); - w.set_pue(true); - w.set_pde(false); - }); - sda.pad_ctrl().write(|w| { - w.set_schmitt(true); - w.set_ie(true); - w.set_od(false); - w.set_pue(true); - w.set_pde(false); - }); + set_up_i2c_pin(&scl); + set_up_i2c_pin(&sda); // Configure baudrate @@ -713,7 +724,7 @@ mod nightly { Self::setup(addr)?; self.write_async_internal(write.iter().cloned(), false).await?; - self.read_async_internal(read, false, true).await + self.read_async_internal(read, true, true).await } async fn transaction(&mut self, address: A, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> { diff --git a/embassy-rp/src/i2c_slave.rs b/embassy-rp/src/i2c_slave.rs index 6136d69c..9271ede3 100644 --- a/embassy-rp/src/i2c_slave.rs +++ b/embassy-rp/src/i2c_slave.rs @@ -5,12 +5,14 @@ use core::task::Poll; use embassy_hal_internal::into_ref; use pac::i2c; -use crate::i2c::{i2c_reserved_addr, AbortReason, Instance, InterruptHandler, SclPin, SdaPin, FIFO_SIZE}; +use crate::i2c::{ + i2c_reserved_addr, set_up_i2c_pin, AbortReason, Instance, InterruptHandler, SclPin, SdaPin, FIFO_SIZE, +}; use crate::interrupt::typelevel::{Binding, Interrupt}; use crate::{pac, Peripheral}; /// I2C error -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] pub enum Error { @@ -100,23 +102,8 @@ impl<'d, T: Instance> I2cSlave<'d, T> { p.ic_rx_tl().write(|w| w.set_rx_tl(0)); // Configure SCL & SDA pins - scl.gpio().ctrl().write(|w| w.set_funcsel(3)); - sda.gpio().ctrl().write(|w| w.set_funcsel(3)); - - scl.pad_ctrl().write(|w| { - w.set_schmitt(true); - w.set_ie(true); - w.set_od(false); - w.set_pue(true); - w.set_pde(false); - }); - sda.pad_ctrl().write(|w| { - w.set_schmitt(true); - w.set_ie(true); - w.set_od(false); - w.set_pue(true); - w.set_pde(false); - }); + set_up_i2c_pin(&scl); + set_up_i2c_pin(&sda); // Clear interrupts p.ic_clr_intr().read(); diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index c3561bbe..2728395b 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -1,5 +1,5 @@ #![no_std] -#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections))] +#![cfg_attr(feature = "nightly", feature(async_fn_in_trait))] // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; @@ -10,6 +10,7 @@ mod critical_section_impl; mod intrinsics; pub mod adc; +pub mod bootsel; pub mod clocks; pub mod dma; pub mod flash; @@ -193,6 +194,7 @@ embassy_hal_internal::peripherals! { PIO1, WATCHDOG, + BOOTSEL, } macro_rules! select_bootloader { diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index e57b7259..645d703d 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs @@ -490,8 +490,6 @@ impl interrupt::typelevel::Handler for BufferedInterr w.set_oeic(ris.oeris()); }); - trace!("on_interrupt ris={:#X}", ris.0); - // Errors if ris.feris() { warn!("Framing error"); diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index 3b10b7c5..b9d7776e 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -13,7 +13,7 @@ features = ["stm32wb55rg"] [dependencies] embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32" } embassy-sync = { version = "0.3.0", path = "../embassy-sync" } -embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true } +embassy-time = { version = "0.1.4", path = "../embassy-time", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = { version = "0.1.0", path = "../embassy-hal-internal" } embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 87f9083b..b18cafb8 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -33,7 +33,7 @@ flavors = [ [dependencies] embassy-sync = { version = "0.3.0", path = "../embassy-sync" } -embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true } +embassy-time = { version = "0.1.4", path = "../embassy-time", optional = true } embassy-futures = { version = "0.1.0", path = "../embassy-futures" } embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] } embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" } @@ -58,16 +58,14 @@ rand_core = "0.6.3" sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } critical-section = "1.1" -atomic-polyfill = "1.0.1" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8ee2862086886cd8ebaf5fd5e3bd6cfbe5baa840" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e6e51db6cdd7d533e52ca7a3237f7816a0486cd4" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" stm32-fmc = "0.3.0" -seq-macro = "0.3.0" cfg-if = "1.0.0" -embedded-io = { version = "0.5.0" } -embedded-io-async = { version = "0.5.0", optional = true } +embedded-io = { version = "0.6.0" } +embedded-io-async = { version = "0.6.0", optional = true } chrono = { version = "^0.4", default-features = false, optional = true} bit_field = "0.10.2" document-features = "0.2.7" @@ -78,7 +76,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-8ee2862086886cd8ebaf5fd5e3bd6cfbe5baa840", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e6e51db6cdd7d533e52ca7a3237f7816a0486cd4", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 76db0a76..3e1c76f3 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -5,9 +5,36 @@ use std::{env, fs}; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; -use stm32_metapac::metadata::{MemoryRegionKind, METADATA}; +use stm32_metapac::metadata::ir::{BlockItemInner, Enum, FieldSet}; +use stm32_metapac::metadata::{MemoryRegionKind, PeripheralRccRegister, METADATA}; fn main() { + let target = env::var("TARGET").unwrap(); + + if target.starts_with("thumbv6m-") { + println!("cargo:rustc-cfg=cortex_m"); + println!("cargo:rustc-cfg=armv6m"); + } else if target.starts_with("thumbv7m-") { + println!("cargo:rustc-cfg=cortex_m"); + println!("cargo:rustc-cfg=armv7m"); + } else if target.starts_with("thumbv7em-") { + println!("cargo:rustc-cfg=cortex_m"); + println!("cargo:rustc-cfg=armv7m"); + println!("cargo:rustc-cfg=armv7em"); // (not currently used) + } else if target.starts_with("thumbv8m.base") { + println!("cargo:rustc-cfg=cortex_m"); + println!("cargo:rustc-cfg=armv8m"); + println!("cargo:rustc-cfg=armv8m_base"); + } else if target.starts_with("thumbv8m.main") { + println!("cargo:rustc-cfg=cortex_m"); + println!("cargo:rustc-cfg=armv8m"); + println!("cargo:rustc-cfg=armv8m_main"); + } + + if target.ends_with("-eabihf") { + println!("cargo:rustc-cfg=has_fpu"); + } + let chip_name = match env::vars() .map(|(a, _)| a) .filter(|x| x.starts_with("CARGO_FEATURE_STM32")) @@ -50,12 +77,14 @@ fn main() { // We *shouldn't* have singletons for these, but the HAL currently requires // singletons, for using with RccPeripheral to enable/disable clocks to them. "rcc" => { - if r.version.starts_with("h5") || r.version.starts_with("h7") || r.version.starts_with("f4") { - singletons.push("MCO1".to_string()); - singletons.push("MCO2".to_string()); - } - if r.version.starts_with("l4") { - singletons.push("MCO".to_string()); + for pin in p.pins { + if pin.signal.starts_with("MCO") { + let name = pin.signal.replace('_', "").to_string(); + if !singletons.contains(&name) { + println!("cargo:rustc-cfg={}", name.to_ascii_lowercase()); + singletons.push(name); + } + } } singletons.push(p.name.to_string()); } @@ -359,6 +388,46 @@ fn main() { }); } + // ======== + // Generate rcc fieldset and enum maps + let rcc_enum_map: HashMap<&str, HashMap<&str, &Enum>> = { + let rcc_registers = METADATA + .peripherals + .iter() + .filter_map(|p| p.registers.as_ref()) + .find(|r| r.kind == "rcc") + .unwrap() + .ir; + + let rcc_blocks = rcc_registers.blocks.iter().find(|b| b.name == "Rcc").unwrap().items; + let rcc_fieldsets: HashMap<&str, &FieldSet> = rcc_registers.fieldsets.iter().map(|f| (f.name, f)).collect(); + let rcc_enums: HashMap<&str, &Enum> = rcc_registers.enums.iter().map(|e| (e.name, e)).collect(); + + rcc_blocks + .iter() + .filter_map(|b| match &b.inner { + BlockItemInner::Register(register) => register.fieldset.map(|f| (b.name, f)), + _ => None, + }) + .filter_map(|(b, f)| { + rcc_fieldsets.get(f).map(|f| { + ( + b, + f.fields + .iter() + .filter_map(|f| { + let enumm = f.enumm?; + let enumm = rcc_enums.get(enumm)?; + + Some((f.name, *enumm)) + }) + .collect(), + ) + }) + }) + .collect() + }; + // ======== // Generate RccPeripheral impls @@ -378,10 +447,8 @@ fn main() { let rst_reg = format_ident!("{}", rst.register.to_ascii_lowercase()); let set_rst_field = format_ident!("set_{}", rst.field.to_ascii_lowercase()); quote! { - critical_section::with(|_| { - crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true)); - crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false)); - }); + crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true)); + crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false)); } } None => TokenStream::new(), @@ -426,31 +493,82 @@ fn main() { (TokenStream::new(), TokenStream::new()) }; + let mux_for = |mux: Option<&'static PeripheralRccRegister>| { + // temporary hack to restrict the scope of the implementation to h5 + if !&chip_name.starts_with("stm32h5") { + return None; + } + + let mux = mux?; + let fieldset = rcc_enum_map.get(mux.register)?; + let enumm = fieldset.get(mux.field)?; + + Some((mux, *enumm)) + }; + + let clock_frequency = match mux_for(rcc.mux.as_ref()) { + Some((mux, rcc_enumm)) => { + let fieldset_name = format_ident!("{}", mux.register); + let field_name = format_ident!("{}", mux.field); + let enum_name = format_ident!("{}", rcc_enumm.name); + + let match_arms: TokenStream = rcc_enumm + .variants + .iter() + .filter(|v| v.name != "DISABLE") + .map(|v| { + let variant_name = format_ident!("{}", v.name); + + // temporary hack to restrict the scope of the implementation until clock names can be stabilized + let clock_name = format_ident!("{}", v.name.to_ascii_lowercase()); + + if v.name.starts_with("AHB") || v.name.starts_with("APB") { + quote! { + #enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name }, + } + } else { + quote! { + #enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name.unwrap() }, + } + } + }) + .collect(); + + quote! { + use crate::pac::rcc::vals::#enum_name; + + #[allow(unreachable_patterns)] + match crate::pac::RCC.#fieldset_name().read().#field_name() { + #match_arms + + _ => unreachable!(), + } + } + } + None => quote! { + unsafe { crate::rcc::get_freqs().#clk } + }, + }; + g.extend(quote! { impl crate::rcc::sealed::RccPeripheral for peripherals::#pname { fn frequency() -> crate::time::Hertz { - unsafe { crate::rcc::get_freqs().#clk } + #clock_frequency } - fn enable() { - critical_section::with(|_| { - #before_enable - #[cfg(feature = "low-power")] - crate::rcc::clock_refcount_add(); - crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); - #after_enable - }) - } - fn disable() { - critical_section::with(|_| { - #before_disable - crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false)); - #[cfg(feature = "low-power")] - crate::rcc::clock_refcount_sub(); - }) - } - fn reset() { + fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) { + #before_enable + #[cfg(feature = "low-power")] + crate::rcc::clock_refcount_add(_cs); + crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true)); + #after_enable #rst } + fn disable_with_cs(_cs: critical_section::CriticalSection) { + #before_disable + crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false)); + #[cfg(feature = "low-power")] + crate::rcc::clock_refcount_sub(_cs); + } } impl crate::rcc::RccPeripheral for peripherals::#pname {} @@ -458,12 +576,14 @@ fn main() { } } - let mut refcount_mod = TokenStream::new(); - for refcount_static in refcount_statics { - refcount_mod.extend(quote! { - pub(crate) static mut #refcount_static: u8 = 0; - }); - } + let refcount_mod: TokenStream = refcount_statics + .iter() + .map(|refcount_static| { + quote! { + pub(crate) static mut #refcount_static: u8 = 0; + } + }) + .collect(); g.extend(quote! { mod refcount_statics { @@ -719,12 +839,17 @@ fn main() { (("sdmmc", "D6"), quote!(crate::sdmmc::D6Pin)), (("sdmmc", "D6"), quote!(crate::sdmmc::D7Pin)), (("sdmmc", "D8"), quote!(crate::sdmmc::D8Pin)), - (("quadspi", "BK1_IO0"), quote!(crate::qspi::D0Pin)), - (("quadspi", "BK1_IO1"), quote!(crate::qspi::D1Pin)), - (("quadspi", "BK1_IO2"), quote!(crate::qspi::D2Pin)), - (("quadspi", "BK1_IO3"), quote!(crate::qspi::D3Pin)), + (("quadspi", "BK1_IO0"), quote!(crate::qspi::BK1D0Pin)), + (("quadspi", "BK1_IO1"), quote!(crate::qspi::BK1D1Pin)), + (("quadspi", "BK1_IO2"), quote!(crate::qspi::BK1D2Pin)), + (("quadspi", "BK1_IO3"), quote!(crate::qspi::BK1D3Pin)), + (("quadspi", "BK1_NCS"), quote!(crate::qspi::BK1NSSPin)), + (("quadspi", "BK2_IO0"), quote!(crate::qspi::BK2D0Pin)), + (("quadspi", "BK2_IO1"), quote!(crate::qspi::BK2D1Pin)), + (("quadspi", "BK2_IO2"), quote!(crate::qspi::BK2D2Pin)), + (("quadspi", "BK2_IO3"), quote!(crate::qspi::BK2D3Pin)), + (("quadspi", "BK2_NCS"), quote!(crate::qspi::BK2NSSPin)), (("quadspi", "CLK"), quote!(crate::qspi::SckPin)), - (("quadspi", "BK1_NCS"), quote!(crate::qspi::NSSPin)), ].into(); for p in METADATA.peripherals { @@ -746,25 +871,8 @@ fn main() { let af = pin.af.unwrap_or(0); // MCO is special - if pin.signal.starts_with("MCO_") { - // Supported in H7 only for now - if regs.version.starts_with("h5") - || regs.version.starts_with("h7") - || regs.version.starts_with("f4") - { - peri = format_ident!("{}", pin.signal.replace('_', "")); - } else { - continue; - } - } - - if pin.signal == "MCO" { - // Supported in H7 only for now - if regs.version.starts_with("l4") { - peri = format_ident!("MCO"); - } else { - continue; - } + if pin.signal.starts_with("MCO") { + peri = format_ident!("{}", pin.signal.replace('_', "")); } g.extend(quote! { @@ -805,6 +913,20 @@ fn main() { } } + if regs.kind == "opamp" { + if !pin.signal.starts_with("VP") { + continue; + } + + let peri = format_ident!("{}", p.name); + let pin_name = format_ident!("{}", pin.pin); + let ch: u8 = pin.signal.strip_prefix("VP").unwrap().parse().unwrap(); + + g.extend(quote! { + impl_opamp_pin!( #peri, #pin_name, #ch); + }) + } + // DAC is special if regs.kind == "dac" { let peri = format_ident!("{}", p.name); @@ -889,6 +1011,105 @@ fn main() { } } + // ======== + // Generate Div/Mul impls for RCC prescalers/dividers/multipliers. + let rcc_registers = METADATA + .peripherals + .iter() + .filter_map(|p| p.registers.as_ref()) + .find(|r| r.kind == "rcc") + .unwrap() + .ir; + + for e in rcc_registers.enums { + fn is_rcc_name(e: &str) -> bool { + match e { + "Pllp" | "Pllq" | "Pllr" | "Pllm" | "Plln" => true, + "Timpre" | "Pllrclkpre" => false, + e if e.ends_with("pre") || e.ends_with("pres") || e.ends_with("div") || e.ends_with("mul") => true, + _ => false, + } + } + + #[derive(Copy, Clone, Debug)] + struct Frac { + num: u32, + denom: u32, + } + + impl Frac { + fn simplify(self) -> Self { + let d = gcd(self.num, self.denom); + Self { + num: self.num / d, + denom: self.denom / d, + } + } + } + + fn gcd(a: u32, b: u32) -> u32 { + if b == 0 { + return a; + } + gcd(b, a % b) + } + + fn parse_num(n: &str) -> Result { + 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 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 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 diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index c1326481..ad0f1382 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs @@ -51,8 +51,7 @@ impl super::sealed::AdcPin for Temperature { impl<'d, T: Instance> Adc<'d, T> { pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayUs) -> Self { into_ref!(adc); - T::enable(); - T::reset(); + T::enable_and_reset(); T::regs().cr2().modify(|reg| reg.set_adon(true)); // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’) diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index 7c13f810..6f59c230 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -64,8 +64,7 @@ impl<'d, T: Instance> Adc<'d, T> { into_ref!(adc); - T::enable(); - T::reset(); + T::enable_and_reset(); // Enable the adc regulator T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE)); diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 365738a3..3e2980bf 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -74,9 +74,9 @@ pub(crate) mod sealed { } } -#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v4, adc_f3)))] +#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_g0)))] pub trait Instance: sealed::Instance + crate::Peripheral

{} -#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v4, adc_f3))] +#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_g0))] pub trait Instance: sealed::Instance + crate::Peripheral

+ crate::rcc::RccPeripheral {} pub trait AdcPin: sealed::AdcPin {} diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index fded26e4..852b027d 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -61,8 +61,7 @@ impl<'d, T: Instance> Adc<'d, T> { delay: &mut impl DelayUs, ) -> Self { into_ref!(adc); - T::enable(); - T::reset(); + T::enable_and_reset(); // Delay 1μs when using HSI14 as the ADC clock. // diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index a669013c..eda1324d 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -95,8 +95,7 @@ where { pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayUs) -> Self { into_ref!(adc); - T::enable(); - T::reset(); + T::enable_and_reset(); let presc = Prescaler::from_pclk2(T::frequency()); T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre())); diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 011ecc28..281a99f7 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -9,19 +9,6 @@ pub const VREF_DEFAULT_MV: u32 = 3300; /// VREF voltage used for factory calibration of VREFINTCAL register. pub const VREF_CALIB_MV: u32 = 3000; -/// Sadly we cannot use `RccPeripheral::enable` since devices are quite inconsistent ADC clock -/// configuration. -fn enable() { - critical_section::with(|_| { - #[cfg(any(stm32h7, stm32wl))] - crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true)); - #[cfg(stm32g0)] - crate::pac::RCC.apbenr2().modify(|w| w.set_adcen(true)); - #[cfg(any(stm32l4, stm32l5, stm32wb))] - crate::pac::RCC.ahb2enr().modify(|w| w.set_adcen(true)); - }); -} - pub struct VrefInt; impl AdcPin for VrefInt {} impl super::sealed::AdcPin for VrefInt { @@ -61,7 +48,7 @@ impl super::sealed::AdcPin for Vbat { impl<'d, T: Instance> Adc<'d, T> { pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayUs) -> Self { into_ref!(adc); - enable(); + T::enable_and_reset(); T::regs().cr().modify(|reg| { #[cfg(not(adc_g0))] reg.set_deeppwd(false); diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 655c0cb6..d74617cb 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -127,8 +127,7 @@ impl Prescaler { impl<'d, T: Instance> Adc<'d, T> { pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayUs) -> Self { embassy_hal_internal::into_ref!(adc); - T::enable(); - T::reset(); + T::enable_and_reset(); let prescaler = Prescaler::from_ker_ck(T::frequency()); diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 7ad13cec..0d4bf692 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -136,8 +136,7 @@ impl<'d, T: Instance> Can<'d, T> { rx.set_as_af(rx.af_num(), AFType::Input); tx.set_as_af(tx.af_num(), AFType::OutputPushPull); - T::enable(); - T::reset(); + T::enable_and_reset(); { use crate::pac::can::vals::{Errie, Fmpie, Tmeie}; diff --git a/embassy-stm32/src/crc/v1.rs b/embassy-stm32/src/crc/v1.rs index 154f2eb9..c0f58083 100644 --- a/embassy-stm32/src/crc/v1.rs +++ b/embassy-stm32/src/crc/v1.rs @@ -16,9 +16,7 @@ impl<'d> Crc<'d> { // Note: enable and reset come from RccPeripheral. // enable CRC clock in RCC. - CRC::enable(); - // Reset CRC to default values. - CRC::reset(); + CRC::enable_and_reset(); // Peripheral the peripheral let mut instance = Self { _peri: peripheral }; instance.reset(); diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs index de0c0875..b36f6018 100644 --- a/embassy-stm32/src/crc/v2v3.rs +++ b/embassy-stm32/src/crc/v2v3.rs @@ -69,16 +69,13 @@ impl<'d> Crc<'d> { /// Instantiates the CRC32 peripheral and initializes it to default values. pub fn new(peripheral: impl Peripheral

+ 'd, config: Config) -> Self { // Note: enable and reset come from RccPeripheral. - // enable CRC clock in RCC. - CRC::enable(); - // Reset CRC to default values. - CRC::reset(); + // reset to default values and enable CRC clock in RCC. + CRC::enable_and_reset(); into_ref!(peripheral); let mut instance = Self { _peripheral: peripheral, _config: config, }; - CRC::reset(); instance.reconfigure(); instance.reset(); instance diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index a2040b85..a3c7823c 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -11,7 +11,7 @@ use crate::{peripherals, Peripheral}; #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] -/// Curstom Errors +/// Custom Errors pub enum Error { UnconfiguredChannel, InvalidValue, @@ -255,8 +255,7 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> { ) -> Self { pin.set_as_analog(); into_ref!(peri, dma); - T::enable(); - T::reset(); + T::enable_and_reset(); let mut dac = Self { _peri: peri, dma }; @@ -366,8 +365,7 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> { ) -> Self { pin.set_as_analog(); into_ref!(_peri, dma); - T::enable(); - T::reset(); + T::enable_and_reset(); let mut dac = Self { phantom: PhantomData, @@ -483,8 +481,7 @@ impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> { pin_ch1.set_as_analog(); pin_ch2.set_as_analog(); into_ref!(peri, dma_ch1, dma_ch2); - T::enable(); - T::reset(); + T::enable_and_reset(); let mut dac_ch1 = DacCh1 { _peri: peri, @@ -563,35 +560,26 @@ pub trait DacPin: crate::gpio::Pin + 'static {} foreach_peripheral!( (dac, $inst:ident) => { - // H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented - #[cfg(rcc_h7)] - impl crate::rcc::sealed::RccPeripheral for peripherals::$inst { - fn frequency() -> crate::time::Hertz { - critical_section::with(|_| unsafe { crate::rcc::get_freqs().apb1 }) - } + // H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented + #[cfg(any(rcc_h7, rcc_h7rm0433))] + impl crate::rcc::sealed::RccPeripheral for peripherals::$inst { + fn frequency() -> crate::time::Hertz { + critical_section::with(|_| unsafe { crate::rcc::get_freqs().apb1 }) + } - fn reset() { - critical_section::with(|_| { - crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true)); - crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false)); - }) - } + fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) { + crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true)); + crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false)); + crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true)); + } - fn enable() { - critical_section::with(|_| { - crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true)); - }) - } + fn disable_with_cs(_cs: critical_section::CriticalSection) { + crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false)) + } + } - fn disable() { - critical_section::with(|_| { - crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false)) - }) - } - } - - #[cfg(rcc_h7)] - impl crate::rcc::RccPeripheral for peripherals::$inst {} + #[cfg(any(rcc_h7, rcc_h7rm0433))] + impl crate::rcc::RccPeripheral for peripherals::$inst {} impl crate::dac::sealed::Instance for peripherals::$inst { fn regs() -> &'static crate::pac::dac::Dac { diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs index 7497f4aa..b1223079 100644 --- a/embassy-stm32/src/dcmi.rs +++ b/embassy-stm32/src/dcmi.rs @@ -330,8 +330,7 @@ where use_embedded_synchronization: bool, edm: u8, ) -> Self { - T::reset(); - T::enable(); + T::enable_and_reset(); peri.regs().cr().modify(|r| { r.set_cm(true); // disable continuous mode (snapshot mode) diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index 20ff29be..a7422f66 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs @@ -2,10 +2,9 @@ use core::future::Future; use core::pin::Pin; -use core::sync::atomic::{fence, Ordering}; +use core::sync::atomic::{fence, AtomicUsize, Ordering}; use core::task::{Context, Poll, Waker}; -use atomic_polyfill::AtomicUsize; use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; @@ -78,10 +77,10 @@ impl State { static STATE: State = State::new(); /// safety: must be called only once -pub(crate) unsafe fn init(irq_priority: Priority) { +pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: Priority) { foreach_interrupt! { ($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => { - crate::interrupt::typelevel::$irq::set_priority(irq_priority); + crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, irq_priority); crate::interrupt::typelevel::$irq::enable(); }; } @@ -127,7 +126,13 @@ pub(crate) unsafe fn on_irq_inner(dma: pac::bdma::Dma, channel_num: usize, index } else if isr.tcif(channel_num) && cr.read().tcie() { // Acknowledge transfer complete interrupt dma.ifcr().write(|w| w.set_tcif(channel_num, true)); + #[cfg(not(armv6m))] STATE.complete_count[index].fetch_add(1, Ordering::Release); + #[cfg(armv6m)] + critical_section::with(|_| { + let x = STATE.complete_count[index].load(Ordering::Relaxed); + STATE.complete_count[index].store(x + 1, Ordering::Release); + }) } else { return; } @@ -391,7 +396,14 @@ impl<'a, C: Channel> DmaCtrl for DmaCtrlImpl<'a, C> { } fn reset_complete_count(&mut self) -> usize { - STATE.complete_count[self.0.index()].swap(0, Ordering::AcqRel) + #[cfg(not(armv6m))] + return STATE.complete_count[self.0.index()].swap(0, Ordering::AcqRel); + #[cfg(armv6m)] + return critical_section::with(|_| { + let x = STATE.complete_count[self.0.index()].load(Ordering::Acquire); + STATE.complete_count[self.0.index()].store(0, Ordering::Release); + x + }); } fn set_waker(&mut self, waker: &Waker) { diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index 5033ae47..cce0407c 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs @@ -154,10 +154,10 @@ impl State { static STATE: State = State::new(); /// safety: must be called only once -pub(crate) unsafe fn init(irq_priority: Priority) { +pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: Priority) { foreach_interrupt! { ($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => { - interrupt::typelevel::$irq::set_priority(irq_priority); + interrupt::typelevel::$irq::set_priority_with_cs(cs, irq_priority); interrupt::typelevel::$irq::enable(); }; } diff --git a/embassy-stm32/src/dma/dmamux.rs b/embassy-stm32/src/dma/dmamux.rs index 36fc0340..20601dc8 100644 --- a/embassy-stm32/src/dma/dmamux.rs +++ b/embassy-stm32/src/dma/dmamux.rs @@ -47,6 +47,6 @@ foreach_dma_channel! { } /// safety: must be called only once -pub(crate) unsafe fn init() { +pub(crate) unsafe fn init(_cs: critical_section::CriticalSection) { crate::_generated::init_dmamux(); } diff --git a/embassy-stm32/src/dma/gpdma.rs b/embassy-stm32/src/dma/gpdma.rs index 97cc200d..b811da1f 100644 --- a/embassy-stm32/src/dma/gpdma.rs +++ b/embassy-stm32/src/dma/gpdma.rs @@ -53,10 +53,10 @@ impl State { static STATE: State = State::new(); /// safety: must be called only once -pub(crate) unsafe fn init(irq_priority: Priority) { +pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: Priority) { foreach_interrupt! { ($peri:ident, gpdma, $block:ident, $signal_name:ident, $irq:ident) => { - crate::interrupt::typelevel::$irq::set_priority(irq_priority); + crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, irq_priority); crate::interrupt::typelevel::$irq::enable(); }; } diff --git a/embassy-stm32/src/dma/mod.rs b/embassy-stm32/src/dma/mod.rs index 4f1a58ae..29fced8f 100644 --- a/embassy-stm32/src/dma/mod.rs +++ b/embassy-stm32/src/dma/mod.rs @@ -56,16 +56,17 @@ pub(crate) fn slice_ptr_parts_mut(slice: *mut [T]) -> (usize, usize) { // safety: must be called only once at startup pub(crate) unsafe fn init( + cs: critical_section::CriticalSection, #[cfg(bdma)] bdma_priority: Priority, #[cfg(dma)] dma_priority: Priority, #[cfg(gpdma)] gpdma_priority: Priority, ) { #[cfg(bdma)] - bdma::init(bdma_priority); + bdma::init(cs, bdma_priority); #[cfg(dma)] - dma::init(dma_priority); + dma::init(cs, dma_priority); #[cfg(gpdma)] - gpdma::init(gpdma_priority); + gpdma::init(cs, gpdma_priority); #[cfg(dmamux)] - dmamux::init(); + dmamux::init(cs); } diff --git a/embassy-stm32/src/eth/generic_smi.rs b/embassy-stm32/src/eth/generic_smi.rs index 2ed46ca2..1e1094a1 100644 --- a/embassy-stm32/src/eth/generic_smi.rs +++ b/embassy-stm32/src/eth/generic_smi.rs @@ -41,39 +41,40 @@ mod phy_consts { } use self::phy_consts::*; -/// Generic SMI Ethernet PHY +/// Generic SMI Ethernet PHY implementation pub struct GenericSMI { + phy_addr: u8, #[cfg(feature = "time")] poll_interval: Duration, - #[cfg(not(feature = "time"))] - _private: (), } impl GenericSMI { - pub fn new() -> Self { + /// Construct the PHY. It assumes the address `phy_addr` in the SMI communication + pub fn new(phy_addr: u8) -> Self { Self { + phy_addr, #[cfg(feature = "time")] poll_interval: Duration::from_millis(500), - #[cfg(not(feature = "time"))] - _private: (), } } } unsafe impl PHY for GenericSMI { - /// Reset PHY and wait for it to come out of reset. fn phy_reset(&mut self, sm: &mut S) { - sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_RESET); - while sm.smi_read(PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {} + sm.smi_write(self.phy_addr, PHY_REG_BCR, PHY_REG_BCR_RESET); + while sm.smi_read(self.phy_addr, PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {} } - /// PHY initialisation. fn phy_init(&mut self, sm: &mut S) { // Clear WU CSR self.smi_write_ext(sm, PHY_REG_WUCSR, 0); // Enable auto-negotiation - sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_AN | PHY_REG_BCR_ANRST | PHY_REG_BCR_100M); + sm.smi_write( + self.phy_addr, + PHY_REG_BCR, + PHY_REG_BCR_AN | PHY_REG_BCR_ANRST | PHY_REG_BCR_100M, + ); } fn poll_link(&mut self, sm: &mut S, cx: &mut Context) -> bool { @@ -83,7 +84,7 @@ unsafe impl PHY for GenericSMI { #[cfg(feature = "time")] let _ = Timer::after(self.poll_interval).poll_unpin(cx); - let bsr = sm.smi_read(PHY_REG_BSR); + let bsr = sm.smi_read(self.phy_addr, PHY_REG_BSR); // No link without autonegotiate if bsr & PHY_REG_BSR_ANDONE == 0 { @@ -108,9 +109,9 @@ impl GenericSMI { // Writes a value to an extended PHY register in MMD address space fn smi_write_ext(&mut self, sm: &mut S, reg_addr: u16, reg_data: u16) { - sm.smi_write(PHY_REG_CTL, 0x0003); // set address - sm.smi_write(PHY_REG_ADDAR, reg_addr); - sm.smi_write(PHY_REG_CTL, 0x4003); // set data - sm.smi_write(PHY_REG_ADDAR, reg_data); + sm.smi_write(self.phy_addr, PHY_REG_CTL, 0x0003); // set address + sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_addr); + sm.smi_write(self.phy_addr, PHY_REG_CTL, 0x4003); // set data + sm.smi_write(self.phy_addr, PHY_REG_ADDAR, reg_data); } } diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs index 1e057235..556aadd7 100644 --- a/embassy-stm32/src/eth/mod.rs +++ b/embassy-stm32/src/eth/mod.rs @@ -134,9 +134,9 @@ impl<'a, 'd> embassy_net_driver::TxToken for TxToken<'a, 'd> { /// The methods cannot move out of self pub unsafe trait StationManagement { /// Read a register over SMI. - fn smi_read(&mut self, reg: u8) -> u16; + fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16; /// Write a register over SMI. - fn smi_write(&mut self, reg: u8, val: u16); + fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16); } /// Traits for an Ethernet PHY diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs index 4d19103d..631a9377 100644 --- a/embassy-stm32/src/eth/v1/mod.rs +++ b/embassy-stm32/src/eth/v1/mod.rs @@ -107,7 +107,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { tx_en: impl Peripheral

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

> + 'd, phy: P, mac_addr: [u8; 6], - phy_addr: u8, ) -> Self { into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); @@ -202,7 +201,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { station_management: EthernetStationManagement { peri: PhantomData, clock_range: clock_range, - phy_addr: phy_addr, }, mac_addr, }; @@ -242,15 +240,14 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { pub struct EthernetStationManagement { peri: PhantomData, clock_range: u8, - phy_addr: u8, } unsafe impl StationManagement for EthernetStationManagement { - fn smi_read(&mut self, reg: u8) -> u16 { + fn smi_read(&mut self, phy_addr: u8, reg: u8) -> u16 { let mac = ETH.ethernet_mac(); mac.macmdioar().modify(|w| { - w.set_pa(self.phy_addr); + w.set_pa(phy_addr); w.set_rda(reg); w.set_goc(0b11); // read w.set_cr(self.clock_range); @@ -260,12 +257,12 @@ unsafe impl StationManagement for EthernetStationManagement { mac.macmdiodr().read().md() } - fn smi_write(&mut self, reg: u8, val: u16) { + fn smi_write(&mut self, phy_addr: u8, reg: u8, val: u16) { let mac = ETH.ethernet_mac(); mac.macmdiodr().write(|w| w.set_md(val)); mac.macmdioar().modify(|w| { - w.set_pa(self.phy_addr); + w.set_pa(phy_addr); w.set_rda(reg); w.set_goc(0b01); // write w.set_cr(self.clock_range); diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index 62f32170..538791a5 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -367,7 +367,7 @@ macro_rules! enable_irq { } /// safety: must be called only once -pub(crate) unsafe fn init() { +pub(crate) unsafe fn init(_cs: critical_section::CriticalSection) { use crate::interrupt::typelevel::Interrupt; foreach_exti_irq!(enable_irq); diff --git a/embassy-stm32/src/flash/f0.rs b/embassy-stm32/src/flash/f0.rs index d011522b..1ab8435a 100644 --- a/embassy-stm32/src/flash/f0.rs +++ b/embassy-stm32/src/flash/f0.rs @@ -19,8 +19,10 @@ pub(crate) unsafe fn lock() { } pub(crate) unsafe fn unlock() { - pac::FLASH.keyr().write(|w| w.set_fkeyr(0x4567_0123)); - pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB)); + if pac::FLASH.cr().read().lock() { + pac::FLASH.keyr().write(|w| w.set_fkeyr(0x4567_0123)); + pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB)); + } } pub(crate) unsafe fn enable_blocking_write() { diff --git a/embassy-stm32/src/flash/f3.rs b/embassy-stm32/src/flash/f3.rs index 065369f6..7e6d7ca2 100644 --- a/embassy-stm32/src/flash/f3.rs +++ b/embassy-stm32/src/flash/f3.rs @@ -19,8 +19,10 @@ pub(crate) unsafe fn lock() { } pub(crate) unsafe fn unlock() { - pac::FLASH.keyr().write(|w| w.set_fkeyr(0x4567_0123)); - pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB)); + if pac::FLASH.cr().read().lock() { + pac::FLASH.keyr().write(|w| w.set_fkeyr(0x4567_0123)); + pac::FLASH.keyr().write(|w| w.set_fkeyr(0xCDEF_89AB)); + } } pub(crate) unsafe fn enable_blocking_write() { diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 913950fe..81deaa17 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -228,8 +228,10 @@ pub(crate) unsafe fn lock() { } pub(crate) unsafe fn unlock() { - pac::FLASH.keyr().write(|w| w.set_key(0x45670123)); - pac::FLASH.keyr().write(|w| w.set_key(0xCDEF89AB)); + if pac::FLASH.cr().read().lock() { + pac::FLASH.keyr().write(|w| w.set_key(0x45670123)); + pac::FLASH.keyr().write(|w| w.set_key(0xCDEF89AB)); + } } pub(crate) unsafe fn enable_write() { diff --git a/embassy-stm32/src/flash/f7.rs b/embassy-stm32/src/flash/f7.rs index 3a5bdf9c..b52231ca 100644 --- a/embassy-stm32/src/flash/f7.rs +++ b/embassy-stm32/src/flash/f7.rs @@ -19,8 +19,10 @@ pub(crate) unsafe fn lock() { } pub(crate) unsafe fn unlock() { - pac::FLASH.keyr().write(|w| w.set_key(0x4567_0123)); - pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB)); + if pac::FLASH.cr().read().lock() { + pac::FLASH.keyr().write(|w| w.set_key(0x4567_0123)); + pac::FLASH.keyr().write(|w| w.set_key(0xCDEF_89AB)); + } } pub(crate) unsafe fn enable_blocking_write() { diff --git a/embassy-stm32/src/flash/g0.rs b/embassy-stm32/src/flash/g0.rs index 3a457601..19a38897 100644 --- a/embassy-stm32/src/flash/g0.rs +++ b/embassy-stm32/src/flash/g0.rs @@ -24,8 +24,10 @@ pub(crate) unsafe fn unlock() { while pac::FLASH.sr().read().bsy() {} // Unlock flash - pac::FLASH.keyr().write(|w| w.set_keyr(0x4567_0123)); - pac::FLASH.keyr().write(|w| w.set_keyr(0xCDEF_89AB)); + if pac::FLASH.cr().read().lock() { + pac::FLASH.keyr().write(|w| w.set_keyr(0x4567_0123)); + pac::FLASH.keyr().write(|w| w.set_keyr(0xCDEF_89AB)); + } } pub(crate) unsafe fn enable_blocking_write() { diff --git a/embassy-stm32/src/flash/h7.rs b/embassy-stm32/src/flash/h7.rs index 625bf13f..b064fd6e 100644 --- a/embassy-stm32/src/flash/h7.rs +++ b/embassy-stm32/src/flash/h7.rs @@ -26,11 +26,15 @@ pub(crate) unsafe fn lock() { } pub(crate) unsafe fn unlock() { - pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0x4567_0123)); - pac::FLASH.bank(0).keyr().write(|w| w.set_keyr(0xCDEF_89AB)); + if 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(0xCDEF_89AB)); + } if is_dual_bank() { - pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0x4567_0123)); - pac::FLASH.bank(1).keyr().write(|w| w.set_keyr(0xCDEF_89AB)); + 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(0xCDEF_89AB)); + } } } diff --git a/embassy-stm32/src/flash/l.rs b/embassy-stm32/src/flash/l.rs index 24dcf99b..1db0da92 100644 --- a/embassy-stm32/src/flash/l.rs +++ b/embassy-stm32/src/flash/l.rs @@ -28,17 +28,23 @@ pub(crate) unsafe fn lock() { pub(crate) unsafe fn unlock() { #[cfg(any(flash_wl, flash_wb, flash_l4))] { - pac::FLASH.keyr().write(|w| w.set_keyr(0x4567_0123)); - pac::FLASH.keyr().write(|w| w.set_keyr(0xCDEF_89AB)); + if pac::FLASH.cr().read().lock() { + pac::FLASH.keyr().write(|w| w.set_keyr(0x4567_0123)); + pac::FLASH.keyr().write(|w| w.set_keyr(0xCDEF_89AB)); + } } #[cfg(any(flash_l0, flash_l1))] { - pac::FLASH.pekeyr().write(|w| w.set_pekeyr(0x89ABCDEF)); - pac::FLASH.pekeyr().write(|w| w.set_pekeyr(0x02030405)); + if pac::FLASH.pecr().read().pelock() { + pac::FLASH.pekeyr().write(|w| w.set_pekeyr(0x89ABCDEF)); + pac::FLASH.pekeyr().write(|w| w.set_pekeyr(0x02030405)); + } - pac::FLASH.prgkeyr().write(|w| w.set_prgkeyr(0x8C9DAEBF)); - pac::FLASH.prgkeyr().write(|w| w.set_prgkeyr(0x13141516)); + if pac::FLASH.pecr().read().prglock() { + pac::FLASH.prgkeyr().write(|w| w.set_prgkeyr(0x8C9DAEBF)); + pac::FLASH.prgkeyr().write(|w| w.set_prgkeyr(0x13141516)); + } } } diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs index 177e66a9..d6e25996 100644 --- a/embassy-stm32/src/fmc.rs +++ b/embassy-stm32/src/fmc.rs @@ -19,8 +19,7 @@ where const REGISTERS: *const () = T::REGS.as_ptr() as *const _; fn enable(&mut self) { - ::enable(); - ::reset(); + T::enable_and_reset(); } fn memory_controller_enable(&mut self) { diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index c709d46d..e1702b00 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -1,6 +1,7 @@ #![macro_use] use core::convert::Infallible; +use critical_section::CriticalSection; use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; use crate::pac::gpio::{self, vals}; @@ -757,9 +758,9 @@ foreach_pin!( }; ); -pub(crate) unsafe fn init() { +pub(crate) unsafe fn init(_cs: CriticalSection) { #[cfg(afio)] - ::enable(); + ::enable_and_reset_with_cs(_cs); crate::_generated::init_gpio(); } @@ -974,6 +975,18 @@ mod eh1 { type Error = Infallible; } + impl<'d, T: Pin> InputPin for OutputOpenDrain<'d, T> { + #[inline] + fn is_high(&self) -> Result { + Ok(self.is_high()) + } + + #[inline] + fn is_low(&self) -> Result { + Ok(self.is_low()) + } + } + impl<'d, T: Pin> OutputPin for OutputOpenDrain<'d, T> { #[inline] fn set_high(&mut self) -> Result<(), Self::Error> { diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs index c47b0c09..17096d48 100644 --- a/embassy-stm32/src/hrtim/mod.rs +++ b/embassy-stm32/src/hrtim/mod.rs @@ -157,8 +157,7 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> { fn new_inner(tim: impl Peripheral

+ 'd) -> Self { into_ref!(tim); - T::enable(); - ::reset(); + T::enable_and_reset(); #[cfg(stm32f334)] if unsafe { get_freqs() }.hrtim.is_some() { diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index b35678ed..dde1a504 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -7,14 +7,9 @@ use crate::interrupt; mod _version; pub use _version::*; -#[cfg(feature = "time")] -mod timeout; -#[cfg(feature = "time")] -pub use timeout::*; - use crate::peripherals; -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { Bus, diff --git a/embassy-stm32/src/i2c/timeout.rs b/embassy-stm32/src/i2c/timeout.rs deleted file mode 100644 index 103017cd..00000000 --- a/embassy-stm32/src/i2c/timeout.rs +++ /dev/null @@ -1,209 +0,0 @@ -use embassy_time::{Duration, Instant}; - -use super::{Error, I2c, Instance}; - -/// An I2C wrapper, which provides `embassy-time` based timeouts for all `embedded-hal` trait methods. -/// -/// This is useful for recovering from a shorted bus or a device stuck in a clock stretching state. -/// A regular [I2c] would freeze until condition is removed. -pub struct TimeoutI2c<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> { - i2c: &'a mut I2c<'d, T, TXDMA, RXDMA>, - timeout: Duration, -} - -fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> { - let deadline = Instant::now() + timeout; - move || { - if Instant::now() > deadline { - Err(Error::Timeout) - } else { - Ok(()) - } - } -} - -impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> { - pub fn new(i2c: &'a mut I2c<'d, T, TXDMA, RXDMA>, timeout: Duration) -> Self { - Self { i2c, timeout } - } - - // ========================= - // Async public API - - #[cfg(i2c_v2)] - pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> - where - TXDMA: crate::i2c::TxDma, - { - self.write_timeout(address, write, self.timeout).await - } - - #[cfg(i2c_v2)] - pub async fn write_timeout(&mut self, address: u8, write: &[u8], timeout: Duration) -> Result<(), Error> - where - TXDMA: crate::i2c::TxDma, - { - self.i2c.write_timeout(address, write, timeout_fn(timeout)).await - } - - #[cfg(i2c_v2)] - pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> - where - TXDMA: crate::i2c::TxDma, - { - self.write_vectored_timeout(address, write, self.timeout).await - } - - #[cfg(i2c_v2)] - pub async fn write_vectored_timeout(&mut self, address: u8, write: &[&[u8]], timeout: Duration) -> Result<(), Error> - where - TXDMA: crate::i2c::TxDma, - { - self.i2c - .write_vectored_timeout(address, write, timeout_fn(timeout)) - .await - } - - #[cfg(i2c_v2)] - pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> - where - RXDMA: crate::i2c::RxDma, - { - self.read_timeout(address, buffer, self.timeout).await - } - - #[cfg(i2c_v2)] - pub async fn read_timeout(&mut self, address: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error> - where - RXDMA: crate::i2c::RxDma, - { - self.i2c.read_timeout(address, buffer, timeout_fn(timeout)).await - } - - #[cfg(i2c_v2)] - pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> - where - TXDMA: super::TxDma, - RXDMA: super::RxDma, - { - self.write_read_timeout(address, write, read, self.timeout).await - } - - #[cfg(i2c_v2)] - pub async fn write_read_timeout( - &mut self, - address: u8, - write: &[u8], - read: &mut [u8], - timeout: Duration, - ) -> Result<(), Error> - where - TXDMA: super::TxDma, - RXDMA: super::RxDma, - { - self.i2c - .write_read_timeout(address, write, read, timeout_fn(timeout)) - .await - } - - // ========================= - // Blocking public API - - /// Blocking read with a custom timeout - pub fn blocking_read_timeout(&mut self, addr: u8, read: &mut [u8], timeout: Duration) -> Result<(), Error> { - self.i2c.blocking_read_timeout(addr, read, timeout_fn(timeout)) - } - - /// Blocking read with default timeout, provided in [`TimeoutI2c::new()`] - pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> { - self.blocking_read_timeout(addr, read, self.timeout) - } - - /// Blocking write with a custom timeout - pub fn blocking_write_timeout(&mut self, addr: u8, write: &[u8], timeout: Duration) -> Result<(), Error> { - self.i2c.blocking_write_timeout(addr, write, timeout_fn(timeout)) - } - - /// Blocking write with default timeout, provided in [`TimeoutI2c::new()`] - pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> { - self.blocking_write_timeout(addr, write, self.timeout) - } - - /// Blocking write-read with a custom timeout - pub fn blocking_write_read_timeout( - &mut self, - addr: u8, - write: &[u8], - read: &mut [u8], - timeout: Duration, - ) -> Result<(), Error> { - self.i2c - .blocking_write_read_timeout(addr, write, read, timeout_fn(timeout)) - } - - /// Blocking write-read with default timeout, provided in [`TimeoutI2c::new()`] - pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { - self.blocking_write_read_timeout(addr, write, read, self.timeout) - } -} - -impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Read - for TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> -{ - type Error = Error; - - fn read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_read(addr, read) - } -} - -impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::Write - for TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> -{ - type Error = Error; - - fn write(&mut self, addr: u8, write: &[u8]) -> Result<(), Self::Error> { - self.blocking_write(addr, write) - } -} - -impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> embedded_hal_02::blocking::i2c::WriteRead - for TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> -{ - type Error = Error; - - fn write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_write_read(addr, write, read) - } -} - -#[cfg(feature = "unstable-traits")] -mod eh1 { - use super::*; - - impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::ErrorType for TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> { - type Error = Error; - } - - impl<'a, 'd: 'a, T: Instance, TXDMA, RXDMA> embedded_hal_1::i2c::I2c for TimeoutI2c<'a, 'd, T, TXDMA, RXDMA> { - fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_read(address, read) - } - - fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { - self.blocking_write(address, write) - } - - fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_write_read(address, write, read) - } - - fn transaction( - &mut self, - _address: u8, - _operations: &mut [embedded_hal_1::i2c::Operation<'_>], - ) -> Result<(), Self::Error> { - todo!(); - } - } -} diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 0d2bfc06..ab59f5ab 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -56,8 +56,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { ) -> Self { into_ref!(scl, sda, tx_dma, rx_dma); - T::enable(); - T::reset(); + T::enable_and_reset(); scl.set_as_af_pull( scl.af_num(), diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 543d8f1b..fc6dcd6e 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -1,14 +1,21 @@ use core::cmp; +#[cfg(feature = "time")] use core::future::poll_fn; use core::marker::PhantomData; +#[cfg(feature = "time")] use core::task::Poll; use embassy_embedded_hal::SetConfig; +#[cfg(feature = "time")] use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; +#[cfg(feature = "time")] +use embassy_time::{Duration, Instant}; -use crate::dma::{NoDma, Transfer}; +use crate::dma::NoDma; +#[cfg(feature = "time")] +use crate::dma::Transfer; use crate::gpio::sealed::AFType; use crate::gpio::Pull; use crate::i2c::{Error, Instance, SclPin, SdaPin}; @@ -43,6 +50,8 @@ impl interrupt::typelevel::Handler for InterruptHandl pub struct Config { pub sda_pullup: bool, pub scl_pullup: bool, + #[cfg(feature = "time")] + pub transaction_timeout: Duration, } impl Default for Config { @@ -50,6 +59,8 @@ impl Default for Config { Self { sda_pullup: false, scl_pullup: false, + #[cfg(feature = "time")] + transaction_timeout: Duration::from_millis(100), } } } @@ -68,9 +79,12 @@ impl State { pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { _peri: PeripheralRef<'d, T>, + #[allow(dead_code)] tx_dma: PeripheralRef<'d, TXDMA>, #[allow(dead_code)] rx_dma: PeripheralRef<'d, RXDMA>, + #[cfg(feature = "time")] + timeout: Duration, } impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { @@ -86,8 +100,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { ) -> Self { into_ref!(peri, scl, sda, tx_dma, rx_dma); - T::enable(); - T::reset(); + T::enable_and_reset(); scl.set_as_af_pull( scl.af_num(), @@ -132,6 +145,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { _peri: peri, tx_dma, rx_dma, + #[cfg(feature = "time")] + timeout: config.transaction_timeout, } } @@ -422,6 +437,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { result } + #[cfg(feature = "time")] async fn write_dma_internal( &mut self, address: u8, @@ -512,6 +528,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { Ok(()) } + #[cfg(feature = "time")] async fn read_dma_internal( &mut self, address: u8, @@ -594,42 +611,41 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { // ========================= // Async public API + #[cfg(feature = "time")] pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> where TXDMA: crate::i2c::TxDma, { - self.write_timeout(address, write, || Ok(())).await + self.write_timeout(address, write, self.timeout).await } - pub async fn write_timeout( - &mut self, - address: u8, - write: &[u8], - check_timeout: impl Fn() -> Result<(), Error>, - ) -> Result<(), Error> + #[cfg(feature = "time")] + pub async fn write_timeout(&mut self, address: u8, write: &[u8], timeout: Duration) -> Result<(), Error> where TXDMA: crate::i2c::TxDma, { if write.is_empty() { - self.write_internal(address, write, true, check_timeout) + self.write_internal(address, write, true, timeout_fn(timeout)) } else { - self.write_dma_internal(address, write, true, true, check_timeout).await + embassy_time::with_timeout( + timeout, + self.write_dma_internal(address, write, true, true, timeout_fn(timeout)), + ) + .await + .unwrap_or(Err(Error::Timeout)) } } + #[cfg(feature = "time")] pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> where TXDMA: crate::i2c::TxDma, { - self.write_vectored_timeout(address, write, || Ok(())).await + self.write_vectored_timeout(address, write, self.timeout).await } - pub async fn write_vectored_timeout( - &mut self, - address: u8, - write: &[&[u8]], - check_timeout: impl Fn() -> Result<(), Error>, - ) -> Result<(), Error> + #[cfg(feature = "time")] + pub async fn write_vectored_timeout(&mut self, address: u8, write: &[&[u8]], timeout: Duration) -> Result<(), Error> where TXDMA: crate::i2c::TxDma, { @@ -644,67 +660,88 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { let next = iter.next(); let is_last = next.is_none(); - self.write_dma_internal(address, c, first, is_last, || check_timeout()) - .await?; + embassy_time::with_timeout( + timeout, + self.write_dma_internal(address, c, first, is_last, timeout_fn(timeout)), + ) + .await + .unwrap_or(Err(Error::Timeout))?; first = false; current = next; } Ok(()) } + #[cfg(feature = "time")] pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> where RXDMA: crate::i2c::RxDma, { - self.read_timeout(address, buffer, || Ok(())).await + self.read_timeout(address, buffer, self.timeout).await } - pub async fn read_timeout( - &mut self, - address: u8, - buffer: &mut [u8], - check_timeout: impl Fn() -> Result<(), Error>, - ) -> Result<(), Error> + #[cfg(feature = "time")] + pub async fn read_timeout(&mut self, address: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error> where RXDMA: crate::i2c::RxDma, { if buffer.is_empty() { - self.read_internal(address, buffer, false, check_timeout) + self.read_internal(address, buffer, false, timeout_fn(timeout)) } else { - self.read_dma_internal(address, buffer, false, check_timeout).await + embassy_time::with_timeout( + timeout, + self.read_dma_internal(address, buffer, false, timeout_fn(timeout)), + ) + .await + .unwrap_or(Err(Error::Timeout)) } } + #[cfg(feature = "time")] pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> where TXDMA: super::TxDma, RXDMA: super::RxDma, { - self.write_read_timeout(address, write, read, || Ok(())).await + self.write_read_timeout(address, write, read, self.timeout).await } + #[cfg(feature = "time")] pub async fn write_read_timeout( &mut self, address: u8, write: &[u8], read: &mut [u8], - check_timeout: impl Fn() -> Result<(), Error>, + timeout: Duration, ) -> Result<(), Error> where TXDMA: super::TxDma, RXDMA: super::RxDma, { + let start_instant = Instant::now(); + let check_timeout = timeout_fn(timeout); if write.is_empty() { - self.write_internal(address, write, false, || check_timeout())?; + self.write_internal(address, write, false, &check_timeout)?; } else { - self.write_dma_internal(address, write, true, true, || check_timeout()) - .await?; + embassy_time::with_timeout( + timeout, + self.write_dma_internal(address, write, true, true, &check_timeout), + ) + .await + .unwrap_or(Err(Error::Timeout))?; } + let time_left_until_timeout = timeout - Instant::now().duration_since(start_instant); + if read.is_empty() { - self.read_internal(address, read, true, check_timeout)?; + self.read_internal(address, read, true, &check_timeout)?; } else { - self.read_dma_internal(address, read, true, check_timeout).await?; + embassy_time::with_timeout( + time_left_until_timeout, + self.read_dma_internal(address, read, true, &check_timeout), + ) + .await + .unwrap_or(Err(Error::Timeout))?; } Ok(()) @@ -713,33 +750,73 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { // ========================= // Blocking public API + #[cfg(feature = "time")] + pub fn blocking_read_timeout(&mut self, address: u8, read: &mut [u8], timeout: Duration) -> Result<(), Error> { + self.read_internal(address, read, false, timeout_fn(timeout)) + // Automatic Stop + } + + #[cfg(not(feature = "time"))] pub fn blocking_read_timeout( &mut self, address: u8, read: &mut [u8], check_timeout: impl Fn() -> Result<(), Error>, ) -> Result<(), Error> { - self.read_internal(address, read, false, &check_timeout) + self.read_internal(address, read, false, check_timeout) // Automatic Stop } + #[cfg(feature = "time")] + pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { + self.blocking_read_timeout(address, read, self.timeout) + } + + #[cfg(not(feature = "time"))] pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { self.blocking_read_timeout(address, read, || Ok(())) } + #[cfg(feature = "time")] + pub fn blocking_write_timeout(&mut self, address: u8, write: &[u8], timeout: Duration) -> Result<(), Error> { + self.write_internal(address, write, true, timeout_fn(timeout)) + } + + #[cfg(not(feature = "time"))] pub fn blocking_write_timeout( &mut self, address: u8, write: &[u8], check_timeout: impl Fn() -> Result<(), Error>, ) -> Result<(), Error> { - self.write_internal(address, write, true, &check_timeout) + self.write_internal(address, write, true, check_timeout) } + #[cfg(feature = "time")] + pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { + self.blocking_write_timeout(address, write, self.timeout) + } + + #[cfg(not(feature = "time"))] pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { self.blocking_write_timeout(address, write, || Ok(())) } + #[cfg(feature = "time")] + pub fn blocking_write_read_timeout( + &mut self, + address: u8, + write: &[u8], + read: &mut [u8], + timeout: Duration, + ) -> Result<(), Error> { + let check_timeout = timeout_fn(timeout); + self.write_internal(address, write, false, &check_timeout)?; + self.read_internal(address, read, true, &check_timeout) + // Automatic Stop + } + + #[cfg(not(feature = "time"))] pub fn blocking_write_read_timeout( &mut self, address: u8, @@ -752,11 +829,17 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { // Automatic Stop } + #[cfg(feature = "time")] + pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { + self.blocking_write_read_timeout(address, write, read, self.timeout) + } + + #[cfg(not(feature = "time"))] pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { self.blocking_write_read_timeout(address, write, read, || Ok(())) } - pub fn blocking_write_vectored_timeout( + fn blocking_write_vectored_with_timeout( &mut self, address: u8, write: &[&[u8]], @@ -765,6 +848,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { if write.is_empty() { return Err(Error::ZeroLengthTransfer); } + let first_length = write[0].len(); let last_slice_index = write.len() - 1; @@ -833,6 +917,33 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { result } + #[cfg(feature = "time")] + pub fn blocking_write_vectored_timeout( + &mut self, + address: u8, + write: &[&[u8]], + timeout: Duration, + ) -> Result<(), Error> { + let check_timeout = timeout_fn(timeout); + self.blocking_write_vectored_with_timeout(address, write, check_timeout) + } + + #[cfg(not(feature = "time"))] + pub fn blocking_write_vectored_timeout( + &mut self, + address: u8, + write: &[&[u8]], + check_timeout: impl Fn() -> Result<(), Error>, + ) -> Result<(), Error> { + self.blocking_write_vectored_with_timeout(address, write, check_timeout) + } + + #[cfg(feature = "time")] + pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> { + self.blocking_write_vectored_timeout(address, write, self.timeout) + } + + #[cfg(not(feature = "time"))] pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> { self.blocking_write_vectored_timeout(address, write, || Ok(())) } @@ -844,6 +955,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { } } +#[cfg(feature = "time")] mod eh02 { use super::*; @@ -1043,7 +1155,7 @@ mod eh1 { } } -#[cfg(all(feature = "unstable-traits", feature = "nightly"))] +#[cfg(all(feature = "unstable-traits", feature = "nightly", feature = "time"))] mod eha { use super::super::{RxDma, TxDma}; use super::*; @@ -1089,3 +1201,15 @@ impl<'d, T: Instance> SetConfig for I2c<'d, T> { Ok(()) } } + +#[cfg(feature = "time")] +fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> { + let deadline = Instant::now() + timeout; + move || { + if Instant::now() > deadline { + Err(Error::Timeout) + } else { + Ok(()) + } + } +} diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs index e100ca5c..1b1e182f 100644 --- a/embassy-stm32/src/ipcc.rs +++ b/embassy-stm32/src/ipcc.rs @@ -93,8 +93,7 @@ pub struct Ipcc; impl Ipcc { pub fn enable(_config: Config) { - IPCC::enable(); - IPCC::reset(); + IPCC::enable_and_reset(); IPCC::set_cpu2(true); _configure_pwr(); diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 9dd2f616..372246f8 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -1,5 +1,5 @@ #![cfg_attr(not(test), no_std)] -#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections))] +#![cfg_attr(feature = "nightly", feature(async_fn_in_trait))] //! ## Feature flags #![doc = document_features::document_features!(feature_label = r#"{feature}"#)] @@ -49,6 +49,8 @@ pub mod i2s; pub mod ipcc; #[cfg(feature = "low-power")] pub mod low_power; +#[cfg(opamp)] +pub mod opamp; #[cfg(quadspi)] pub mod qspi; #[cfg(rng)] @@ -153,79 +155,82 @@ impl Default for Config { /// Initialize embassy. pub fn init(config: Config) -> Peripherals { - let p = Peripherals::take(); + critical_section::with(|cs| { + let p = Peripherals::take_with_cs(cs); - #[cfg(dbgmcu)] - if config.enable_debug_during_sleep { - crate::pac::DBGMCU.cr().modify(|cr| { - #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba))] - { - cr.set_dbg_stop(true); - cr.set_dbg_standby(true); - } - #[cfg(any( - dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1, - dbgmcu_l4, dbgmcu_wb, dbgmcu_wl - ))] - { - cr.set_dbg_sleep(true); - cr.set_dbg_stop(true); - cr.set_dbg_standby(true); - } - #[cfg(dbgmcu_h7)] - { - cr.set_d1dbgcken(true); - cr.set_d3dbgcken(true); - cr.set_dbgsleep_d1(true); - cr.set_dbgstby_d1(true); - cr.set_dbgstop_d1(true); - } - }); - } - - #[cfg(not(any(stm32f1, stm32wb, stm32wl)))] - peripherals::SYSCFG::enable(); - #[cfg(not(any(stm32h5, stm32h7, stm32wb, stm32wl)))] - peripherals::PWR::enable(); - #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7)))] - peripherals::FLASH::enable(); - - unsafe { - #[cfg(feature = "_split-pins-enabled")] - crate::pac::SYSCFG.pmcr().modify(|pmcr| { - #[cfg(feature = "split-pa0")] - pmcr.set_pa0so(true); - #[cfg(feature = "split-pa1")] - pmcr.set_pa1so(true); - #[cfg(feature = "split-pc2")] - pmcr.set_pc2so(true); - #[cfg(feature = "split-pc3")] - pmcr.set_pc3so(true); - }); - - gpio::init(); - dma::init( - #[cfg(bdma)] - config.bdma_interrupt_priority, - #[cfg(dma)] - config.dma_interrupt_priority, - #[cfg(gpdma)] - config.gpdma_interrupt_priority, - ); - #[cfg(feature = "exti")] - exti::init(); - - rcc::init(config.rcc); - - // must be after rcc init - #[cfg(feature = "_time-driver")] - time_driver::init(); - - #[cfg(feature = "low-power")] - while !crate::rcc::low_power_ready() { - crate::rcc::clock_refcount_sub(); + #[cfg(dbgmcu)] + if config.enable_debug_during_sleep { + crate::pac::DBGMCU.cr().modify(|cr| { + #[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u5, dbgmcu_wba))] + { + cr.set_dbg_stop(true); + cr.set_dbg_standby(true); + } + #[cfg(any( + dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1, + dbgmcu_l4, dbgmcu_wb, dbgmcu_wl + ))] + { + cr.set_dbg_sleep(true); + cr.set_dbg_stop(true); + cr.set_dbg_standby(true); + } + #[cfg(dbgmcu_h7)] + { + cr.set_d1dbgcken(true); + cr.set_d3dbgcken(true); + cr.set_dbgsleep_d1(true); + cr.set_dbgstby_d1(true); + cr.set_dbgstop_d1(true); + } + }); } - } - p + #[cfg(not(any(stm32f1, stm32wb, stm32wl)))] + peripherals::SYSCFG::enable_and_reset_with_cs(cs); + #[cfg(not(any(stm32h5, stm32h7, stm32wb, stm32wl)))] + peripherals::PWR::enable_and_reset_with_cs(cs); + #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7)))] + peripherals::FLASH::enable_and_reset_with_cs(cs); + + unsafe { + #[cfg(feature = "_split-pins-enabled")] + crate::pac::SYSCFG.pmcr().modify(|pmcr| { + #[cfg(feature = "split-pa0")] + pmcr.set_pa0so(true); + #[cfg(feature = "split-pa1")] + pmcr.set_pa1so(true); + #[cfg(feature = "split-pc2")] + pmcr.set_pc2so(true); + #[cfg(feature = "split-pc3")] + pmcr.set_pc3so(true); + }); + + gpio::init(cs); + dma::init( + cs, + #[cfg(bdma)] + config.bdma_interrupt_priority, + #[cfg(dma)] + config.dma_interrupt_priority, + #[cfg(gpdma)] + config.gpdma_interrupt_priority, + ); + #[cfg(feature = "exti")] + exti::init(cs); + + rcc::init(config.rcc); + + // must be after rcc init + #[cfg(feature = "_time-driver")] + time_driver::init(cs); + + #[cfg(feature = "low-power")] + while !crate::rcc::low_power_ready() { + crate::rcc::clock_refcount_sub(cs); + } + } + + p + }) } diff --git a/embassy-stm32/src/low_power.rs b/embassy-stm32/src/low_power.rs index ce8afb57..861a59d7 100644 --- a/embassy-stm32/src/low_power.rs +++ b/embassy-stm32/src/low_power.rs @@ -1,5 +1,6 @@ use core::arch::asm; use core::marker::PhantomData; +use core::sync::atomic::{compiler_fence, Ordering}; use cortex_m::peripheral::SCB; use embassy_executor::*; @@ -67,10 +68,8 @@ impl Executor { } unsafe fn on_wakeup_irq(&mut self) { - trace!("low power: on wakeup irq"); - self.time_driver.resume_time(); - trace!("low power: resume time"); + trace!("low power: resume"); } pub(self) fn stop_with_rtc(&mut self, rtc: &'static Rtc) { @@ -82,21 +81,18 @@ impl Executor { } fn configure_pwr(&mut self) { - trace!("low power: configure_pwr"); - self.scb.clear_sleepdeep(); + + compiler_fence(Ordering::SeqCst); + if !low_power_ready() { - trace!("low power: configure_pwr: low power not ready"); - return; + trace!("low power: not ready to stop"); + } else if self.time_driver.pause_time().is_err() { + trace!("low power: failed to pause time"); + } else { + trace!("low power: stop"); + self.scb.set_sleepdeep(); } - - if self.time_driver.pause_time().is_err() { - trace!("low power: configure_pwr: time driver failed to pause"); - return; - } - - trace!("low power: enter stop..."); - self.scb.set_sleepdeep(); } /// Run the executor. diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs new file mode 100644 index 00000000..e0fad26e --- /dev/null +++ b/embassy-stm32/src/opamp.rs @@ -0,0 +1,159 @@ +#![macro_use] + +use embassy_hal_internal::{into_ref, PeripheralRef}; + +use crate::Peripheral; + +#[derive(Clone, Copy)] +pub enum OpAmpGain { + Mul1, + Mul2, + Mul4, + Mul8, + Mul16, +} + +pub struct OpAmpOutput<'d, 'p, T: Instance, P: NonInvertingPin> { + _inner: &'d OpAmp<'d, T>, + _input: &'p mut P, +} + +pub struct OpAmp<'d, T: Instance> { + _inner: PeripheralRef<'d, T>, +} + +impl<'d, T: Instance> OpAmp<'d, T> { + pub fn new(opamp: impl Peripheral

+ 'd) -> Self { + Self::new_inner(opamp) + } + + fn new_inner(opamp: impl Peripheral

+ 'd) -> Self { + into_ref!(opamp); + + #[cfg(opamp_f3)] + T::regs().opampcsr().modify(|w| { + w.set_opampen(true); + }); + + #[cfg(opamp_g4)] + T::regs().opamp_csr().modify(|w| { + w.set_opaen(true); + }); + + Self { _inner: opamp } + } + + pub fn buffer_for<'a, 'b, P>(&'a mut self, pin: &'b mut P, gain: OpAmpGain) -> OpAmpOutput<'a, 'b, T, P> + where + P: NonInvertingPin, + { + let (vm_sel, pga_gain) = match gain { + OpAmpGain::Mul1 => (0b11, 0b00), + OpAmpGain::Mul2 => (0b10, 0b00), + OpAmpGain::Mul4 => (0b10, 0b01), + OpAmpGain::Mul8 => (0b10, 0b10), + OpAmpGain::Mul16 => (0b10, 0b11), + }; + + #[cfg(opamp_f3)] + T::regs().opampcsr().modify(|w| { + w.set_vp_sel(pin.channel()); + w.set_vm_sel(vm_sel); + w.set_pga_gain(pga_gain); + }); + + #[cfg(opamp_g4)] + T::regs().opamp_csr().modify(|w| { + use crate::pac::opamp::vals::*; + + w.set_vp_sel(OpampCsrVpSel::from_bits(pin.channel())); + w.set_vm_sel(OpampCsrVmSel::from_bits(vm_sel)); + w.set_pga_gain(OpampCsrPgaGain::from_bits(pga_gain)); + }); + + OpAmpOutput { + _inner: self, + _input: pin, + } + } +} + +pub trait Instance: sealed::Instance + 'static {} + +pub(crate) mod sealed { + pub trait Instance { + fn regs() -> crate::pac::opamp::Opamp; + } + + pub trait NonInvertingPin { + fn channel(&self) -> u8; + } + + pub trait InvertingPin { + fn channel(&self) -> u8; + } +} + +pub trait NonInvertingPin: sealed::NonInvertingPin {} + +pub trait InvertingPin: sealed::InvertingPin {} + +#[cfg(opamp_f3)] +macro_rules! impl_opamp_output { + ($inst:ident, $adc:ident, $ch:expr) => { + impl<'d, 'p, P: NonInvertingPin> crate::adc::sealed::AdcPin + for OpAmpOutput<'d, 'p, crate::peripherals::$inst, P> + { + fn channel(&self) -> u8 { + $ch + } + } + + impl<'d, 'p, P: NonInvertingPin> crate::adc::AdcPin + for OpAmpOutput<'d, 'p, crate::peripherals::$inst, P> + { + } + }; +} + +#[cfg(opamp_f3)] +foreach_peripheral!( + (opamp, OPAMP1) => { + impl_opamp_output!(OPAMP1, ADC1, 3); + }; + (opamp, OPAMP2) => { + impl_opamp_output!(OPAMP2, ADC2, 3); + }; + (opamp, OPAMP3) => { + impl_opamp_output!(OPAMP3, ADC3, 1); + }; + (opamp, OPAMP4) => { + impl_opamp_output!(OPAMP4, ADC4, 3); + }; +); + +foreach_peripheral! { + (opamp, $inst:ident) => { + impl sealed::Instance for crate::peripherals::$inst { + fn regs() -> crate::pac::opamp::Opamp { + crate::pac::$inst + } + } + + impl Instance for crate::peripherals::$inst { + + } + }; +} + +#[allow(unused_macros)] +macro_rules! impl_opamp_pin { + ($inst:ident, $pin:ident, $ch:expr) => { + impl crate::opamp::NonInvertingPin for crate::peripherals::$pin {} + impl crate::opamp::sealed::NonInvertingPin for crate::peripherals::$pin { + fn channel(&self) -> u8 { + $ch + } + } + }; +} diff --git a/embassy-stm32/src/qspi/enums.rs b/embassy-stm32/src/qspi/enums.rs index 2dbe2b06..0412d991 100644 --- a/embassy-stm32/src/qspi/enums.rs +++ b/embassy-stm32/src/qspi/enums.rs @@ -38,6 +38,22 @@ impl Into for QspiWidth { } } +#[allow(dead_code)] +#[derive(Copy, Clone)] +pub enum FlashSelection { + Flash1, + Flash2, +} + +impl Into for FlashSelection { + fn into(self) -> bool { + match self { + FlashSelection::Flash1 => false, + FlashSelection::Flash2 => true, + } + } +} + #[derive(Copy, Clone)] pub enum MemorySize { _1KiB, diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs index 32382fb2..4b0e8ece 100644 --- a/embassy-stm32/src/qspi/mod.rs +++ b/embassy-stm32/src/qspi/mod.rs @@ -7,7 +7,7 @@ use enums::*; use crate::dma::Transfer; use crate::gpio::sealed::AFType; -use crate::gpio::AnyPin; +use crate::gpio::{AnyPin, Pull}; use crate::pac::quadspi::Quadspi as Regs; use crate::rcc::RccPeripheral; use crate::{peripherals, Peripheral}; @@ -83,30 +83,30 @@ pub struct Qspi<'d, T: Instance, Dma> { } impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { - pub fn new( + pub fn new_bk1( peri: impl Peripheral

+ 'd, - d0: impl Peripheral

> + 'd, - d1: impl Peripheral

> + 'd, - d2: impl Peripheral

> + 'd, - d3: impl Peripheral

> + 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + d2: impl Peripheral

> + 'd, + d3: impl Peripheral

> + 'd, sck: impl Peripheral

> + 'd, - nss: impl Peripheral

> + 'd, + nss: impl Peripheral

> + 'd, dma: impl Peripheral

+ 'd, config: Config, ) -> Self { into_ref!(peri, d0, d1, d2, d3, sck, nss); - sck.set_as_af(sck.af_num(), AFType::OutputPushPull); + sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None); sck.set_speed(crate::gpio::Speed::VeryHigh); - nss.set_as_af(nss.af_num(), AFType::OutputPushPull); + nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up); nss.set_speed(crate::gpio::Speed::VeryHigh); - d0.set_as_af(d0.af_num(), AFType::OutputPushPull); + d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None); d0.set_speed(crate::gpio::Speed::VeryHigh); - d1.set_as_af(d1.af_num(), AFType::OutputPushPull); + d1.set_as_af_pull(d1.af_num(), AFType::OutputPushPull, Pull::None); d1.set_speed(crate::gpio::Speed::VeryHigh); - d2.set_as_af(d2.af_num(), AFType::OutputPushPull); + d2.set_as_af_pull(d2.af_num(), AFType::OutputPushPull, Pull::None); d2.set_speed(crate::gpio::Speed::VeryHigh); - d3.set_as_af(d3.af_num(), AFType::OutputPushPull); + d3.set_as_af_pull(d3.af_num(), AFType::OutputPushPull, Pull::None); d3.set_speed(crate::gpio::Speed::VeryHigh); Self::new_inner( @@ -119,6 +119,47 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { Some(nss.map_into()), dma, config, + FlashSelection::Flash2, + ) + } + + pub fn new_bk2( + peri: impl Peripheral

+ 'd, + d0: impl Peripheral

> + 'd, + d1: impl Peripheral

> + 'd, + d2: impl Peripheral

> + 'd, + d3: impl Peripheral

> + 'd, + sck: impl Peripheral

> + 'd, + nss: impl Peripheral

> + 'd, + dma: impl Peripheral

+ 'd, + config: Config, + ) -> Self { + into_ref!(peri, d0, d1, d2, d3, sck, nss); + + sck.set_as_af_pull(sck.af_num(), AFType::OutputPushPull, Pull::None); + sck.set_speed(crate::gpio::Speed::VeryHigh); + nss.set_as_af_pull(nss.af_num(), AFType::OutputPushPull, Pull::Up); + nss.set_speed(crate::gpio::Speed::VeryHigh); + d0.set_as_af_pull(d0.af_num(), AFType::OutputPushPull, Pull::None); + d0.set_speed(crate::gpio::Speed::VeryHigh); + d1.set_as_af_pull(d1.af_num(), AFType::OutputPushPull, Pull::None); + d1.set_speed(crate::gpio::Speed::VeryHigh); + d2.set_as_af_pull(d2.af_num(), AFType::OutputPushPull, Pull::None); + d2.set_speed(crate::gpio::Speed::VeryHigh); + d3.set_as_af_pull(d3.af_num(), AFType::OutputPushPull, Pull::None); + d3.set_speed(crate::gpio::Speed::VeryHigh); + + Self::new_inner( + peri, + Some(d0.map_into()), + Some(d1.map_into()), + Some(d2.map_into()), + Some(d3.map_into()), + Some(sck.map_into()), + Some(nss.map_into()), + dma, + config, + FlashSelection::Flash2, ) } @@ -132,22 +173,39 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { nss: Option>, dma: impl Peripheral

+ 'd, config: Config, + fsel: FlashSelection, ) -> Self { into_ref!(peri, dma); - T::enable(); - T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into())); + T::enable_and_reset(); while T::REGS.sr().read().busy() {} - T::REGS.cr().write(|w| { - w.set_prescaler(config.prescaler); + #[cfg(stm32h7)] + { + use stm32_metapac::quadspi::regs::Cr; + // Apply precautionary steps according to the errata... + T::REGS.cr().write_value(Cr(0)); + while T::REGS.sr().read().busy() {} + T::REGS.cr().write_value(Cr(0xFF000001)); + T::REGS.ccr().write(|w| w.set_frcm(true)); + T::REGS.ccr().write(|w| w.set_frcm(true)); + T::REGS.cr().write_value(Cr(0)); + while T::REGS.sr().read().busy() {} + } + + T::REGS.cr().modify(|w| { w.set_en(true); + //w.set_tcen(false); + w.set_sshift(false); + w.set_fthres(config.fifo_threshold.into()); + w.set_prescaler(config.prescaler); + w.set_fsel(fsel.into()); }); - T::REGS.dcr().write(|w| { + T::REGS.dcr().modify(|w| { w.set_fsize(config.memory_size.into()); w.set_csht(config.cs_high_time.into()); - w.set_ckmode(false); + w.set_ckmode(true); }); Self { @@ -164,6 +222,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { } pub fn command(&mut self, transaction: TransferConfig) { + #[cfg(not(stm32h7))] T::REGS.cr().modify(|v| v.set_dmaen(false)); self.setup_transaction(QspiMode::IndirectWrite, &transaction); @@ -172,6 +231,7 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { } pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) { + #[cfg(not(stm32h7))] T::REGS.cr().modify(|v| v.set_dmaen(false)); self.setup_transaction(QspiMode::IndirectWrite, &transaction); @@ -195,7 +255,10 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { } pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) { + // STM32H7 does not have dmaen + #[cfg(not(stm32h7))] T::REGS.cr().modify(|v| v.set_dmaen(false)); + self.setup_transaction(QspiMode::IndirectWrite, &transaction); if let Some(len) = transaction.data_len { @@ -238,6 +301,8 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { ) }; + // STM32H7 does not have dmaen + #[cfg(not(stm32h7))] T::REGS.cr().modify(|v| v.set_dmaen(true)); transfer.blocking_wait(); @@ -264,6 +329,8 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { ) }; + // STM32H7 does not have dmaen + #[cfg(not(stm32h7))] T::REGS.cr().modify(|v| v.set_dmaen(true)); transfer.blocking_wait(); @@ -313,11 +380,17 @@ pub(crate) mod sealed { pub trait Instance: Peripheral

+ sealed::Instance + RccPeripheral {} pin_trait!(SckPin, Instance); -pin_trait!(D0Pin, Instance); -pin_trait!(D1Pin, Instance); -pin_trait!(D2Pin, Instance); -pin_trait!(D3Pin, Instance); -pin_trait!(NSSPin, Instance); +pin_trait!(BK1D0Pin, Instance); +pin_trait!(BK1D1Pin, Instance); +pin_trait!(BK1D2Pin, Instance); +pin_trait!(BK1D3Pin, Instance); +pin_trait!(BK1NSSPin, Instance); + +pin_trait!(BK2D0Pin, Instance); +pin_trait!(BK2D1Pin, Instance); +pin_trait!(BK2D2Pin, Instance); +pin_trait!(BK2D3Pin, Instance); +pin_trait!(BK2NSSPin, Instance); dma_trait!(QuadDma, Instance); diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs index de27130f..a7c4b4f9 100644 --- a/embassy-stm32/src/rcc/bd.rs +++ b/embassy-stm32/src/rcc/bd.rs @@ -1,102 +1,161 @@ +use core::sync::atomic::{compiler_fence, Ordering}; + +use crate::pac::common::{Reg, RW}; +pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource; +use crate::time::Hertz; + +#[cfg(any(stm32f0, stm32f1, stm32f3))] +pub const LSI_FREQ: Hertz = Hertz(40_000); +#[cfg(not(any(stm32f0, stm32f1, stm32f3)))] +pub const LSI_FREQ: Hertz = Hertz(32_000); + +#[allow(dead_code)] +#[derive(Clone, Copy)] +pub enum LseMode { + Oscillator(LseDrive), + Bypass, +} + +pub struct LseConfig { + pub frequency: Hertz, + pub mode: LseMode, +} + #[allow(dead_code)] #[derive(Default, Clone, Copy)] pub enum LseDrive { - #[cfg(any(rtc_v2f7, rtc_v2l4))] Low = 0, MediumLow = 0x01, #[default] MediumHigh = 0x02, - #[cfg(any(rtc_v2f7, rtc_v2l4))] High = 0x03, } -#[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] +// All families but these have the LSEDRV register +#[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f400, rcc_f410, rcc_l1)))] impl From for crate::pac::rcc::vals::Lsedrv { fn from(value: LseDrive) -> Self { use crate::pac::rcc::vals::Lsedrv; match value { - #[cfg(any(rtc_v2f7, rtc_v2l4))] LseDrive::Low => Lsedrv::LOW, LseDrive::MediumLow => Lsedrv::MEDIUMLOW, LseDrive::MediumHigh => Lsedrv::MEDIUMHIGH, - #[cfg(any(rtc_v2f7, rtc_v2l4))] LseDrive::High => Lsedrv::HIGH, } } } -pub use crate::pac::rcc::vals::Rtcsel as RtcClockSource; - #[cfg(not(any(rtc_v2l0, rtc_v2l1, stm32c0)))] -#[allow(dead_code)] type Bdcr = crate::pac::rcc::regs::Bdcr; - #[cfg(any(rtc_v2l0, rtc_v2l1))] -#[allow(dead_code)] type Bdcr = crate::pac::rcc::regs::Csr; +#[cfg(any(stm32c0))] +type Bdcr = crate::pac::rcc::regs::Csr1; -#[allow(dead_code)] -pub struct BackupDomain {} +#[cfg(any(stm32c0))] +fn unlock() {} -impl BackupDomain { - #[cfg(any( - rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, - rtc_v3u5 - ))] - #[allow(dead_code, unused_variables)] - fn modify(f: impl FnOnce(&mut Bdcr) -> R) -> R { - #[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(); +#[cfg(not(any(stm32c0)))] +fn unlock() { + #[cfg(any(stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1))] + let cr = crate::pac::PWR.cr(); + #[cfg(not(any(stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1, stm32u5, stm32h5, stm32wba)))] + let cr = crate::pac::PWR.cr1(); + #[cfg(any(stm32u5, stm32h5, stm32wba))] + let cr = crate::pac::PWR.dbpcr(); - // TODO: Missing from PAC for l0 and f0? - #[cfg(not(any(rtc_v2f0, rtc_v3u5)))] - { - cr.modify(|w| w.set_dbp(true)); - while !cr.read().dbp() {} + cr.modify(|w| w.set_dbp(true)); + while !cr.read().dbp() {} +} + +fn bdcr() -> Reg { + #[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, +} + +impl LsConfig { + pub const fn default_lse() -> Self { + Self { + rtc: RtcClockSource::LSE, + lse: Some(LseConfig { + frequency: Hertz(32_768), + mode: LseMode::Oscillator(LseDrive::MediumHigh), + }), + lsi: false, } - - #[cfg(any(rtc_v2l0, rtc_v2l1))] - let cr = crate::pac::RCC.csr(); - - #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] - let cr = crate::pac::RCC.bdcr(); - - cr.modify(|w| f(w)) } - #[cfg(any( - rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, - rtc_v3u5 - ))] - #[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 default_lsi() -> Self { + Self { + rtc: RtcClockSource::LSI, + lsi: true, + lse: None, + } } - #[cfg(any( - rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb, rtc_v3, - rtc_v3u5 - ))] - #[allow(dead_code, unused_variables)] - pub fn configure_ls(clock_source: RtcClockSource, lsi: bool, lse: Option) { - if lsi { - #[cfg(rtc_v3u5)] + pub const fn off() -> Self { + Self { + rtc: RtcClockSource::NOCLOCK, + lsi: false, + lse: None, + } + } +} + +impl Default for LsConfig { + fn default() -> Self { + // on L5, just the fact that LSI is enabled makes things crash. + // TODO: investigate. + + #[cfg(not(stm32l5))] + return Self::default_lsi(); + #[cfg(stm32l5)] + return Self::off(); + } +} + +impl LsConfig { + pub(crate) fn init(&self) -> Option { + let rtc_clk = match self.rtc { + RtcClockSource::LSI => { + assert!(self.lsi); + Some(LSI_FREQ) + } + RtcClockSource::LSE => Some(self.lse.as_ref().unwrap().frequency), + RtcClockSource::NOCLOCK => None, + _ => todo!(), + }; + + let (lse_en, lse_byp, lse_drv) = match &self.lse { + Some(c) => match c.mode { + LseMode::Oscillator(lse_drv) => (true, false, Some(lse_drv)), + LseMode::Bypass => (true, true, None), + }, + None => (false, false, None), + }; + _ = lse_drv; // not all chips have it. + + // Disable backup domain write protection + unlock(); + + if self.lsi { + #[cfg(any(stm32u5, stm32h5, stm32wba))] let csr = crate::pac::RCC.bdcr(); - - #[cfg(not(rtc_v3u5))] + #[cfg(not(any(stm32u5, stm32h5, stm32wba, stm32c0)))] let csr = crate::pac::RCC.csr(); - - // Disable backup domain write protection - Self::modify(|_| {}); + #[cfg(any(stm32c0))] + let csr = crate::pac::RCC.csr2(); #[cfg(not(any(rcc_wb, rcc_wba)))] csr.modify(|w| w.set_lsion(true)); @@ -111,66 +170,76 @@ impl BackupDomain { while !csr.read().lsi1rdy() {} } - if let Some(lse_drive) = lse { - Self::modify(|w| { - #[cfg(any(rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l4))] - w.set_lsedrv(lse_drive.into()); + // backup domain configuration (LSEON, RTCEN, RTCSEL) is kept across resets. + // once set, changing it requires a backup domain reset. + // first check if the configuration matches what we want. + + // check if it's already enabled and in the source we want. + let reg = bdcr().read(); + let mut ok = true; + ok &= reg.rtcsel() == self.rtc; + #[cfg(not(rcc_wba))] + { + ok &= reg.rtcen() == (self.rtc != RtcClockSource::NOCLOCK); + } + ok &= reg.lseon() == lse_en; + ok &= reg.lsebyp() == lse_byp; + #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f400, rcc_f410, rcc_l1)))] + if let Some(lse_drv) = lse_drv { + ok &= reg.lsedrv() == lse_drv.into(); + } + + // if configuration is OK, we're done. + if ok { + trace!("BDCR ok: {:08x}", bdcr().read().0); + return rtc_clk; + } + + // If not OK, reset backup domain and configure it. + #[cfg(not(any(rcc_l0, rcc_l0_v2, rcc_l1, stm32h5, stm32c0)))] + { + bdcr().modify(|w| w.set_bdrst(true)); + bdcr().modify(|w| w.set_bdrst(false)); + } + #[cfg(any(stm32h5))] + { + bdcr().modify(|w| w.set_vswrst(true)); + bdcr().modify(|w| w.set_vswrst(false)); + } + #[cfg(any(stm32c0))] + { + bdcr().modify(|w| w.set_rtcrst(true)); + bdcr().modify(|w| w.set_rtcrst(false)); + } + + if lse_en { + bdcr().modify(|w| { + #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f400, rcc_f410, rcc_l1)))] + if let Some(lse_drv) = lse_drv { + w.set_lsedrv(lse_drv.into()); + } + w.set_lsebyp(lse_byp); w.set_lseon(true); }); - while !Self::read().lserdy() {} + while !bdcr().read().lserdy() {} } - match clock_source { - RtcClockSource::LSI => assert!(lsi), - RtcClockSource::LSE => assert!(&lse.is_some()), - _ => {} - }; - - if clock_source == RtcClockSource::NOCLOCK { - // disable it - Self::modify(|w| { - #[cfg(not(rcc_wba))] - w.set_rtcen(false); - w.set_rtcsel(clock_source); - }); - } else { - // check if it's already enabled and in the source we want. - let reg = Self::read(); - let ok = reg.rtcsel() == clock_source; - #[cfg(not(rcc_wba))] - let ok = ok & reg.rtcen(); - - // if not, configure it. - if !ok { + if self.rtc != RtcClockSource::NOCLOCK { + bdcr().modify(|w| { #[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] - assert!(!reg.lsecsson(), "RTC is not compatible with LSE CSS, yet."); + assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet."); - #[cfg(not(any(rcc_l0, rcc_l1)))] - Self::modify(|w| w.set_bdrst(true)); - - Self::modify(|w| { - // Reset - #[cfg(not(any(rcc_l0, rcc_l1)))] - w.set_bdrst(false); - - #[cfg(not(rcc_wba))] - w.set_rtcen(true); - w.set_rtcsel(clock_source); - - // Restore bcdr - #[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] - w.set_lscosel(reg.lscosel()); - #[cfg(any(rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] - w.set_lscoen(reg.lscoen()); - - w.set_lseon(reg.lseon()); - - #[cfg(any(rtc_v2f0, rtc_v2f7, rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))] - w.set_lsedrv(reg.lsedrv()); - w.set_lsebyp(reg.lsebyp()); - }); - } + #[cfg(not(rcc_wba))] + w.set_rtcen(true); + w.set_rtcsel(self.rtc); + }); } + + trace!("BDCR configured: {:08x}", bdcr().read().0); + + compiler_fence(Ordering::SeqCst); + + rtc_clk } } diff --git a/embassy-stm32/src/rcc/bus.rs b/embassy-stm32/src/rcc/bus.rs deleted file mode 100644 index 495cf7fe..00000000 --- a/embassy-stm32/src/rcc/bus.rs +++ /dev/null @@ -1,56 +0,0 @@ -use core::ops::Div; - -#[allow(unused_imports)] -use crate::pac::rcc; -pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; -use crate::time::Hertz; - -impl Div 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 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) - } -} diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs index 8f45e7c0..eeb6418a 100644 --- a/embassy-stm32/src/rcc/c0.rs +++ b/embassy-stm32/src/rcc/c0.rs @@ -1,6 +1,6 @@ -pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::pac::flash::vals::Latency; -use crate::pac::rcc::vals::{Hsidiv, Ppre, Sw}; +use crate::pac::rcc::vals::Sw; +pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Hsidiv as HSIPrescaler, Ppre as APBPrescaler}; use crate::pac::{FLASH, RCC}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; @@ -8,9 +8,6 @@ use crate::time::Hertz; /// HSI speed pub const HSI_FREQ: Hertz = Hertz(48_000_000); -/// LSI speed -pub const LSI_FREQ: Hertz = Hertz(32_000); - /// System clock mux source #[derive(Clone, Copy)] pub enum ClockSrc { @@ -19,47 +16,22 @@ pub enum ClockSrc { LSI, } -#[derive(Clone, Copy)] -pub enum HSIPrescaler { - NotDivided, - Div2, - Div4, - Div8, - Div16, - Div32, - Div64, - Div128, -} - -impl Into 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 pub struct Config { pub mux: ClockSrc, pub ahb_pre: AHBPrescaler, pub apb_pre: APBPrescaler, + pub ls: super::LsConfig, } impl Default for Config { #[inline] fn default() -> Config { Config { - mux: ClockSrc::HSI(HSIPrescaler::NotDivided), + mux: ClockSrc::HSI(HSIPrescaler::DIV1), ahb_pre: AHBPrescaler::DIV1, apb_pre: APBPrescaler::DIV1, + ls: Default::default(), } } } @@ -68,33 +40,34 @@ pub(crate) unsafe fn init(config: Config) { let (sys_clk, sw) = match config.mux { ClockSrc::HSI(div) => { // Enable HSI - let div: Hsidiv = div.into(); RCC.cr().write(|w| { w.set_hsidiv(div); w.set_hsion(true) }); while !RCC.cr().read().hsirdy() {} - (HSI_FREQ.0 >> div.to_bits(), Sw::HSI) + (HSI_FREQ / div, Sw::HSI) } ClockSrc::HSE(freq) => { // Enable HSE RCC.cr().write(|w| w.set_hseon(true)); while !RCC.cr().read().hserdy() {} - (freq.0, Sw::HSE) + (freq, Sw::HSE) } ClockSrc::LSI => { // Enable LSI RCC.csr2().write(|w| w.set_lsion(true)); while !RCC.csr2().read().lsirdy() {} - (LSI_FREQ.0, Sw::LSI) + (super::LSI_FREQ, Sw::LSI) } }; + let rtc = config.ls.init(); + // Determine the flash latency implied by the target clock speed // RM0454 § 3.3.4: - let target_flash_latency = if sys_clk <= 24_000_000 { + let target_flash_latency = if sys_clk <= Hertz(24_000_000) { Latency::WS0 } else { Latency::WS1 @@ -129,7 +102,7 @@ pub(crate) unsafe fn init(config: Config) { } // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once - let (sw, hpre, ppre) = (sw.into(), config.ahb_pre.into(), config.apb_pre.into()); + let (sw, hpre, ppre) = (sw.into(), config.ahb_pre, config.apb_pre); RCC.cfgr().modify(|w| { w.set_sw(sw); w.set_hpre(hpre); @@ -150,34 +123,21 @@ pub(crate) unsafe fn init(config: Config) { FLASH.acr().modify(|w| w.set_latency(target_flash_latency)); } - 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 ahb_freq = sys_clk / config.ahb_pre; let (apb_freq, apb_tim_freq) = match config.apb_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 freq = ahb_freq / pre; + (freq, freq * 2u32) } }; set_freqs(Clocks { - sys: Hertz(sys_clk), - ahb1: Hertz(ahb_freq), - apb1: Hertz(apb_freq), - apb1_tim: Hertz(apb_tim_freq), + sys: sys_clk, + ahb1: ahb_freq, + apb1: apb_freq, + apb1_tim: apb_tim_freq, + rtc, }); } diff --git a/embassy-stm32/src/rcc/f0.rs b/embassy-stm32/src/rcc/f0.rs index ca6eed28..cc712e87 100644 --- a/embassy-stm32/src/rcc/f0.rs +++ b/embassy-stm32/src/rcc/f0.rs @@ -8,9 +8,6 @@ use crate::time::Hertz; /// HSI speed pub const HSI_FREQ: Hertz = Hertz(8_000_000); -/// LSI speed -pub const LSI_FREQ: Hertz = Hertz(40_000); - /// Configuration of the clocks /// /// hse takes precedence over hsi48 if both are enabled @@ -27,6 +24,8 @@ pub struct Config { pub sys_ck: Option, pub hclk: Option, pub pclk: Option, + + pub ls: super::LsConfig, } pub(crate) unsafe fn init(config: Config) { @@ -159,6 +158,8 @@ pub(crate) unsafe fn init(config: Config) { }) } + let rtc = config.ls.init(); + set_freqs(Clocks { sys: Hertz(real_sysclk), apb1: Hertz(pclk), @@ -166,5 +167,6 @@ pub(crate) unsafe fn init(config: Config) { apb1_tim: Hertz(pclk * timer_mul), apb2_tim: Hertz(pclk * timer_mul), ahb1: Hertz(hclk), + rtc, }); } diff --git a/embassy-stm32/src/rcc/f1.rs b/embassy-stm32/src/rcc/f1.rs index 081c0c76..56c49cd8 100644 --- a/embassy-stm32/src/rcc/f1.rs +++ b/embassy-stm32/src/rcc/f1.rs @@ -9,9 +9,6 @@ use crate::time::Hertz; /// HSI speed pub const HSI_FREQ: Hertz = Hertz(8_000_000); -/// LSI speed -pub const LSI_FREQ: Hertz = Hertz(40_000); - /// Configuration of the clocks /// #[non_exhaustive] @@ -25,6 +22,8 @@ pub struct Config { pub pclk2: Option, pub adcclk: Option, pub pllxtpre: bool, + + pub ls: super::LsConfig, } pub(crate) unsafe fn init(config: Config) { @@ -177,6 +176,8 @@ pub(crate) unsafe fn init(config: Config) { }); }); + let rtc = config.ls.init(); + set_freqs(Clocks { sys: Hertz(real_sysclk), apb1: Hertz(pclk1), @@ -185,5 +186,6 @@ pub(crate) unsafe fn init(config: Config) { apb2_tim: Hertz(pclk2 * timer_mul2), ahb1: Hertz(hclk), adc: Some(Hertz(adcclk)), + rtc, }); } diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs index 44de5bf1..ab588233 100644 --- a/embassy-stm32/src/rcc/f2.rs +++ b/embassy-stm32/src/rcc/f2.rs @@ -1,21 +1,16 @@ -use core::convert::TryFrom; -use core::ops::{Div, Mul}; - -pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::pac::flash::vals::Latency; -use crate::pac::rcc::vals::{Pllp, Pllsrc, Sw}; +use crate::pac::rcc::vals::Sw; +pub use crate::pac::rcc::vals::{ + Hpre as AHBPrescaler, Pllm as PLLPreDiv, Plln as PLLMul, Pllp as PLLPDiv, Pllq as PLLQDiv, Pllsrc as PLLSrc, + Ppre as APBPrescaler, +}; use crate::pac::{FLASH, RCC}; -use crate::rcc::bd::BackupDomain; use crate::rcc::{set_freqs, Clocks}; -use crate::rtc::RtcClockSource; 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); - #[derive(Clone, Copy)] pub struct HSEConfig { pub frequency: Hertz, @@ -43,17 +38,17 @@ pub enum HSESrc { pub struct PLLConfig { pub pre_div: PLLPreDiv, pub mul: PLLMul, - pub main_div: PLLMainDiv, - pub pll48_div: PLL48Div, + pub p_div: PLLPDiv, + pub q_div: PLLQDiv, } impl Default for PLLConfig { fn default() -> Self { PLLConfig { - pre_div: PLLPreDiv(16), - mul: PLLMul(192), - main_div: PLLMainDiv::Div2, - pll48_div: PLL48Div(4), + pre_div: PLLPreDiv::DIV16, + mul: PLLMul::MUL192, + p_div: PLLPDiv::DIV2, + q_div: PLLQDiv::DIV4, } } } @@ -61,9 +56,9 @@ impl Default for PLLConfig { impl PLLConfig { pub fn clocks(&self, src_freq: Hertz) -> PLLClocks { let in_freq = src_freq / self.pre_div; - let vco_freq = Hertz((src_freq.0 as u64 * self.mul.0 as u64 / self.pre_div.0 as u64) as u32); - let main_freq = vco_freq / self.main_div; - let pll48_freq = vco_freq / self.pll48_div; + let vco_freq = src_freq / self.pre_div * self.mul; + let main_freq = vco_freq / self.p_div; + let pll48_freq = vco_freq / self.q_div; PLLClocks { in_freq, vco_freq, @@ -72,129 +67,6 @@ impl PLLConfig { } } } - -/// Clock source for both main PLL and PLLI2S -#[derive(Clone, Copy, PartialEq)] -pub enum PLLSrc { - HSE, - HSI, -} - -impl Into 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 for PLLPreDiv { - type Error = &'static str; - - fn try_from(value: u8) -> Result { - match value { - 2..=63 => Ok(PLLPreDiv(value)), - _ => Err("PLLPreDiv must be within range 2..=63"), - } - } -} - -impl Div 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 for Hertz { - type Output = Hertz; - - fn mul(self, rhs: PLLMul) -> Self::Output { - Hertz(self.0 * u32::from(rhs.0)) - } -} - -impl TryFrom for PLLMul { - type Error = &'static str; - - fn try_from(value: u16) -> Result { - 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 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 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 for Hertz { - type Output = Hertz; - - fn div(self, rhs: PLL48Div) -> Self::Output { - Hertz(self.0 / u32::from(rhs.0)) - } -} - -impl TryFrom for PLL48Div { - type Error = &'static str; - - fn try_from(value: u8) -> Result { - match value { - 2..=15 => Ok(PLL48Div(value)), - _ => Err("PLL48Div must be within range 2..=15"), - } - } -} - #[derive(Clone, Copy, PartialEq)] pub struct PLLClocks { pub in_freq: Hertz, @@ -303,13 +175,11 @@ pub struct Config { pub pll_mux: PLLSrc, pub pll: PLLConfig, pub mux: ClockSrc, - pub rtc: Option, - pub lsi: bool, - pub lse: Option, pub voltage: VoltageScale, pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, pub apb2_pre: APBPrescaler, + pub ls: super::LsConfig, } impl Default for Config { @@ -322,12 +192,10 @@ impl Default for Config { pll: PLLConfig::default(), voltage: VoltageScale::Range3, mux: ClockSrc::HSI, - rtc: None, - lsi: false, - lse: None, ahb_pre: AHBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, + ls: Default::default(), } } } @@ -367,11 +235,11 @@ pub(crate) unsafe fn init(config: Config) { assert!(pll_clocks.pll48_freq <= Hertz(48_000_000)); RCC.pllcfgr().write(|w| { - w.set_pllsrc(config.pll_mux.into()); - w.set_pllm(config.pll.pre_div.0); - w.set_plln(config.pll.mul.0); - w.set_pllp(config.pll.main_div.into()); - w.set_pllq(config.pll.pll48_div.0); + w.set_pllsrc(config.pll_mux); + w.set_pllm(config.pll.pre_div); + w.set_plln(config.pll.mul); + w.set_pllp(config.pll.p_div); + w.set_pllq(config.pll.q_div); }); let (sys_clk, sw) = match config.mux { @@ -424,9 +292,9 @@ pub(crate) unsafe fn init(config: Config) { RCC.cfgr().modify(|w| { w.set_sw(sw.into()); - w.set_hpre(config.ahb_pre.into()); - w.set_ppre1(config.apb1_pre.into()); - w.set_ppre2(config.apb2_pre.into()); + w.set_hpre(config.ahb_pre); + w.set_ppre1(config.apb1_pre); + w.set_ppre2(config.apb2_pre); }); while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {} @@ -435,11 +303,7 @@ pub(crate) unsafe fn init(config: Config) { RCC.cr().modify(|w| w.set_hsion(false)); } - BackupDomain::configure_ls( - config.rtc.unwrap_or(RtcClockSource::NOCLOCK), - config.lsi, - config.lse.map(|_| Default::default()), - ); + let rtc = config.ls.init(); set_freqs(Clocks { sys: sys_clk, @@ -451,5 +315,6 @@ pub(crate) unsafe fn init(config: Config) { apb2: apb2_freq, apb2_tim: apb2_tim_freq, pll48: Some(pll_clocks.pll48_freq), + rtc, }); } diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs index 630dbd4f..2aa79cec 100644 --- a/embassy-stm32/src/rcc/f3.rs +++ b/embassy-stm32/src/rcc/f3.rs @@ -1,7 +1,8 @@ #[cfg(rcc_f3)] use crate::pac::adccommon::vals::Ckmode; use crate::pac::flash::vals::Latency; -use crate::pac::rcc::vals::{Adcpres, Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre}; +pub use crate::pac::rcc::vals::Adcpres; +use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre}; use crate::pac::{FLASH, RCC}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; @@ -9,28 +10,6 @@ use crate::time::Hertz; /// HSI speed pub const HSI_FREQ: Hertz = Hertz(8_000_000); -/// LSI speed -pub const LSI_FREQ: Hertz = Hertz(40_000); - -impl From 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)] impl From for Ckmode { fn from(value: AdcClockSource) -> Self { @@ -45,32 +24,13 @@ impl From for Ckmode { #[derive(Clone, Copy)] pub enum AdcClockSource { - PllDiv1 = 1, - PllDiv2 = 2, - PllDiv4 = 4, - PllDiv6 = 6, - PllDiv8 = 8, - PllDiv12 = 12, - PllDiv16 = 16, - PllDiv32 = 32, - PllDiv64 = 64, - PllDiv128 = 128, - PllDiv256 = 256, + Pll(Adcpres), BusDiv1, BusDiv2, BusDiv4, } 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 { match self { Self::BusDiv1 => 1, @@ -124,6 +84,7 @@ pub struct Config { pub adc34: Option, #[cfg(stm32f334)] pub hrtim: HrtimClockSource, + pub ls: super::LsConfig, } // Information required to setup the PLL clock @@ -137,67 +98,67 @@ struct PllConfig { /// Initialize and Set the clock frequencies pub(crate) unsafe fn init(config: Config) { // Calculate the real System clock, and PLL configuration if applicable - let (Hertz(sysclk), pll_config) = get_sysclk(&config); - assert!(sysclk <= 72_000_000); + let (sysclk, pll_config) = get_sysclk(&config); + assert!(sysclk.0 <= 72_000_000); // Calculate real AHB clock - let hclk = config.hclk.map(|h| h.0).unwrap_or(sysclk); - let (hpre_bits, hpre_div) = match sysclk / hclk { + let hclk = config.hclk.map(|h| h).unwrap_or(sysclk); + let hpre = match sysclk.0 / hclk.0 { 0 => unreachable!(), - 1 => (Hpre::DIV1, 1), - 2 => (Hpre::DIV2, 2), - 3..=5 => (Hpre::DIV4, 4), - 6..=11 => (Hpre::DIV8, 8), - 12..=39 => (Hpre::DIV16, 16), - 40..=95 => (Hpre::DIV64, 64), - 96..=191 => (Hpre::DIV128, 128), - 192..=383 => (Hpre::DIV256, 256), - _ => (Hpre::DIV512, 512), + 1 => Hpre::DIV1, + 2 => Hpre::DIV2, + 3..=5 => Hpre::DIV4, + 6..=11 => Hpre::DIV8, + 12..=39 => Hpre::DIV16, + 40..=95 => Hpre::DIV64, + 96..=191 => Hpre::DIV128, + 192..=383 => Hpre::DIV256, + _ => Hpre::DIV512, }; - let hclk = sysclk / hpre_div; - assert!(hclk <= 72_000_000); + let hclk = sysclk / hpre; + assert!(hclk <= Hertz(72_000_000)); // Calculate real APB1 clock - let pclk1 = config.pclk1.map(|p| p.0).unwrap_or(hclk); - let (ppre1_bits, ppre1) = match hclk / pclk1 { + let pclk1 = config.pclk1.unwrap_or(hclk); + let ppre1 = match hclk / pclk1 { 0 => unreachable!(), - 1 => (Ppre::DIV1, 1), - 2 => (Ppre::DIV2, 2), - 3..=5 => (Ppre::DIV4, 4), - 6..=11 => (Ppre::DIV8, 8), - _ => (Ppre::DIV16, 16), + 1 => Ppre::DIV1, + 2 => Ppre::DIV2, + 3..=5 => Ppre::DIV4, + 6..=11 => Ppre::DIV8, + _ => Ppre::DIV16, }; - let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; + let timer_mul1 = if ppre1 == Ppre::DIV1 { 1u32 } else { 2 }; let pclk1 = hclk / ppre1; - assert!(pclk1 <= 36_000_000); + assert!(pclk1 <= Hertz(36_000_000)); // Calculate real APB2 clock - let pclk2 = config.pclk2.map(|p| p.0).unwrap_or(hclk); - let (ppre2_bits, ppre2) = match hclk / pclk2 { + let pclk2 = config.pclk2.unwrap_or(hclk); + let ppre2 = match hclk / pclk2 { 0 => unreachable!(), - 1 => (Ppre::DIV1, 1), - 2 => (Ppre::DIV2, 2), - 3..=5 => (Ppre::DIV4, 4), - 6..=11 => (Ppre::DIV8, 8), - _ => (Ppre::DIV16, 16), + 1 => Ppre::DIV1, + 2 => Ppre::DIV2, + 3..=5 => Ppre::DIV4, + 6..=11 => Ppre::DIV8, + _ => Ppre::DIV16, }; - let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; + let timer_mul2 = if ppre2 == Ppre::DIV1 { 1u32 } else { 2 }; let pclk2 = hclk / ppre2; - assert!(pclk2 <= 72_000_000); + assert!(pclk2 <= Hertz(72_000_000)); // Set latency based on HCLK frquency // RM0316: "The prefetch buffer must be kept on when using a prescaler // 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" FLASH.acr().modify(|w| { - w.set_latency(if hclk <= 24_000_000 { + w.set_latency(if hclk <= Hertz(24_000_000) { Latency::WS0 - } else if hclk <= 48_000_000 { + } else if hclk <= Hertz(48_000_000) { Latency::WS1 } else { Latency::WS2 }); - if hpre_div != 1 { + if hpre != Hpre::DIV1 { w.set_hlfcya(false); w.set_prftbe(true); } @@ -240,9 +201,9 @@ pub(crate) unsafe fn init(config: Config) { // Set prescalers // CFGR has been written before (PLL, PLL48) don't overwrite these settings RCC.cfgr().modify(|w| { - w.set_ppre2(ppre2_bits); - w.set_ppre1(ppre1_bits); - w.set_hpre(hpre_bits); + w.set_ppre2(ppre2); + w.set_ppre1(ppre1); + w.set_hpre(hpre); }); // Wait for the new prescalers to kick in @@ -260,45 +221,43 @@ pub(crate) unsafe fn init(config: Config) { }); #[cfg(rcc_f3)] - let adc = config.adc.map(|adc| { - if !adc.is_bus() { + let adc = config.adc.map(|adc| match adc { + AdcClockSource::Pll(adcpres) => { RCC.cfgr2().modify(|w| { // Make sure that we're using the PLL pll_config.unwrap(); - w.set_adc12pres(adc.into()); + w.set_adc12pres(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) + sysclk / adcpres }) } + _ => 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))] - let adc34 = config.adc.map(|adc| { - if !adc.is_bus() { + let adc34 = config.adc34.map(|adc| match adc { + AdcClockSource::Pll(adcpres) => { RCC.cfgr2().modify(|w| { // Make sure that we're using the PLL pll_config.unwrap(); - w.set_adc12pres(adc.into()); + w.set_adc34pres(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) + sysclk / adcpres }) } + _ => 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)] @@ -310,21 +269,23 @@ pub(crate) unsafe fn init(config: Config) { // Make sure that we're using the PLL pll_config.unwrap(); - assert!((pclk2 == sysclk) || (pclk2 * 2 == sysclk)); + assert!((pclk2 == sysclk) || (pclk2 * 2u32 == sysclk)); RCC.cfgr3().modify(|w| w.set_hrtim1sw(Timsw::PLL)); - Some(Hertz(sysclk * 2)) + Some(sysclk * 2u32) } }; + let rtc = config.ls.init(); + set_freqs(Clocks { - sys: Hertz(sysclk), - apb1: Hertz(pclk1), - apb2: Hertz(pclk2), - apb1_tim: Hertz(pclk1 * timer_mul1), - apb2_tim: Hertz(pclk2 * timer_mul2), - ahb1: Hertz(hclk), + sys: sysclk, + apb1: pclk1, + apb2: pclk2, + apb1_tim: pclk1 * timer_mul1, + apb2_tim: pclk2 * timer_mul2, + ahb1: hclk, #[cfg(rcc_f3)] adc: adc, #[cfg(all(rcc_f3, adc3_common))] @@ -333,6 +294,7 @@ pub(crate) unsafe fn init(config: Config) { adc34: None, #[cfg(stm32f334)] hrtim: hrtim, + rtc, }); } @@ -421,16 +383,16 @@ fn calc_pll(config: &Config, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) { #[inline] #[allow(unused_variables)] -fn get_usb_pre(config: &Config, sysclk: u32, pclk1: u32, pll_config: &Option) -> Usbpre { +fn get_usb_pre(config: &Config, sysclk: Hertz, pclk1: Hertz, pll_config: &Option) -> Usbpre { cfg_if::cfg_if! { // Some chips do not have USB if #[cfg(any(stm32f301, stm32f318, stm32f334))] { panic!("USB clock not supported by the chip"); } else { - let usb_ok = config.hse.is_some() && pll_config.is_some() && (pclk1 >= 10_000_000); + let usb_ok = config.hse.is_some() && pll_config.is_some() && (pclk1 >= Hertz(10_000_000)); match (usb_ok, sysclk) { - (true, 72_000_000) => Usbpre::DIV1_5, - (true, 48_000_000) => Usbpre::DIV1, + (true, Hertz(72_000_000)) => Usbpre::DIV1_5, + (true, Hertz(48_000_000)) => Usbpre::DIV1, _ => panic!( "USB clock is only valid if the PLL output frequency is either 48MHz or 72MHz" ), diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs index ebf78d0e..79c2d2f6 100644 --- a/embassy-stm32/src/rcc/f4.rs +++ b/embassy-stm32/src/rcc/f4.rs @@ -1,23 +1,11 @@ -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::rcc::vals::{Hpre, Pllm, Plln, Pllq, Pllr, Ppre, Sw}; use crate::pac::{FLASH, PWR, RCC}; -use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; -use crate::{peripherals, Peripheral}; /// HSI speed pub const HSI_FREQ: Hertz = Hertz(16_000_000); -/// LSI speed -pub const LSI_FREQ: Hertz = Hertz(32_000); - /// Clocks configuration #[non_exhaustive] #[derive(Default)] @@ -36,9 +24,7 @@ pub struct Config { pub pllsai: Option, pub pll48: bool, - pub rtc: Option, - pub lsi: bool, - pub lse: Option, + pub ls: super::LsConfig, } #[cfg(stm32f410)] @@ -52,7 +38,7 @@ fn setup_i2s_pll(_vco_in: u32, _plli2s: Option) -> Option { None } -#[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))] +#[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423)))] fn calculate_sai_i2s_pll_values(vco_in: u32, max_div: u32, target: Option) -> Option<(u32, u32, u32)> { let min_div = 2; let target = match target { @@ -178,12 +164,12 @@ fn setup_pll( let real_pll48clk = vco_in * plln / pllq; RCC.pllcfgr().modify(|w| { - w.set_pllm(pllm as u8); - w.set_plln(plln as u16); + w.set_pllm(Pllm::from_bits(pllm as u8)); + w.set_plln(Plln::from_bits(plln as u16)); w.set_pllp(Pllp::from_bits(pllp as u8)); - w.set_pllq(pllq as u8); + w.set_pllq(Pllq::from_bits(pllq as u8)); w.set_pllsrc(Pllsrc::from_bits(use_hse as u8)); - w.set_pllr(0); + w.set_pllr(Pllr::from_bits(0)); }); let real_pllsysclk = vco_in * plln / sysclk_div; @@ -197,164 +183,6 @@ fn setup_pll( } } -pub enum McoClock { - DIV1, - DIV2, - DIV3, - DIV4, - DIV5, -} - -impl McoClock { - fn into_raw(&self) -> Mcopre { - match self { - McoClock::DIV1 => Mcopre::DIV1, - McoClock::DIV2 => Mcopre::DIV2, - McoClock::DIV3 => Mcopre::DIV3, - McoClock::DIV4 => Mcopre::DIV4, - McoClock::DIV5 => Mcopre::DIV5, - } - } -} - -#[derive(Copy, Clone)] -pub enum Mco1Source { - Hsi, - Lse, - Hse, - Pll, -} - -impl Default for Mco1Source { - fn default() -> Self { - Self::Hsi - } -} - -pub trait McoSource { - type Raw; - - fn into_raw(&self) -> Self::Raw; -} - -impl McoSource for Mco1Source { - type Raw = Mco1; - fn into_raw(&self) -> Self::Raw { - match self { - Mco1Source::Hsi => Mco1::HSI, - Mco1Source::Lse => Mco1::LSE, - Mco1Source::Hse => Mco1::HSE, - Mco1Source::Pll => Mco1::PLL, - } - } -} - -#[derive(Copy, Clone)] -pub enum Mco2Source { - SysClk, - Plli2s, - Hse, - Pll, -} - -impl Default for Mco2Source { - fn default() -> Self { - Self::SysClk - } -} - -impl McoSource for Mco2Source { - type Raw = Mco2; - fn into_raw(&self) -> Self::Raw { - match self { - Mco2Source::SysClk => Mco2::SYSCLK, - Mco2Source::Plli2s => Mco2::PLLI2S, - Mco2Source::Hse => Mco2::HSE, - Mco2Source::Pll => Mco2::PLL, - } - } -} - -pub(crate) mod sealed { - use stm32_metapac::rcc::vals::Mcopre; - pub trait McoInstance { - type Source; - unsafe fn apply_clock_settings(source: Self::Source, prescaler: Mcopre); - } -} - -pub trait McoInstance: sealed::McoInstance + 'static {} - -pin_trait!(McoPin, McoInstance); - -impl sealed::McoInstance for peripherals::MCO1 { - type Source = Mco1; - unsafe fn apply_clock_settings(source: Self::Source, prescaler: Mcopre) { - RCC.cfgr().modify(|w| { - w.set_mco1(source); - w.set_mco1pre(prescaler); - }); - match source { - Mco1::PLL => { - RCC.cr().modify(|w| w.set_pllon(true)); - while !RCC.cr().read().pllrdy() {} - } - Mco1::HSI => { - RCC.cr().modify(|w| w.set_hsion(true)); - while !RCC.cr().read().hsirdy() {} - } - _ => {} - } - } -} -impl McoInstance for peripherals::MCO1 {} - -impl sealed::McoInstance for peripherals::MCO2 { - type Source = Mco2; - unsafe fn apply_clock_settings(source: Self::Source, prescaler: Mcopre) { - RCC.cfgr().modify(|w| { - w.set_mco2(source); - w.set_mco2pre(prescaler); - }); - match source { - Mco2::PLL => { - RCC.cr().modify(|w| w.set_pllon(true)); - while !RCC.cr().read().pllrdy() {} - } - #[cfg(not(stm32f410))] - Mco2::PLLI2S => { - RCC.cr().modify(|w| w.set_plli2son(true)); - while !RCC.cr().read().plli2srdy() {} - } - _ => {} - } - } -} -impl McoInstance for peripherals::MCO2 {} - -pub struct Mco<'d, T: McoInstance> { - phantom: PhantomData<&'d mut T>, -} - -impl<'d, T: McoInstance> Mco<'d, T> { - pub fn new( - _peri: impl Peripheral

+ 'd, - pin: impl Peripheral

> + 'd, - source: impl McoSource, - 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) { use crate::pac::flash::vals::Latency; @@ -508,17 +336,7 @@ pub(crate) unsafe fn init(config: Config) { }) }); - BackupDomain::configure_ls( - config.rtc.unwrap_or(RtcClockSource::NOCLOCK), - config.lsi, - config.lse.map(|_| Default::default()), - ); - - let rtc = match config.rtc { - Some(RtcClockSource::LSI) => Some(LSI_FREQ), - Some(RtcClockSource::LSE) => Some(config.lse.unwrap()), - _ => None, - }; + let rtc = config.ls.init(); set_freqs(Clocks { sys: Hertz(sysclk), @@ -540,8 +358,7 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] pllsai: plls.pllsaiclk.map(Hertz), - rtc: rtc, - rtc_hse: None, + rtc, }); } diff --git a/embassy-stm32/src/rcc/f7.rs b/embassy-stm32/src/rcc/f7.rs index f32559e2..0a0a1cf2 100644 --- a/embassy-stm32/src/rcc/f7.rs +++ b/embassy-stm32/src/rcc/f7.rs @@ -1,16 +1,12 @@ use crate::pac::pwr::vals::Vos; -use crate::pac::rcc::vals::{Hpre, Ppre, Sw}; +use crate::pac::rcc::vals::{Hpre, Pllm, Plln, Pllp, Pllq, Pllsrc, Ppre, Sw}; use crate::pac::{FLASH, PWR, RCC}; -use crate::rcc::bd::{BackupDomain, RtcClockSource}; 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); - /// Clocks configuration #[non_exhaustive] #[derive(Default)] @@ -23,14 +19,10 @@ pub struct Config { pub pclk2: Option, pub pll48: bool, - pub rtc: Option, - pub lsi: bool, - pub lse: Option, + pub ls: super::LsConfig, } fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option, pll48clk: bool) -> PllResults { - use crate::pac::rcc::vals::{Pllp, Pllsrc}; - let sysclk = pllsysclk.unwrap_or(pllsrcclk); if pllsysclk.is_none() && !pll48clk { RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc::from_bits(use_hse as u8))); @@ -84,10 +76,10 @@ fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option, pll48clk: bo let real_pll48clk = vco_in * plln / pllq; RCC.pllcfgr().modify(|w| { - w.set_pllm(pllm as u8); - w.set_plln(plln as u16); + w.set_pllm(Pllm::from_bits(pllm as u8)); + w.set_plln(Plln::from_bits(plln as u16)); w.set_pllp(Pllp::from_bits(pllp as u8)); - w.set_pllq(pllq as u8); + w.set_pllq(Pllq::from_bits(pllq as u8)); w.set_pllsrc(Pllsrc::from_bits(use_hse as u8)); }); @@ -263,17 +255,7 @@ pub(crate) unsafe fn init(config: Config) { }) }); - BackupDomain::configure_ls( - config.rtc.unwrap_or(RtcClockSource::NOCLOCK), - config.lsi, - config.lse.map(|_| Default::default()), - ); - - let rtc = match config.rtc { - Some(RtcClockSource::LSI) => Some(LSI_FREQ), - Some(RtcClockSource::LSE) => Some(config.lse.unwrap()), - _ => None, - }; + let rtc = config.ls.init(); set_freqs(Clocks { sys: Hertz(sysclk), diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index 7f0a2c7f..962b1dc0 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -1,6 +1,8 @@ -pub use super::bus::{AHBPrescaler, APBPrescaler}; use crate::pac::flash::vals::Latency; -use crate::pac::rcc::vals::{self, Hsidiv, Ppre, Sw}; +use crate::pac::rcc::vals::{self, Sw}; +pub use crate::pac::rcc::vals::{ + Hpre as AHBPrescaler, Hsidiv as HSI16Prescaler, Pllm, Plln, Pllp, Pllq, Pllr, Ppre as APBPrescaler, +}; use crate::pac::{FLASH, PWR, RCC}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; @@ -8,9 +10,6 @@ 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 { @@ -20,33 +19,6 @@ pub enum ClockSrc { LSI, } -#[derive(Clone, Copy)] -pub enum HSI16Prescaler { - NotDivided, - Div2, - Div4, - Div8, - Div16, - Div32, - Div64, - Div128, -} - -impl Into 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. /// /// * `VCOCLK = source / m * n` @@ -60,15 +32,15 @@ pub struct PllConfig { /// The initial divisor of that clock signal pub m: Pllm, /// The PLL VCO multiplier, which must be in the range `8..=86`. - pub n: u8, + pub n: Plln, /// The final divisor for `PLLRCLK` output which drives the system clock pub r: Pllr, /// The divisor for the `PLLQCLK` output, if desired - pub q: Option, + pub q: Option, /// The divisor for the `PLLPCLK` output, if desired - pub p: Option, + pub p: Option, } impl Default for PllConfig { @@ -77,9 +49,9 @@ impl Default for PllConfig { // HSI16 / 1 * 8 / 2 = 64 MHz PllConfig { source: PllSrc::HSI16, - m: Pllm::Div1, - n: 8, - r: Pllr::Div2, + m: Pllm::DIV1, + n: Plln::MUL8, + r: Pllr::DIV2, q: None, p: None, } @@ -92,131 +64,51 @@ pub enum PllSrc { HSE(Hertz), } -#[derive(Clone, Copy)] -pub enum Pllm { - Div1, - Div2, - Div3, - Div4, - Div5, - Div6, - Div7, - Div8, -} - -impl From 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 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 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 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 pub struct Config { pub mux: ClockSrc, pub ahb_pre: AHBPrescaler, pub apb_pre: APBPrescaler, pub low_power_run: bool, + pub ls: super::LsConfig, } impl Default for Config { #[inline] fn default() -> Config { Config { - mux: ClockSrc::HSI16(HSI16Prescaler::NotDivided), + mux: ClockSrc::HSI16(HSI16Prescaler::DIV1), ahb_pre: AHBPrescaler::DIV1, apb_pre: APBPrescaler::DIV1, low_power_run: false, + ls: Default::default(), } } } impl PllConfig { - pub(crate) fn init(self) -> u32 { - assert!(self.n >= 8 && self.n <= 86); + pub(crate) fn init(self) -> Hertz { let (src, input_freq) = match self.source { - PllSrc::HSI16 => (vals::Pllsrc::HSI16, HSI_FREQ.0), - PllSrc::HSE(freq) => (vals::Pllsrc::HSE, freq.0), + PllSrc::HSI16 => (vals::Pllsrc::HSI16, HSI_FREQ), + PllSrc::HSE(freq) => (vals::Pllsrc::HSE, freq), }; - let m_freq = input_freq / u32::from(self.m); + let m_freq = input_freq / self.m; // RM0454 § 5.4.4: // > Caution: The software must set these bits so that the PLL input frequency after the // > /M divider is between 2.66 and 16 MHz. - debug_assert!(m_freq >= 2_660_000 && m_freq <= 16_000_000); + debug_assert!(m_freq.0 >= 2_660_000 && m_freq.0 <= 16_000_000); let n_freq = m_freq * self.n as u32; // RM0454 § 5.4.4: // > Caution: The software must set these bits so that the VCO output frequency is between // > 64 and 344 MHz. - debug_assert!(n_freq >= 64_000_000 && n_freq <= 344_000_000); + debug_assert!(n_freq.0 >= 64_000_000 && n_freq.0 <= 344_000_000); - let r_freq = n_freq / u32::from(self.r); + let r_freq = n_freq / self.r; // RM0454 § 5.4.4: // > Caution: The software must set this bitfield so as not to exceed 64 MHz on this clock. - debug_assert!(r_freq <= 64_000_000); + debug_assert!(r_freq.0 <= 64_000_000); // RM0454 § 5.2.3: // > To modify the PLL configuration, proceed as follows: @@ -239,25 +131,16 @@ impl PllConfig { } } - // Configure PLLSYSCFGR - RCC.pllsyscfgr().modify(|w| { - w.set_pllr(u8::from(self.r)); + // Configure PLLCFGR + RCC.pllcfgr().modify(|w| { + w.set_pllr(self.r); w.set_pllren(false); - - if let Some(q) = self.q { - w.set_pllq(u8::from(q)); - } + w.set_pllq(self.q.unwrap_or(Pllq::DIV2)); w.set_pllqen(false); - - if let Some(p) = self.p { - w.set_pllp(u8::from(p)); - } + w.set_pllp(self.p.unwrap_or(Pllp::DIV2)); w.set_pllpen(false); - w.set_plln(self.n); - - w.set_pllm(self.m as u8); - + w.set_pllm(self.m); w.set_pllsrc(src) }); @@ -269,7 +152,7 @@ impl PllConfig { // > 5. Enable the desired PLL outputs by configuring PLLPEN, PLLQEN, and PLLREN in PLL // > configuration register (RCC_PLLCFGR). - RCC.pllsyscfgr().modify(|w| { + RCC.pllcfgr().modify(|w| { // We'll use R for system clock, so enable that unconditionally w.set_pllren(true); @@ -286,21 +169,20 @@ pub(crate) unsafe fn init(config: Config) { let (sys_clk, sw) = match config.mux { ClockSrc::HSI16(div) => { // Enable HSI16 - let div: Hsidiv = div.into(); RCC.cr().write(|w| { w.set_hsidiv(div); w.set_hsion(true) }); while !RCC.cr().read().hsirdy() {} - (HSI_FREQ.0 >> div.to_bits(), Sw::HSI) + (HSI_FREQ / div, Sw::HSI) } ClockSrc::HSE(freq) => { // Enable HSE RCC.cr().write(|w| w.set_hseon(true)); while !RCC.cr().read().hserdy() {} - (freq.0, Sw::HSE) + (freq, Sw::HSE) } ClockSrc::PLL(pll) => { let freq = pll.init(); @@ -310,15 +192,15 @@ pub(crate) unsafe fn init(config: Config) { // Enable LSI RCC.csr().write(|w| w.set_lsion(true)); while !RCC.csr().read().lsirdy() {} - (LSI_FREQ.0, Sw::LSI) + (super::LSI_FREQ, Sw::LSI) } }; // Determine the flash latency implied by the target clock speed // RM0454 § 3.3.4: - let target_flash_latency = if sys_clk <= 24_000_000 { + let target_flash_latency = if sys_clk.0 <= 24_000_000 { Latency::WS0 - } else if sys_clk <= 48_000_000 { + } else if sys_clk.0 <= 48_000_000 { Latency::WS1 } else { Latency::WS2 @@ -353,7 +235,7 @@ pub(crate) unsafe fn init(config: Config) { } // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once - let (sw, hpre, ppre) = (sw.into(), config.ahb_pre.into(), config.apb_pre.into()); + let (sw, hpre, ppre) = (sw.into(), config.ahb_pre, config.apb_pre); RCC.cfgr().modify(|w| { w.set_sw(sw); w.set_hpre(hpre); @@ -374,27 +256,28 @@ pub(crate) unsafe fn init(config: Config) { FLASH.acr().modify(|w| w.set_latency(target_flash_latency)); } - let ahb_freq = Hertz(sys_clk) / config.ahb_pre; + let ahb_freq = sys_clk / config.ahb_pre; let (apb_freq, apb_tim_freq) = match config.apb_pre { - APBPrescaler::DIV1 => (ahb_freq.0, ahb_freq.0), + APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { - let pre: Ppre = pre.into(); - let pre: u8 = 1 << (pre.to_bits() - 3); - let freq = ahb_freq.0 / pre as u32; - (freq, freq * 2) + let freq = ahb_freq / pre; + (freq, freq * 2u32) } }; if config.low_power_run { - assert!(sys_clk <= 2_000_000); + assert!(sys_clk.0 <= 2_000_000); PWR.cr1().modify(|w| w.set_lpr(true)); } + let rtc = config.ls.init(); + set_freqs(Clocks { - sys: Hertz(sys_clk), + sys: sys_clk, ahb1: ahb_freq, - apb1: Hertz(apb_freq), - apb1_tim: Hertz(apb_tim_freq), + apb1: apb_freq, + apb1_tim: apb_tim_freq, + rtc, }); } diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 41bebc91..afdf5cc7 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -2,7 +2,10 @@ use stm32_metapac::flash::vals::Latency; use stm32_metapac::rcc::vals::{Adcsel, Pllsrc, Sw}; use stm32_metapac::FLASH; -pub use super::bus::{AHBPrescaler, APBPrescaler}; +pub use crate::pac::rcc::vals::{ + Adcsel as AdcClockSource, Hpre as AHBPrescaler, Pllm as PllM, Plln as PllN, Pllp as PllP, Pllq as PllQ, + Pllr as PllR, Ppre as APBPrescaler, +}; use crate::pac::{PWR, RCC}; use crate::rcc::sealed::RccPeripheral; use crate::rcc::{set_freqs, Clocks}; @@ -11,32 +14,6 @@ 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); - -#[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 #[derive(Clone, Copy)] pub enum ClockSrc { @@ -61,181 +38,6 @@ impl Into 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 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 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 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 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 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 /// /// Use this struct to configure the PLL source, input frequency, multiplication factor, and output @@ -261,32 +63,6 @@ pub struct Pll { pub div_r: Option, } -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. pub enum Clock48MhzSrc { /// Use the High Speed Internal Oscillator. For USB usage, the CRS must be used to calibrate the @@ -322,6 +98,8 @@ pub struct Config { pub clock_48mhz_src: Option, pub adc12_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. @@ -341,8 +119,9 @@ impl Default for Config { low_power_run: false, pll: None, clock_48mhz_src: None, - adc12_clock_source: Default::default(), - adc345_clock_source: Default::default(), + adc12_clock_source: Adcsel::NOCLK, + adc345_clock_source: Adcsel::NOCLK, + ls: Default::default(), } } } @@ -360,12 +139,12 @@ pub(crate) unsafe fn init(config: Config) { RCC.cr().write(|w| w.set_hsion(true)); while !RCC.cr().read().hsirdy() {} - HSI_FREQ.0 + HSI_FREQ } PllSrc::HSE(freq) => { RCC.cr().write(|w| w.set_hseon(true)); while !RCC.cr().read().hserdy() {} - freq.0 + freq } }; @@ -373,36 +152,36 @@ pub(crate) unsafe fn init(config: Config) { RCC.cr().modify(|w| w.set_pllon(false)); while RCC.cr().read().pllrdy() {} - let internal_freq = src_freq / pll_config.prediv_m.to_div() * pll_config.mul_n.to_mul(); + let internal_freq = src_freq / pll_config.prediv_m * pll_config.mul_n; RCC.pllcfgr().write(|w| { - w.set_plln(pll_config.mul_n.into()); - w.set_pllm(pll_config.prediv_m.into()); + w.set_plln(pll_config.mul_n); + w.set_pllm(pll_config.prediv_m); w.set_pllsrc(pll_config.source.into()); }); let pll_p_freq = pll_config.div_p.map(|div_p| { RCC.pllcfgr().modify(|w| { - w.set_pllpdiv(div_p.into()); + w.set_pllp(div_p); w.set_pllpen(true); }); - Hertz(internal_freq / div_p.to_div()) + internal_freq / div_p }); let pll_q_freq = pll_config.div_q.map(|div_q| { RCC.pllcfgr().modify(|w| { - w.set_pllq(div_q.into()); + w.set_pllq(div_q); w.set_pllqen(true); }); - Hertz(internal_freq / div_q.to_div()) + internal_freq / div_q }); let pll_r_freq = pll_config.div_r.map(|div_r| { RCC.pllcfgr().modify(|w| { - w.set_pllr(div_r.into()); + w.set_pllr(div_r); w.set_pllren(true); }); - Hertz(internal_freq / div_r.to_div()) + internal_freq / div_r }); // Enable the PLL @@ -422,14 +201,14 @@ pub(crate) unsafe fn init(config: Config) { RCC.cr().write(|w| w.set_hsion(true)); while !RCC.cr().read().hsirdy() {} - (HSI_FREQ.0, Sw::HSI16) + (HSI_FREQ, Sw::HSI16) } ClockSrc::HSE(freq) => { // Enable HSE RCC.cr().write(|w| w.set_hseon(true)); while !RCC.cr().read().hserdy() {} - (freq.0, Sw::HSE) + (freq, Sw::HSE) } ClockSrc::PLL => { assert!(pll_freq.is_some()); @@ -470,35 +249,32 @@ pub(crate) unsafe fn init(config: Config) { } } - (freq, Sw::PLLRCLK) + (Hertz(freq), Sw::PLLRCLK) } }; RCC.cfgr().modify(|w| { 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()); + w.set_hpre(config.ahb_pre); + w.set_ppre1(config.apb1_pre); + w.set_ppre2(config.apb2_pre); }); - let ahb_freq: u32 = match config.ahb_pre { - AHBPrescaler::DIV1 => sys_clk, - pre => sys_clk / ahb_div(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 / apb_div(pre); - (freq, freq * 2) + 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 / apb_div(pre); - (freq, freq * 2) + let freq = ahb_freq / pre; + (freq, freq * 2u32) } }; @@ -520,7 +296,7 @@ pub(crate) unsafe fn init(config: Config) { // Enable and setup CRS if needed if let Some(crs_config) = crs_config { - crate::peripherals::CRS::enable(); + crate::peripherals::CRS::enable_and_reset(); let sync_src = match crs_config.sync_src { CrsSyncSource::Gpio => crate::pac::crs::vals::Syncsrc::GPIO, @@ -546,43 +322,40 @@ pub(crate) unsafe fn init(config: Config) { RCC.ccipr().modify(|w| w.set_clk48sel(source)); } - RCC.ccipr() - .modify(|w| w.set_adc12sel(config.adc12_clock_source.adcsel())); - RCC.ccipr() - .modify(|w| w.set_adc345sel(config.adc345_clock_source.adcsel())); + RCC.ccipr().modify(|w| w.set_adc12sel(config.adc12_clock_source)); + RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source)); let adc12_ck = match config.adc12_clock_source { - AdcClockSource::NoClk => None, - AdcClockSource::PllP => match &pll_freq { - Some(pll) => pll.pll_p, - None => None, - }, - AdcClockSource::SysClk => Some(Hertz(sys_clk)), + AdcClockSource::NOCLK => None, + AdcClockSource::PLLP => pll_freq.as_ref().unwrap().pll_p, + AdcClockSource::SYSCLK => Some(sys_clk), + _ => unreachable!(), }; let adc345_ck = match config.adc345_clock_source { - AdcClockSource::NoClk => None, - AdcClockSource::PllP => match &pll_freq { - Some(pll) => pll.pll_p, - None => None, - }, - AdcClockSource::SysClk => Some(Hertz(sys_clk)), + AdcClockSource::NOCLK => None, + AdcClockSource::PLLP => pll_freq.as_ref().unwrap().pll_p, + AdcClockSource::SYSCLK => Some(sys_clk), + _ => unreachable!(), }; if config.low_power_run { - assert!(sys_clk <= 2_000_000); + assert!(sys_clk <= Hertz(2_000_000)); PWR.cr1().modify(|w| w.set_lpr(true)); } + let rtc = config.ls.init(); + set_freqs(Clocks { - sys: Hertz(sys_clk), - ahb1: Hertz(ahb_freq), - ahb2: Hertz(ahb_freq), - apb1: Hertz(apb1_freq), - apb1_tim: Hertz(apb1_tim_freq), - apb2: Hertz(apb2_freq), - apb2_tim: Hertz(apb2_tim_freq), + sys: sys_clk, + ahb1: ahb_freq, + ahb2: ahb_freq, + apb1: apb1_freq, + apb1_tim: apb1_tim_freq, + apb2: apb2_freq, + apb2_tim: apb2_tim_freq, adc: adc12_ck, adc34: adc345_ck, + rtc, }); } diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs index 43e8db22..a24f4d4e 100644 --- a/embassy-stm32/src/rcc/h.rs +++ b/embassy-stm32/src/rcc/h.rs @@ -6,8 +6,8 @@ use crate::pac::pwr::vals::Vos; pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource; #[cfg(stm32h7)] pub use crate::pac::rcc::vals::Adcsel as AdcClockSource; -pub use crate::pac::rcc::vals::Ckpersel as PerClockSource; use crate::pac::rcc::vals::{Ckpersel, Hsidiv, Pllrge, Pllsrc, Pllvcosel, Sw, Timpre}; +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::rcc::{set_freqs, Clocks}; use crate::time::Hertz; @@ -21,18 +21,15 @@ pub const CSI_FREQ: Hertz = Hertz(4_000_000); /// HSI48 speed pub const HSI48_FREQ: Hertz = Hertz(48_000_000); -/// LSI speed -pub const LSI_FREQ: Hertz = Hertz(32_000); - -const VCO_RANGE: RangeInclusive = 150_000_000..=420_000_000; +const VCO_RANGE: RangeInclusive = Hertz(150_000_000)..=Hertz(420_000_000); #[cfg(any(stm32h5, pwr_h7rm0455))] -const VCO_WIDE_RANGE: RangeInclusive = 128_000_000..=560_000_000; +const VCO_WIDE_RANGE: RangeInclusive = Hertz(128_000_000)..=Hertz(560_000_000); #[cfg(pwr_h7rm0468)] -const VCO_WIDE_RANGE: RangeInclusive = 192_000_000..=836_000_000; +const VCO_WIDE_RANGE: RangeInclusive = Hertz(192_000_000)..=Hertz(836_000_000); #[cfg(any(pwr_h7rm0399, pwr_h7rm0433))] -const VCO_WIDE_RANGE: RangeInclusive = 192_000_000..=960_000_000; +const VCO_WIDE_RANGE: RangeInclusive = Hertz(192_000_000)..=Hertz(960_000_000); -pub use super::bus::{AHBPrescaler, APBPrescaler}; +pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; #[derive(Clone, Copy, Eq, PartialEq)] pub enum VoltageScale { @@ -46,9 +43,9 @@ pub enum VoltageScale { pub enum HseMode { /// crystal/ceramic oscillator (HSEBYP=0) Oscillator, - /// external analog clock (low swing) (HSEBYP=1, HSEEXT=0) + /// external analog clock (low swing) (HSEBYP=1, HSEEXT=0) 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))] BypassDigital, } @@ -61,6 +58,15 @@ pub struct Hse { 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)] pub enum Hsi { /// 64Mhz @@ -98,19 +104,19 @@ pub struct Pll { #[cfg(stm32h5)] pub source: PllSource, - /// PLL pre-divider (DIVM). Must be between 1 and 63. - pub prediv: u8, + /// PLL pre-divider (DIVM). + pub prediv: PllPreDiv, - /// PLL multiplication factor. Must be between 4 and 512. - pub mul: u16, + /// PLL multiplication factor. + pub mul: PllMul, - /// PLL P division factor. If None, PLL P output is disabled. Must be between 1 and 128. + /// PLL P division factor. If None, PLL P output is disabled. /// On PLL1, it must be even (in particular, it cannot be 1.) - pub divp: Option, - /// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128. - pub divq: Option, - /// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128. - pub divr: Option, + pub divp: Option, + /// PLL Q division factor. If None, PLL Q output is disabled. + pub divq: Option, + /// PLL R division factor. If None, PLL R output is disabled. + pub divr: Option, } fn apb_div_tim(apb: &APBPrescaler, clk: Hertz, tim: TimerPrescaler) -> Hertz { @@ -157,6 +163,10 @@ impl From for Timpre { pub struct Config { pub hsi: Option, pub hse: Option, + #[cfg(stm32h7)] + pub lse: Option, + #[cfg(stm32h7)] + pub lsi: bool, pub csi: bool, pub hsi48: bool, pub sys: Sysclk, @@ -181,6 +191,7 @@ pub struct Config { pub adc_clock_source: AdcClockSource, pub timer_prescaler: TimerPrescaler, pub voltage_scale: VoltageScale, + pub ls: super::LsConfig, } impl Default for Config { @@ -188,6 +199,10 @@ impl Default for Config { Self { hsi: Some(Hsi::Mhz64), hse: None, + #[cfg(stm32h7)] + lse: None, + #[cfg(stm32h7)] + lsi: false, csi: false, hsi48: false, sys: Sysclk::HSI, @@ -210,6 +225,7 @@ impl Default for Config { adc_clock_source: AdcClockSource::from_bits(0), // PLL2_P on H7, HCLK on H5 timer_prescaler: TimerPrescaler::DefaultX2, voltage_scale: VoltageScale::Scale0, + ls: Default::default(), } } } @@ -372,7 +388,7 @@ pub(crate) unsafe fn init(config: Config) { let pll1 = init_pll(0, config.pll1, &pll_input); let pll2 = init_pll(1, config.pll2, &pll_input); #[cfg(any(rcc_h5, stm32h7))] - let _pll3 = init_pll(2, config.pll3, &pll_input); + let pll3 = init_pll(2, config.pll3, &pll_input); // Configure sysclk let (sys, sw) = match config.sys { @@ -431,7 +447,7 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(stm32h7)] let adc = match config.adc_clock_source { AdcClockSource::PLL2_P => pll2.p, - AdcClockSource::PLL3_R => _pll3.r, + AdcClockSource::PLL3_R => pll3.r, AdcClockSource::PER => _per_ck, _ => unreachable!(), }; @@ -441,13 +457,15 @@ pub(crate) unsafe fn init(config: Config) { AdcClockSource::SYSCLK => Some(sys), AdcClockSource::PLL2_R => pll2.r, AdcClockSource::HSE => hse, - AdcClockSource::HSI_KER => hsi, - AdcClockSource::CSI_KER => csi, + AdcClockSource::HSI => hsi, + AdcClockSource::CSI => csi, _ => unreachable!(), }; flash_setup(hclk, config.voltage_scale); + let rtc = config.ls.init(); + #[cfg(stm32h7)] { RCC.d1cfgr().modify(|w| { @@ -523,9 +541,55 @@ pub(crate) unsafe fn init(config: Config) { apb3, #[cfg(stm32h7)] apb4, + #[cfg(stm32h5)] + apb4: Hertz(1), apb1_tim, apb2_tim, - adc: adc, + adc, + rtc, + + #[cfg(stm32h5)] + hsi: None, + #[cfg(stm32h5)] + hsi48: None, + #[cfg(stm32h5)] + lsi: None, + #[cfg(stm32h5)] + csi: None, + + #[cfg(stm32h5)] + lse: None, + #[cfg(stm32h5)] + hse: None, + + #[cfg(stm32h5)] + pll1_q: pll1.q, + #[cfg(stm32h5)] + pll2_q: pll2.q, + #[cfg(stm32h5)] + pll2_p: pll2.p, + #[cfg(stm32h5)] + pll2_r: pll2.r, + #[cfg(rcc_h5)] + pll3_p: pll3.p, + #[cfg(rcc_h5)] + pll3_q: pll3.q, + #[cfg(rcc_h5)] + pll3_r: pll3.r, + #[cfg(stm32h5)] + pll3_1: None, + + #[cfg(rcc_h50)] + pll3_p: None, + #[cfg(rcc_h50)] + pll3_q: None, + #[cfg(rcc_h50)] + pll3_r: None, + + #[cfg(stm32h5)] + audioclk: None, + #[cfg(stm32h5)] + per: None, }); } @@ -553,9 +617,9 @@ fn init_pll(num: usize, config: Option, input: &PllInput) -> PllOutput { // "To save power when PLL1 is not used, the value of PLL1M must be set to 0."" #[cfg(stm32h7)] - RCC.pllckselr().write(|w| w.set_divm(num, 0)); + RCC.pllckselr().write(|w| w.set_divm(num, PllPreDiv::from_bits(0))); #[cfg(stm32h5)] - RCC.pllcfgr(num).write(|w| w.set_divm(0)); + RCC.pllcfgr(num).write(|w| w.set_divm(PllPreDiv::from_bits(0))); return PllOutput { p: None, @@ -564,9 +628,6 @@ fn init_pll(num: usize, config: Option, input: &PllInput) -> PllOutput { }; }; - assert!(1 <= config.prediv && config.prediv <= 63); - assert!(4 <= config.mul && config.mul <= 512); - #[cfg(stm32h5)] let source = config.source; #[cfg(stm32h7)] @@ -593,31 +654,25 @@ fn init_pll(num: usize, config: Option, input: &PllInput) -> PllOutput { let wide_allowed = ref_range != Pllrge::RANGE1; let vco_clk = ref_clk * config.mul; - let vco_range = if VCO_RANGE.contains(&vco_clk.0) { + let vco_range = if VCO_RANGE.contains(&vco_clk) { Pllvcosel::MEDIUMVCO - } else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk.0) { + } else if wide_allowed && VCO_WIDE_RANGE.contains(&vco_clk) { Pllvcosel::WIDEVCO } else { panic!("pll vco_clk out of range: {} mhz", vco_clk.0) }; let p = config.divp.map(|div| { - assert!(1 <= div && div <= 128); if num == 0 { // on PLL1, DIVP must be even. - assert!(div % 2 == 0); + // The enum value is 1 less than the divider, so check it's odd. + assert!(div.to_bits() % 2 == 1); } vco_clk / div }); - let q = config.divq.map(|div| { - assert!(1 <= div && div <= 128); - vco_clk / div - }); - let r = config.divr.map(|div| { - assert!(1 <= div && div <= 128); - vco_clk / div - }); + let q = config.divq.map(|div| vco_clk / div); + let r = config.divr.map(|div| vco_clk / div); #[cfg(stm32h5)] RCC.pllcfgr(num).write(|w| { @@ -648,10 +703,10 @@ fn init_pll(num: usize, config: Option, input: &PllInput) -> PllOutput { } RCC.plldivr(num).write(|w| { - w.set_plln(config.mul - 1); - w.set_pllp((config.divp.unwrap_or(1) - 1) as u8); - w.set_pllq((config.divq.unwrap_or(1) - 1) as u8); - w.set_pllr((config.divr.unwrap_or(1) - 1) as u8); + w.set_plln(config.mul); + w.set_pllp(config.divp.unwrap_or(PllDiv::DIV2)); + w.set_pllq(config.divq.unwrap_or(PllDiv::DIV2)); + w.set_pllr(config.divr.unwrap_or(PllDiv::DIV2)); }); RCC.cr().modify(|w| w.set_pllon(num, true)); diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs deleted file mode 100644 index 7358be31..00000000 --- a/embassy-stm32/src/rcc/l0.rs +++ /dev/null @@ -1,349 +0,0 @@ -use super::bd::BackupDomain; -pub use super::bus::{AHBPrescaler, APBPrescaler}; -use super::RtcClockSource; -pub use crate::pac::pwr::vals::Vos as VoltageScale; -use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; -#[cfg(crs)] -use crate::pac::{crs, CRS, SYSCFG}; -use crate::pac::{FLASH, PWR, RCC}; -use crate::rcc::{set_freqs, Clocks}; -use crate::time::Hertz; - -/// HSI speed -pub const HSI_FREQ: Hertz = Hertz(16_000_000); - -/// LSI speed -pub const LSI_FREQ: Hertz = Hertz(32_000); - -/// System clock mux source -#[derive(Clone, Copy)] -pub enum ClockSrc { - MSI(MSIRange), - PLL(PLLSource, PLLMul, PLLDiv), - HSE(Hertz), - HSI16, -} - -/// MSI Clock Range -/// -/// These ranges control the frequency of the MSI. Internally, these ranges map -/// to the `MSIRANGE` bits in the `RCC_ICSCR` register. -#[derive(Clone, Copy)] -pub enum MSIRange { - /// Around 65.536 kHz - Range0, - /// Around 131.072 kHz - Range1, - /// Around 262.144 kHz - Range2, - /// Around 524.288 kHz - Range3, - /// Around 1.048 MHz - Range4, - /// Around 2.097 MHz (reset value) - Range5, - /// Around 4.194 MHz - Range6, -} - -impl Default for MSIRange { - fn default() -> MSIRange { - MSIRange::Range5 - } -} - -/// PLL divider -#[derive(Clone, Copy)] -pub enum PLLDiv { - Div2, - Div3, - Div4, -} - -/// PLL multiplier -#[derive(Clone, Copy)] -pub enum PLLMul { - Mul3, - Mul4, - Mul6, - Mul8, - Mul12, - Mul16, - Mul24, - Mul32, - Mul48, -} - -/// PLL clock input source -#[derive(Clone, Copy)] -pub enum PLLSource { - HSI16, - HSE(Hertz), -} - -impl From 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 for Plldiv { - fn from(val: PLLDiv) -> Plldiv { - match val { - PLLDiv::Div2 => Plldiv::DIV2, - PLLDiv::Div3 => Plldiv::DIV3, - PLLDiv::Div4 => Plldiv::DIV4, - } - } -} - -impl From for Pllsrc { - fn from(val: PLLSource) -> Pllsrc { - match val { - PLLSource::HSI16 => Pllsrc::HSI16, - PLLSource::HSE(_) => Pllsrc::HSE, - } - } -} - -impl From 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, - pub lse: Option, - 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), - }); -} diff --git a/embassy-stm32/src/rcc/l0l1.rs b/embassy-stm32/src/rcc/l0l1.rs new file mode 100644 index 00000000..d8a1fc10 --- /dev/null +++ b/embassy-stm32/src/rcc/l0l1.rs @@ -0,0 +1,219 @@ +pub use crate::pac::pwr::vals::Vos as VoltageScale; +pub use crate::pac::rcc::vals::{ + Hpre as AHBPrescaler, Msirange as MSIRange, Plldiv as PLLDiv, Pllmul as PLLMul, Ppre as APBPrescaler, +}; +use crate::pac::rcc::vals::{Pllsrc, Sw}; +#[cfg(crs)] +use crate::pac::{crs, CRS, SYSCFG}; +use crate::pac::{FLASH, PWR, RCC}; +use crate::rcc::{set_freqs, Clocks}; +use crate::time::Hertz; + +/// HSI speed +pub const HSI_FREQ: Hertz = Hertz(16_000_000); + +/// System clock mux source +#[derive(Clone, Copy)] +pub enum ClockSrc { + MSI(MSIRange), + PLL(PLLSource, PLLMul, PLLDiv), + HSE(Hertz), + HSI16, +} + +/// PLL clock input source +#[derive(Clone, Copy)] +pub enum PLLSource { + HSI16, + HSE(Hertz), +} + +impl From 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, + }); +} diff --git a/embassy-stm32/src/rcc/l1.rs b/embassy-stm32/src/rcc/l1.rs deleted file mode 100644 index 90524fb3..00000000 --- a/embassy-stm32/src/rcc/l1.rs +++ /dev/null @@ -1,279 +0,0 @@ -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 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 for Plldiv { - fn from(val: PLLDiv) -> Plldiv { - match val { - PLLDiv::Div2 => Plldiv::DIV2, - PLLDiv::Div3 => Plldiv::DIV3, - PLLDiv::Div4 => Plldiv::DIV4, - } - } -} - -impl From for Pllsrc { - fn from(val: PLLSource) -> Pllsrc { - match val { - PLLSource::HSI => Pllsrc::HSI, - PLLSource::HSE(_) => Pllsrc::HSE, - } - } -} - -impl From 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), - }); -} diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index 6f1f7458..1e5733d3 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs @@ -1,85 +1,25 @@ -use core::marker::PhantomData; - -use embassy_hal_internal::into_ref; -use stm32_metapac::rcc::regs::Cfgr; -use stm32_metapac::rcc::vals::{Mcopre, Mcosel}; - -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::rcc::regs::Cfgr; +pub use crate::pac::rcc::vals::{ + Hpre as AHBPrescaler, Msirange as MSIRange, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, + Pllr as PllRDiv, Ppre as APBPrescaler, +}; +use crate::pac::rcc::vals::{Msirange, Pllsrc, Sw}; use crate::pac::{FLASH, RCC}; -use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; -use crate::{peripherals, Peripheral}; /// 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, PLLClkDiv, PLLSrcDiv, PLLMul, Option), + PLL(PLLSource, PllRDiv, PllPreDiv, PllMul, Option), 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 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 #[derive(Clone, Copy)] pub enum PLLSource { @@ -88,95 +28,6 @@ pub enum PLLSource { MSI(MSIRange), } -seq_macro::seq!(N in 8..=86 { - #[derive(Clone, Copy)] - pub enum PLLMul { - #( - Mul~N, - )* - } - - impl From 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 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 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 for Pllsrc { fn from(val: PLLSource) -> Pllsrc { match val { @@ -187,214 +38,41 @@ impl From for Pllsrc { } } -impl From 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 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 pub struct Config { pub mux: ClockSrc, pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, pub apb2_pre: APBPrescaler, - pub pllsai1: Option<( - PLLMul, - PLLSrcDiv, - Option, - Option, - Option, - )>, + pub pllsai1: Option<(PllMul, PllPreDiv, Option, Option, Option)>, #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] pub hsi48: bool, - pub rtc_mux: RtcClockSource, - pub lse: Option, - pub lsi: bool, + pub ls: super::LsConfig, } impl Default for Config { #[inline] fn default() -> Config { Config { - mux: ClockSrc::MSI(MSIRange::Range6), + mux: ClockSrc::MSI(MSIRange::RANGE4M), ahb_pre: AHBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, pllsai1: None, #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] hsi48: false, - rtc_mux: RtcClockSource::LSI, - lsi: true, - lse: None, + ls: Default::default(), } } } -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

+ 'd, - pin: impl Peripheral

> + 'd, - source: impl McoSource, - 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) { // 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::default().into()); + w.set_msirange(MSIRange::RANGE4M); w.set_msipllen(false); w.set_msion(true) }); @@ -409,73 +87,68 @@ pub(crate) unsafe fn init(config: Config) { while RCC.cfgr().read().sws() != Sw::MSI {} } - BackupDomain::configure_ls(config.rtc_mux, config.lsi, config.lse.map(|_| Default::default())); + let rtc = config.ls.init(); let (sys_clk, sw) = match config.mux { ClockSrc::MSI(range) => { // Enable MSI RCC.cr().write(|w| { - let bits: Msirange = range.into(); - w.set_msirange(bits); + w.set_msirange(range); w.set_msirgsel(true); w.set_msion(true); - if let RtcClockSource::LSE = config.rtc_mux { - // If LSE is enabled, enable calibration of MSI - w.set_msipllen(true); - } else { - w.set_msipllen(false); - } + // If LSE is enabled, enable calibration of MSI + w.set_msipllen(config.ls.lse.is_some()); }); while !RCC.cr().read().msirdy() {} // Enable as clock source for USB, RNG if running at 48 MHz - if let MSIRange::Range11 = range { + if range == MSIRange::RANGE48M { RCC.ccipr().modify(|w| { w.set_clk48sel(0b11); }); } - (range.into(), Sw::MSI) + (msirange_to_hertz(range), Sw::MSI) } ClockSrc::HSI16 => { // Enable HSI16 RCC.cr().write(|w| w.set_hsion(true)); while !RCC.cr().read().hsirdy() {} - (HSI_FREQ.0, Sw::HSI16) + (HSI_FREQ, Sw::HSI16) } ClockSrc::HSE(freq) => { // Enable HSE RCC.cr().write(|w| w.set_hseon(true)); while !RCC.cr().read().hserdy() {} - (freq.0, Sw::HSE) + (freq, Sw::HSE) } - ClockSrc::PLL(src, div, prediv, mul, pll48div) => { + ClockSrc::PLL(src, divr, prediv, mul, divq) => { let src_freq = match src { PLLSource::HSE(freq) => { // Enable HSE RCC.cr().write(|w| w.set_hseon(true)); while !RCC.cr().read().hserdy() {} - freq.0 + freq } PLLSource::HSI16 => { // Enable HSI RCC.cr().write(|w| w.set_hsion(true)); while !RCC.cr().read().hsirdy() {} - HSI_FREQ.0 + HSI_FREQ } PLLSource::MSI(range) => { // Enable MSI RCC.cr().write(|w| { - let bits: Msirange = range.into(); - w.set_msirange(bits); + w.set_msirange(range); w.set_msipllen(false); // should be turned on if LSE is started w.set_msirgsel(true); w.set_msion(true); }); while !RCC.cr().read().msirdy() {} - range.into() + + msirange_to_hertz(range) } }; @@ -483,28 +156,28 @@ pub(crate) unsafe fn init(config: Config) { RCC.cr().modify(|w| w.set_pllon(false)); while RCC.cr().read().pllrdy() {} - let freq = (src_freq / prediv.to_div() * mul.to_mul()) / div.to_div(); + let freq = src_freq / prediv * mul / divr; #[cfg(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx))] - assert!(freq <= 120_000_000); + assert!(freq.0 <= 120_000_000); #[cfg(not(any(stm32l4px, stm32l4qx, stm32l4rx, stm32l4sx)))] - assert!(freq <= 80_000_000); + assert!(freq.0 <= 80_000_000); RCC.pllcfgr().write(move |w| { - w.set_plln(mul.into()); - w.set_pllm(prediv.into()); - w.set_pllr(div.into()); - if let Some(pll48div) = pll48div { - w.set_pllq(pll48div.into()); + w.set_plln(mul); + w.set_pllm(prediv); + w.set_pllr(divr); + if let Some(divq) = divq { + w.set_pllq(divq); w.set_pllqen(true); } w.set_pllsrc(src.into()); }); // Enable as clock source for USB, RNG if PLL48 divisor is provided - if let Some(pll48div) = pll48div { - let freq = (src_freq / prediv.to_div() * mul.to_mul()) / pll48div.to_div(); - assert!(freq == 48_000_000); + if let Some(divq) = divq { + let freq = src_freq / prediv * mul / divq; + assert!(freq.0 == 48_000_000); RCC.ccipr().modify(|w| { w.set_clk48sel(0b10); }); @@ -512,25 +185,25 @@ pub(crate) unsafe fn init(config: Config) { if let Some((mul, prediv, r_div, q_div, p_div)) = config.pllsai1 { RCC.pllsai1cfgr().write(move |w| { - w.set_pllsai1n(mul.into()); - w.set_pllsai1m(prediv.into()); + w.set_plln(mul); + w.set_pllm(prediv); if let Some(r_div) = r_div { - w.set_pllsai1r(r_div.into()); - w.set_pllsai1ren(true); + w.set_pllr(r_div); + w.set_pllren(true); } if let Some(q_div) = q_div { - w.set_pllsai1q(q_div.into()); - w.set_pllsai1qen(true); - let freq = (src_freq / prediv.to_div() * mul.to_mul()) / q_div.to_div(); - if freq == 48_000_000 { + w.set_pllq(q_div); + w.set_pllqen(true); + let freq = src_freq / prediv * mul / q_div; + if freq.0 == 48_000_000 { RCC.ccipr().modify(|w| { w.set_clk48sel(0b1); }); } } if let Some(p_div) = p_div { - w.set_pllsai1pdiv(p_div.into()); - w.set_pllsai1pen(true); + w.set_pllp(p_div); + w.set_pllpen(true); } }); @@ -557,63 +230,67 @@ pub(crate) unsafe fn init(config: Config) { // Set flash wait states FLASH.acr().modify(|w| { - w.set_latency(if sys_clk <= 16_000_000 { - 0b000 - } else if sys_clk <= 32_000_000 { - 0b001 - } else if sys_clk <= 48_000_000 { - 0b010 - } else if sys_clk <= 64_000_000 { - 0b011 - } else { - 0b100 - }); + w.set_latency(match sys_clk.0 { + 0..=16_000_000 => 0, + 0..=32_000_000 => 1, + 0..=48_000_000 => 2, + 0..=64_000_000 => 3, + _ => 4, + }) }); 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()); + w.set_hpre(config.ahb_pre); + w.set_ppre1(config.apb1_pre); + w.set_ppre2(config.apb2_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 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 pre: Ppre = pre.into(); - let pre: u8 = 1 << (pre.to_bits() - 3); - let freq = ahb_freq / pre as u32; - (freq, freq * 2) + 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 pre: Ppre = pre.into(); - let pre: u8 = 1 << (pre.to_bits() - 3); - let freq = ahb_freq / pre as u32; - (freq, freq * 2) + let freq = ahb_freq / pre; + (freq, freq * 2u32) } }; set_freqs(Clocks { - sys: Hertz(sys_clk), - ahb1: Hertz(ahb_freq), - ahb2: Hertz(ahb_freq), - ahb3: Hertz(ahb_freq), - apb1: Hertz(apb1_freq), - apb2: Hertz(apb2_freq), - apb1_tim: Hertz(apb1_tim_freq), - apb2_tim: Hertz(apb2_tim_freq), + sys: sys_clk, + ahb1: ahb_freq, + ahb2: ahb_freq, + ahb3: ahb_freq, + apb1: apb1_freq, + apb2: apb2_freq, + apb1_tim: apb1_tim_freq, + apb2_tim: 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!(), + } +} diff --git a/embassy-stm32/src/rcc/l5.rs b/embassy-stm32/src/rcc/l5.rs index 652bdcb7..1f4e0034 100644 --- a/embassy-stm32/src/rcc/l5.rs +++ b/embassy-stm32/src/rcc/l5.rs @@ -1,77 +1,25 @@ -use stm32_metapac::PWR; - -pub use super::bus::{AHBPrescaler, APBPrescaler}; -use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw}; -use crate::pac::{FLASH, RCC}; +use crate::pac::rcc::regs::Cfgr; +pub use crate::pac::rcc::vals::{ + Hpre as AHBPrescaler, Msirange as MSIRange, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, + Pllr as PllRDiv, Ppre as APBPrescaler, +}; +use crate::pac::rcc::vals::{Msirange, Pllsrc, Sw}; +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, PLLClkDiv, PLLSrcDiv, PLLMul, Option), + PLL(PLLSource, PllRDiv, PllPreDiv, PllMul, Option), 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 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 #[derive(Clone, Copy)] pub enum PLLSource { @@ -80,95 +28,6 @@ pub enum PLLSource { MSI(MSIRange), } -seq_macro::seq!(N in 8..=86 { - #[derive(Clone, Copy)] - pub enum PLLMul { - #( - Mul~N, - )* - } - - impl From 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 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 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 for Pllsrc { fn from(val: PLLSource) -> Pllsrc { match val { @@ -179,135 +38,116 @@ impl From for Pllsrc { } } -impl From 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 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 pub struct Config { pub mux: ClockSrc, pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, pub apb2_pre: APBPrescaler, - pub pllsai1: Option<( - PLLMul, - PLLSrcDiv, - Option, - Option, - Option, - )>, + pub pllsai1: Option<(PllMul, PllPreDiv, Option, Option, Option)>, pub hsi48: bool, + pub ls: super::LsConfig, } impl Default for Config { #[inline] fn default() -> Config { Config { - mux: ClockSrc::MSI(MSIRange::Range6), + mux: ClockSrc::MSI(MSIRange::RANGE4M), ahb_pre: AHBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, pllsai1: None, hsi48: false, + ls: Default::default(), } } } 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)); let (sys_clk, sw) = match config.mux { ClockSrc::MSI(range) => { // Enable MSI RCC.cr().write(|w| { - let bits: Msirange = range.into(); - w.set_msirange(bits); - w.set_msipllen(false); + w.set_msirange(range); w.set_msirgsel(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() {} // Enable as clock source for USB, RNG if running at 48 MHz - if let MSIRange::Range11 = range { + if range == MSIRange::RANGE48M { RCC.ccipr1().modify(|w| { w.set_clk48msel(0b11); }); } - (range.into(), Sw::MSI) + (msirange_to_hertz(range), Sw::MSI) } ClockSrc::HSI16 => { // Enable HSI16 RCC.cr().write(|w| w.set_hsion(true)); while !RCC.cr().read().hsirdy() {} - (HSI_FREQ.0, Sw::HSI16) + (HSI_FREQ, Sw::HSI16) } ClockSrc::HSE(freq) => { // Enable HSE RCC.cr().write(|w| w.set_hseon(true)); while !RCC.cr().read().hserdy() {} - (freq.0, Sw::HSE) + (freq, Sw::HSE) } - ClockSrc::PLL(src, div, prediv, mul, pll48div) => { + ClockSrc::PLL(src, divr, prediv, mul, divq) => { let src_freq = match src { PLLSource::HSE(freq) => { // Enable HSE RCC.cr().write(|w| w.set_hseon(true)); while !RCC.cr().read().hserdy() {} - freq.0 + freq } PLLSource::HSI16 => { // Enable HSI RCC.cr().write(|w| w.set_hsion(true)); while !RCC.cr().read().hsirdy() {} - HSI_FREQ.0 + HSI_FREQ } PLLSource::MSI(range) => { // Enable MSI RCC.cr().write(|w| { - let bits: Msirange = range.into(); - w.set_msirange(bits); + w.set_msirange(range); w.set_msipllen(false); // should be turned on if LSE is started w.set_msirgsel(true); w.set_msion(true); }); while !RCC.cr().read().msirdy() {} - range.into() + + msirange_to_hertz(range) } }; @@ -315,23 +155,23 @@ pub(crate) unsafe fn init(config: Config) { RCC.cr().modify(|w| w.set_pllon(false)); while RCC.cr().read().pllrdy() {} - let freq = (src_freq / prediv.to_div() * mul.to_mul()) / div.to_div(); + let freq = src_freq / prediv * mul / divr; RCC.pllcfgr().write(move |w| { - w.set_plln(mul.into()); - w.set_pllm(prediv.into()); - w.set_pllr(div.into()); - if let Some(pll48div) = pll48div { - w.set_pllq(pll48div.into()); + w.set_plln(mul); + w.set_pllm(prediv); + w.set_pllr(divr); + if let Some(divq) = divq { + w.set_pllq(divq); w.set_pllqen(true); } w.set_pllsrc(src.into()); }); // Enable as clock source for USB, RNG if PLL48 divisor is provided - if let Some(pll48div) = pll48div { - let freq = (src_freq / prediv.to_div() * mul.to_mul()) / pll48div.to_div(); - assert!(freq == 48_000_000); + if let Some(divq) = divq { + let freq = src_freq / prediv * mul / divq; + assert!(freq.0 == 48_000_000); RCC.ccipr1().modify(|w| { w.set_clk48msel(0b10); }); @@ -339,25 +179,25 @@ pub(crate) unsafe fn init(config: Config) { if let Some((mul, prediv, r_div, q_div, p_div)) = config.pllsai1 { RCC.pllsai1cfgr().write(move |w| { - w.set_pllsai1n(mul.into()); - w.set_pllsai1m(prediv.into()); + w.set_plln(mul); + w.set_pllm(prediv); if let Some(r_div) = r_div { - w.set_pllsai1r(r_div.into()); - w.set_pllsai1ren(true); + w.set_pllr(r_div); + w.set_pllren(true); } if let Some(q_div) = q_div { - w.set_pllsai1q(q_div.into()); - w.set_pllsai1qen(true); - let freq = (src_freq / prediv.to_div() * mul.to_mul()) / q_div.to_div(); - if freq == 48_000_000 { + w.set_pllq(q_div); + w.set_pllqen(true); + let freq = src_freq / prediv * mul / q_div; + if freq.0 == 48_000_000 { RCC.ccipr1().modify(|w| { w.set_clk48msel(0b1); }); } } if let Some(p_div) = p_div { - w.set_pllsai1pdiv(p_div.into()); - w.set_pllsai1pen(true); + w.set_pllp(p_div); + w.set_pllpen(true); } }); @@ -384,7 +224,7 @@ pub(crate) unsafe fn init(config: Config) { // Set flash wait states // VCORE Range 0 (performance), others TODO FLASH.acr().modify(|w| { - w.set_latency(match sys_clk { + w.set_latency(match sys_clk.0 { 0..=20_000_000 => 0, 0..=40_000_000 => 1, 0..=60_000_000 => 2, @@ -396,48 +236,56 @@ pub(crate) unsafe fn init(config: Config) { 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()); + w.set_hpre(config.ahb_pre); + w.set_ppre1(config.apb1_pre); + w.set_ppre2(config.apb2_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 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 pre: Ppre = pre.into(); - let pre: u8 = 1 << (pre.to_bits() - 3); - let freq = ahb_freq / pre as u32; - (freq, freq * 2) + 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 pre: Ppre = pre.into(); - let pre: u8 = 1 << (pre.to_bits() - 3); - let freq = ahb_freq / pre as u32; - (freq, freq * 2) + let freq = ahb_freq / pre; + (freq, freq * 2u32) } }; set_freqs(Clocks { - sys: Hertz(sys_clk), - ahb1: Hertz(ahb_freq), - ahb2: Hertz(ahb_freq), - ahb3: Hertz(ahb_freq), - apb1: Hertz(apb1_freq), - apb2: Hertz(apb2_freq), - apb1_tim: Hertz(apb1_tim_freq), - apb2_tim: Hertz(apb2_tim_freq), + sys: sys_clk, + ahb1: ahb_freq, + ahb2: ahb_freq, + ahb3: ahb_freq, + apb1: apb1_freq, + apb2: apb2_freq, + apb1_tim: apb1_tim_freq, + apb2_tim: 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!(), + } +} diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs index 2453ed82..eaaf8071 100644 --- a/embassy-stm32/src/rcc/mco.rs +++ b/embassy-stm32/src/rcc/mco.rs @@ -4,14 +4,19 @@ use embassy_hal_internal::into_ref; use crate::gpio::sealed::AFType; use crate::gpio::Speed; -pub use crate::pac::rcc::vals::{Mco1 as Mco1Source, Mco2 as Mco2Source}; +#[cfg(not(stm32f1))] +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::{peripherals, Peripheral}; pub(crate) mod sealed { pub trait McoInstance { type Source; - unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8); + unsafe fn apply_clock_settings(source: Self::Source, #[cfg(not(stm32f1))] prescaler: super::McoPrescaler); } } @@ -24,9 +29,15 @@ macro_rules! impl_peri { impl sealed::McoInstance for peripherals::$peri { type Source = $source; - unsafe fn apply_clock_settings(source: Self::Source, prescaler: u8) { - RCC.cfgr().modify(|w| { + unsafe fn apply_clock_settings(source: Self::Source, #[cfg(not(stm32f1))] prescaler: McoPrescaler) { + #[cfg(not(any(stm32u5, stm32wba)))] + let r = RCC.cfgr(); + #[cfg(any(stm32u5, stm32wba))] + let r = RCC.cfgr1(); + + r.modify(|w| { w.$set_source(source); + #[cfg(not(stm32f1))] w.$set_prescaler(prescaler); }); } @@ -36,8 +47,16 @@ macro_rules! impl_peri { }; } -impl_peri!(MCO1, Mco1Source, set_mco1, set_mco1pre); -impl_peri!(MCO2, Mco2Source, set_mco2, set_mco2pre); +#[cfg(any(rcc_c0, rcc_g0))] +#[allow(unused_imports)] +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> { phantom: PhantomData<&'d mut T>, @@ -45,23 +64,20 @@ pub struct Mco<'d, T: McoInstance> { impl<'d, T: McoInstance> Mco<'d, T> { /// Create a new MCO instance. - /// - /// `prescaler` must be between 1 and 15. pub fn new( _peri: impl Peripheral

+ 'd, pin: impl Peripheral

> + 'd, source: T::Source, - prescaler: u8, + #[cfg(not(stm32f1))] prescaler: McoPrescaler, ) -> Self { into_ref!(pin); - assert!( - 1 <= prescaler && prescaler <= 15, - "Mco prescaler must be between 1 and 15. Refer to the reference manual for more information." - ); - critical_section::with(|_| unsafe { - T::apply_clock_settings(source, prescaler); + T::apply_clock_settings( + source, + #[cfg(not(stm32f1))] + prescaler, + ); pin.set_as_af(pin.af_num(), AFType::OutputPushPull); pin.set_speed(Speed::VeryHigh); }); diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 9ccf2ac4..0904ddbd 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -2,14 +2,11 @@ use core::mem::MaybeUninit; -pub use crate::rcc::bd::RtcClockSource; use crate::time::Hertz; -pub(crate) mod bd; -mod bus; -#[cfg(any(stm32h5, stm32h7))] +mod bd; mod mco; -#[cfg(any(stm32h5, stm32h7))] +pub use bd::*; pub use mco::*; #[cfg_attr(rcc_f0, path = "f0.rs")] @@ -21,9 +18,8 @@ pub use mco::*; #[cfg_attr(rcc_c0, path = "c0.rs")] #[cfg_attr(rcc_g0, path = "g0.rs")] #[cfg_attr(rcc_g4, path = "g4.rs")] -#[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab), path = "h.rs")] -#[cfg_attr(rcc_l0, path = "l0.rs")] -#[cfg_attr(rcc_l1, path = "l1.rs")] +#[cfg_attr(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab), path = "h.rs")] +#[cfg_attr(any(rcc_l0, rcc_l0_v2, rcc_l1), path = "l0l1.rs")] #[cfg_attr(rcc_l4, path = "l4.rs")] #[cfg_attr(rcc_l5, path = "l5.rs")] #[cfg_attr(rcc_u5, path = "u5.rs")] @@ -31,9 +27,10 @@ pub use mco::*; #[cfg_attr(rcc_wba, path = "wba.rs")] #[cfg_attr(any(rcc_wl5, rcc_wle), path = "wl.rs")] mod _version; -pub use _version::*; #[cfg(feature = "low-power")] -use atomic_polyfill::{AtomicU32, Ordering}; +use core::sync::atomic::{AtomicU32, Ordering}; + +pub use _version::*; // Model Clock Configuration // @@ -57,9 +54,9 @@ pub struct Clocks { pub apb2: Hertz, #[cfg(not(any(rcc_c0, rcc_g0)))] pub apb2_tim: Hertz, - #[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_u5))] + #[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab, rcc_u5))] pub apb3: Hertz, - #[cfg(any(rcc_h7, rcc_h7ab))] + #[cfg(any(rcc_h7, rcc_h7rm0433, rcc_h7ab, stm32h5))] pub apb4: Hertz, #[cfg(any(rcc_wba))] pub apb7: Hertz, @@ -67,16 +64,44 @@ pub struct Clocks { // AHB pub ahb1: Hertz, #[cfg(any( - rcc_l4, rcc_l5, rcc_f2, rcc_f4, rcc_f410, rcc_f7, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_g4, rcc_u5, rcc_wb, - rcc_wba, rcc_wl5, rcc_wle + rcc_l4, + rcc_l5, + 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, #[cfg(any( - 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_l4, + 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 ))] pub ahb3: Hertz, - #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_wba))] + #[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab, rcc_wba))] pub ahb4: Hertz, #[cfg(any(rcc_f2, rcc_f4, rcc_f410, rcc_f7))] @@ -88,7 +113,18 @@ pub struct Clocks { #[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))] pub pllsai: Option, - #[cfg(any(rcc_f1, rcc_f100, rcc_f1cl, rcc_h5, rcc_h50, rcc_h7, rcc_h7ab, rcc_f3, rcc_g4))] + #[cfg(any( + rcc_f1, + rcc_f100, + rcc_f1cl, + rcc_h5, + rcc_h50, + rcc_h7, + rcc_h7rm0433, + rcc_h7ab, + rcc_f3, + rcc_g4 + ))] pub adc: Option, #[cfg(any(rcc_f3, rcc_g4))] @@ -97,13 +133,43 @@ pub struct Clocks { #[cfg(stm32f334)] pub hrtim: Option, - #[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, - #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] - /// Set if the hse is configured, indicates stop is not supported - pub rtc_hse: Option, + #[cfg(stm32h5)] + pub hsi: Option, + #[cfg(stm32h5)] + pub hsi48: Option, + #[cfg(stm32h5)] + pub lsi: Option, + #[cfg(stm32h5)] + pub csi: Option, + + #[cfg(stm32h5)] + pub lse: Option, + #[cfg(stm32h5)] + pub hse: Option, + + #[cfg(stm32h5)] + pub pll1_q: Option, + #[cfg(stm32h5)] + pub pll2_q: Option, + #[cfg(stm32h5)] + pub pll2_p: Option, + #[cfg(stm32h5)] + pub pll2_r: Option, + #[cfg(stm32h5)] + pub pll3_p: Option, + #[cfg(stm32h5)] + pub pll3_q: Option, + #[cfg(stm32h5)] + pub pll3_r: Option, + #[cfg(stm32h5)] + pub pll3_1: Option, + + #[cfg(stm32h5)] + pub audioclk: Option, + #[cfg(stm32h5)] + pub per: Option, } #[cfg(feature = "low-power")] @@ -111,20 +177,22 @@ static CLOCK_REFCOUNT: AtomicU32 = AtomicU32::new(0); #[cfg(feature = "low-power")] pub fn low_power_ready() -> bool { - trace!("clock refcount: {}", CLOCK_REFCOUNT.load(Ordering::SeqCst)); - + // trace!("clock refcount: {}", CLOCK_REFCOUNT.load(Ordering::SeqCst)); CLOCK_REFCOUNT.load(Ordering::SeqCst) == 0 } #[cfg(feature = "low-power")] -pub(crate) fn clock_refcount_add() { +pub(crate) fn clock_refcount_add(_cs: critical_section::CriticalSection) { // We don't check for overflow because constructing more than u32 peripherals is unlikely - CLOCK_REFCOUNT.fetch_add(1, Ordering::Relaxed); + let n = CLOCK_REFCOUNT.load(Ordering::Relaxed); + CLOCK_REFCOUNT.store(n + 1, Ordering::Relaxed); } #[cfg(feature = "low-power")] -pub(crate) fn clock_refcount_sub() { - assert!(CLOCK_REFCOUNT.fetch_sub(1, Ordering::Relaxed) != 0); +pub(crate) fn clock_refcount_sub(_cs: critical_section::CriticalSection) { + let n = CLOCK_REFCOUNT.load(Ordering::Relaxed); + assert!(n != 0); + CLOCK_REFCOUNT.store(n - 1, Ordering::Relaxed); } /// Frozen clock frequencies @@ -132,14 +200,6 @@ pub(crate) fn clock_refcount_sub() { /// The existence of this value indicates that the clock configuration can no longer be changed static mut CLOCK_FREQS: MaybeUninit = 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 /// /// Safety: Sets a mutable global. @@ -159,11 +219,19 @@ pub mod low_level { } pub(crate) mod sealed { + use critical_section::CriticalSection; + pub trait RccPeripheral { fn frequency() -> crate::time::Hertz; - fn reset(); - fn enable(); - fn disable(); + fn enable_and_reset_with_cs(cs: CriticalSection); + fn disable_with_cs(cs: CriticalSection); + + fn enable_and_reset() { + critical_section::with(|cs| Self::enable_and_reset_with_cs(cs)) + } + fn disable() { + critical_section::with(|cs| Self::disable_with_cs(cs)) + } } } diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index d9a53128..68a8d3a3 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -1,124 +1,102 @@ -use stm32_metapac::rcc::vals::{Msirange, Msirgsel, Pllm, Pllsrc, Sw}; - -pub use super::bus::{AHBPrescaler, APBPrescaler}; -use crate::pac::{FLASH, RCC}; +pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange, Plldiv, Pllm, Plln, Ppre as APBPrescaler}; +use crate::pac::rcc::vals::{Msirgsel, Pllmboost, Pllrge, Pllsrc, Sw}; +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); - pub use crate::pac::pwr::vals::Vos as VoltageScale; #[derive(Copy, Clone)] pub enum ClockSrc { - MSI(MSIRange), + /// Use an internal medium speed oscillator (MSIS) as the system clock. + 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), + /// Use the 16 MHz internal high speed oscillator as the system clock. HSI16, - PLL1R(PllSrc, PllM, PllN, PllClkDiv), + /// Use PLL1 as the system clock. + PLL1R(PllConfig), } -#[derive(Clone, Copy, Debug)] +impl Default for ClockSrc { + 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 { - MSI(MSIRange), + /// Use an internal medium speed oscillator as the PLL source. + 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), + /// Use the 16 MHz internal high speed oscillator as the PLL source. HSI16, } impl Into for PllSrc { fn into(self) -> Pllsrc { match self { - PllSrc::MSI(..) => Pllsrc::MSIS, + PllSrc::MSIS(..) => Pllsrc::MSIS, PllSrc::HSE(..) => Pllsrc::HSE, 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 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 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 for PllM { - fn into(self) -> Pllm { - Pllm::from_bits(self as u8) - } -} - impl Into for ClockSrc { fn into(self) -> Sw { match self { @@ -130,62 +108,6 @@ impl Into 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 for MSIRange { - fn into(self) -> u32 { - self as u32 - } -} - -impl Into 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 mux: ClockSrc, pub ahb_pre: AHBPrescaler, @@ -193,90 +115,209 @@ pub struct Config { pub apb2_pre: APBPrescaler, pub apb3_pre: APBPrescaler, 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 { fn default() -> Self { Self { - mux: ClockSrc::MSI(MSIRange::default()), + mux: ClockSrc::default(), ahb_pre: AHBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, apb3_pre: APBPrescaler::DIV1, hsi48: false, + voltage_range: VoltageScale::RANGE3, + ls: Default::default(), } } } 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 { - ClockSrc::MSI(range) => { - RCC.icscr1().modify(|w| { - let bits: Msirange = range.into(); - w.set_msisrange(bits); - w.set_msirgsel(Msirgsel::RCC_ICSCR1); - }); - RCC.cr().write(|w| { - w.set_msipllen(false); - 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 - } + ClockSrc::MSI(range) => config.init_msis(range), + ClockSrc::HSE(freq) => config.init_hse(freq), + ClockSrc::HSI16 => config.init_hsi16(), + ClockSrc::PLL1R(pll) => { + // Configure the PLL source + let source_clk = match pll.source { + PllSrc::MSIS(range) => config.init_msis(range), + PllSrc::HSE(hertz) => config.init_hse(hertz), + PllSrc::HSI16 => config.init_hsi16(), }; - // disable + // Calculate the reference clock, which is the source divided by m + 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)); while RCC.cr().read().pllrdy(0) {} - let vco = freq * n as u8 as u32; - let pll_ck = vco / (div as u8 as u32 + 1); - + // Configure the PLL RCC.pll1cfgr().write(|w| { - w.set_pllm(m.into()); - w.set_pllsrc(src.into()); + // Configure PLL1 source and prescaler + w.set_pllsrc(pll.source.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); }); + // Configure the PLL divisors RCC.pll1divr().modify(|w| { - w.set_pllr(div.to_div()); - w.set_plln(n.to_mul()); + // Set the VCO multiplier + w.set_plln(pll.n); + // Set the R output divisor + w.set_pllr(pll.r); }); - // Enable PLL + // Do we need the EPOD booster to reach the target clock speed per § 10.5.4? + 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)); while !RCC.cr().read().pllrdy(0) {} - pll_ck + pll1r_clk } }; @@ -285,20 +326,18 @@ pub(crate) unsafe fn init(config: Config) { while !RCC.cr().read().hsi48rdy() {} } - // TODO make configurable - let power_vos = VoltageScale::RANGE3; - - // states and programming delay - let wait_states = match power_vos { + // The clock source is ready + // Calculate and set the flash wait states + let wait_states = match config.voltage_range { // VOS 1 range VCORE 1.26V - 1.40V VoltageScale::RANGE1 => { - if sys_clk < 32_000_000 { + if sys_clk.0 < 32_000_000 { 0 - } else if sys_clk < 64_000_000 { + } else if sys_clk.0 < 64_000_000 { 1 - } else if sys_clk < 96_000_000 { + } else if sys_clk.0 < 96_000_000 { 2 - } else if sys_clk < 128_000_000 { + } else if sys_clk.0 < 128_000_000 { 3 } else { 4 @@ -306,11 +345,11 @@ pub(crate) unsafe fn init(config: Config) { } // VOS 2 range VCORE 1.15V - 1.26V VoltageScale::RANGE2 => { - if sys_clk < 30_000_000 { + if sys_clk.0 < 30_000_000 { 0 - } else if sys_clk < 60_000_000 { + } else if sys_clk.0 < 60_000_000 { 1 - } else if sys_clk < 90_000_000 { + } else if sys_clk.0 < 90_000_000 { 2 } else { 3 @@ -318,9 +357,9 @@ pub(crate) unsafe fn init(config: Config) { } // VOS 3 range VCORE 1.05V - 1.15V VoltageScale::RANGE3 => { - if sys_clk < 24_000_000 { + if sys_clk.0 < 24_000_000 { 0 - } else if sys_clk < 48_000_000 { + } else if sys_clk.0 < 48_000_000 { 1 } else { 2 @@ -328,80 +367,104 @@ pub(crate) unsafe fn init(config: Config) { } // VOS 4 range VCORE 0.95V - 1.05V VoltageScale::RANGE4 => { - if sys_clk < 12_000_000 { + if sys_clk.0 < 12_000_000 { 0 } else { 1 } } }; - FLASH.acr().modify(|w| { w.set_latency(wait_states); }); + // Switch the system clock source RCC.cfgr1().modify(|w| { 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| { - w.set_hpre(config.ahb_pre.into()); - w.set_ppre1(config.apb1_pre.into()); - w.set_ppre2(config.apb2_pre.into()); + w.set_hpre(config.ahb_pre); + w.set_ppre1(config.apb1_pre); + w.set_ppre2(config.apb2_pre); }); - RCC.cfgr3().modify(|w| { - w.set_ppre3(config.apb3_pre.into()); + w.set_ppre3(config.apb3_pre); }); - 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 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 pre: u8 = pre.into(); - let pre: u8 = 1 << (pre - 3); - let freq = ahb_freq / pre as u32; - (freq, freq * 2) + 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 pre: u8 = pre.into(); - let pre: u8 = 1 << (pre - 3); - let freq = ahb_freq / pre as u32; - (freq, freq * 2) + let freq = ahb_freq / pre; + (freq, freq * 2u32) } }; let (apb3_freq, _apb3_tim_freq) = match config.apb3_pre { APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { - let pre: u8 = pre.into(); - let pre: u8 = 1 << (pre - 3); - let freq = ahb_freq / pre as u32; - (freq, freq * 2) + let freq = ahb_freq / pre; + (freq, freq * 2u32) } }; + let rtc = config.ls.init(); + set_freqs(Clocks { - sys: Hertz(sys_clk), - ahb1: Hertz(ahb_freq), - ahb2: Hertz(ahb_freq), - ahb3: Hertz(ahb_freq), - apb1: Hertz(apb1_freq), - apb2: Hertz(apb2_freq), - apb3: Hertz(apb3_freq), - apb1_tim: Hertz(apb1_tim_freq), - apb2_tim: Hertz(apb2_tim_freq), + sys: sys_clk, + ahb1: ahb_freq, + ahb2: ahb_freq, + ahb3: ahb_freq, + apb1: apb1_freq, + apb2: apb2_freq, + apb3: apb3_freq, + apb1_tim: apb1_tim_freq, + apb2_tim: 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), + } +} diff --git a/embassy-stm32/src/rcc/wb.rs b/embassy-stm32/src/rcc/wb.rs index ee45a342..181e6bb5 100644 --- a/embassy-stm32/src/rcc/wb.rs +++ b/embassy-stm32/src/rcc/wb.rs @@ -1,118 +1,45 @@ -pub use super::bus::{AHBPrescaler, APBPrescaler}; -use crate::rcc::bd::{BackupDomain, RtcClockSource}; -use crate::rcc::Clocks; -use crate::time::{khz, 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. +pub use crate::pac::rcc::vals::{ + Hpre as AHBPrescaler, Hsepre as HsePrescaler, Pllm, Plln, Pllp, Pllq, Pllr, Pllsrc as PllSource, + Ppre as APBPrescaler, Sw as Sysclk, +}; +use crate::rcc::{set_freqs, Clocks}; +use crate::time::{mhz, Hertz}; /// HSI speed 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 for bool { - fn from(value: HsePrescaler) -> Self { - match value { - HsePrescaler::NotDivided => false, - HsePrescaler::Div2 => true, - } - } -} - pub struct Hse { pub prediv: HsePrescaler, 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 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 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 { /// Source clock selection. pub source: PllSource, /// PLL pre-divider (DIVM). Must be between 1 and 63. - pub prediv: u8, + pub prediv: Pllm, } pub struct Pll { /// PLL multiplication factor. Must be between 4 and 512. - pub mul: u16, + pub mul: Plln, /// PLL P division factor. If None, PLL P output is disabled. Must be between 1 and 128. /// On PLL1, it must be even (in particular, it cannot be 1.) - pub divp: Option, + pub divp: Option, /// PLL Q division factor. If None, PLL Q output is disabled. Must be between 1 and 128. - pub divq: Option, + pub divq: Option, /// PLL R division factor. If None, PLL R output is disabled. Must be between 1 and 128. - pub divr: Option, + pub divr: Option, } /// Clocks configutation pub struct Config { pub hse: Option, - pub lse: Option, - pub lsi: bool, pub sys: Sysclk, pub mux: Option, - pub pll48: Option, - pub rtc: Option, pub pll: Option, pub pllsai: Option, @@ -122,28 +49,28 @@ pub struct Config { pub ahb3_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, pub apb2_pre: APBPrescaler, + + pub ls: super::LsConfig, } pub const WPAN_DEFAULT: Config = Config { hse: Some(Hse { frequency: mhz(32), - prediv: HsePrescaler::NotDivided, + prediv: HsePrescaler::DIV1, }), - lse: Some(khz(32)), - sys: Sysclk::Pll, + sys: Sysclk::PLL, mux: Some(PllMux { - source: PllSource::Hse, - prediv: 2, + source: PllSource::HSE, + prediv: Pllm::DIV2, }), - pll48: None, - rtc: Some(RtcClockSource::LSE), - lsi: false, + + ls: super::LsConfig::default_lse(), pll: Some(Pll { - mul: 12, - divp: Some(3), - divq: Some(4), - divr: Some(3), + mul: Plln::MUL12, + divp: Some(Pllp::DIV3), + divq: Some(Pllq::DIV4), + divr: Some(Pllr::DIV3), }), pllsai: None, @@ -159,14 +86,12 @@ impl Default for Config { fn default() -> Config { Config { hse: None, - lse: None, - sys: Sysclk::HSI, + sys: Sysclk::HSI16, mux: None, - pll48: None, pll: None, pllsai: None, - rtc: None, - lsi: false, + + ls: Default::default(), ahb1_pre: AHBPrescaler::DIV1, ahb2_pre: AHBPrescaler::DIV1, @@ -177,16 +102,15 @@ impl Default for Config { } } -pub(crate) fn compute_clocks(config: &Config) -> Clocks { - let hse_clk = config.hse.as_ref().map(|hse| match hse.prediv { - HsePrescaler::NotDivided => hse.frequency, - HsePrescaler::Div2 => hse.frequency / 2u32, - }); +#[cfg(stm32wb)] +/// RCC initialization function +pub(crate) unsafe fn init(config: Config) { + let hse_clk = config.hse.as_ref().map(|hse| hse.frequency / hse.prediv); let mux_clk = config.mux.as_ref().map(|pll_mux| { (match pll_mux.source { - PllSource::Hse => hse_clk.unwrap(), - PllSource::Hsi => HSI_FREQ, + PllSource::HSE => hse_clk.unwrap(), + PllSource::HSI16 => HSI_FREQ, _ => unreachable!(), } / pll_mux.prediv) }); @@ -206,44 +130,19 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks { let sys_clk = match config.sys { Sysclk::HSE => hse_clk.unwrap(), - Sysclk::HSI => HSI_FREQ, - Sysclk::Pll => pll_r.unwrap(), + Sysclk::HSI16 => HSI_FREQ, + Sysclk::PLL => pll_r.unwrap(), _ => unreachable!(), }; - let ahb1_clk = match config.ahb1_pre { - AHBPrescaler::DIV1 => sys_clk, - 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 ahb1_clk = sys_clk / config.ahb1_pre; + let ahb2_clk = sys_clk / config.ahb2_pre; + let ahb3_clk = sys_clk / config.ahb3_pre; let (apb1_clk, apb1_tim_clk) = match config.apb1_pre { APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk), pre => { - let pre: u8 = pre.into(); - let pre: u8 = 1 << (pre - 3); - let freq = ahb1_clk / pre as u32; + let freq = ahb1_clk / pre; (freq, freq * 2u32) } }; @@ -251,43 +150,20 @@ pub(crate) fn compute_clocks(config: &Config) -> Clocks { let (apb2_clk, apb2_tim_clk) = match config.apb2_pre { APBPrescaler::DIV1 => (ahb1_clk, ahb1_clk), pre => { - let pre: u8 = pre.into(); - let pre: u8 = 1 << (pre - 3); - let freq = ahb1_clk / pre as u32; + let freq = ahb1_clk / pre; (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 needs_hsi = if let Some(pll_mux) = &config.mux { - pll_mux.source == PllSource::Hsi + pll_mux.source == PllSource::HSI16 } else { false }; - if needs_hsi || config.sys == Sysclk::HSI { + if needs_hsi || config.sys == Sysclk::HSI16 { rcc.cr().modify(|w| { w.set_hsion(true); }); @@ -297,16 +173,12 @@ pub(crate) fn configure_clocks(config: &Config) { rcc.cfgr().modify(|w| w.set_stopwuck(true)); - BackupDomain::configure_ls( - config.rtc.unwrap_or(RtcClockSource::NOCLOCK), - config.lsi, - config.lse.map(|_| Default::default()), - ); + let rtc = config.ls.init(); match &config.hse { Some(hse) => { rcc.cr().modify(|w| { - w.set_hsepre(hse.prediv.into()); + w.set_hsepre(hse.prediv); w.set_hseon(true); }); @@ -328,18 +200,18 @@ pub(crate) fn configure_clocks(config: &Config) { match &config.pll { Some(pll) => { rcc.pllcfgr().modify(|w| { - w.set_plln(pll.mul as u8); + w.set_plln(pll.mul); pll.divp.map(|divp| { w.set_pllpen(true); - w.set_pllp((divp - 1) as u8) + w.set_pllp(divp) }); pll.divq.map(|divq| { w.set_pllqen(true); - w.set_pllq((divq - 1) as u8) + w.set_pllq(divq) }); pll.divr.map(|divr| { - // w.set_pllren(true); - w.set_pllr((divr - 1) as u8); + w.set_pllren(true); + w.set_pllr(divr); }); }); @@ -352,13 +224,25 @@ pub(crate) fn configure_clocks(config: &Config) { rcc.cfgr().modify(|w| { w.set_sw(config.sys.into()); - w.set_hpre(config.ahb1_pre.into()); - w.set_ppre1(config.apb1_pre.into()); - w.set_ppre2(config.apb2_pre.into()); + w.set_hpre(config.ahb1_pre); + w.set_ppre1(config.apb1_pre); + w.set_ppre2(config.apb2_pre); }); rcc.extcfgr().modify(|w| { - w.set_c2hpre(config.ahb2_pre.into()); - w.set_shdhpre(config.ahb3_pre.into()); + w.set_c2hpre(config.ahb2_pre); + w.set_shdhpre(config.ahb3_pre); }); + + 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, + }) } diff --git a/embassy-stm32/src/rcc/wba.rs b/embassy-stm32/src/rcc/wba.rs index c5d7ab62..ff5669ec 100644 --- a/embassy-stm32/src/rcc/wba.rs +++ b/embassy-stm32/src/rcc/wba.rs @@ -7,9 +7,6 @@ use crate::time::Hertz; /// HSI speed pub const HSI_FREQ: Hertz = Hertz(16_000_000); -/// LSI speed -pub const LSI_FREQ: Hertz = Hertz(32_000); - pub use crate::pac::pwr::vals::Vos as VoltageScale; pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler}; @@ -28,7 +25,7 @@ pub enum PllSrc { impl Into for PllSrc { fn into(self) -> Pllsrc { match self { - PllSrc::HSE(..) => Pllsrc::HSE32, + PllSrc::HSE(..) => Pllsrc::HSE, PllSrc::HSI16 => Pllsrc::HSI16, } } @@ -37,19 +34,19 @@ impl Into for PllSrc { impl Into for ClockSrc { fn into(self) -> Sw { match self { - ClockSrc::HSE(..) => Sw::HSE32, + ClockSrc::HSE(..) => Sw::HSE, ClockSrc::HSI16 => Sw::HSI16, } } } -#[derive(Copy, Clone)] pub struct Config { pub mux: ClockSrc, pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, pub apb2_pre: APBPrescaler, pub apb7_pre: APBPrescaler, + pub ls: super::LsConfig, } impl Default for Config { @@ -60,6 +57,7 @@ impl Default for Config { apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, apb7_pre: APBPrescaler::DIV1, + ls: Default::default(), } } } @@ -108,13 +106,13 @@ pub(crate) unsafe fn init(config: Config) { }); RCC.cfgr2().modify(|w| { - w.set_hpre(config.ahb_pre.into()); - w.set_ppre1(config.apb1_pre.into()); - w.set_ppre2(config.apb2_pre.into()); + w.set_hpre(config.ahb_pre); + w.set_ppre1(config.apb1_pre); + w.set_ppre2(config.apb2_pre); }); RCC.cfgr3().modify(|w| { - w.set_ppre7(config.apb7_pre.into()); + w.set_ppre7(config.apb7_pre); }); let ahb_freq = sys_clk / config.ahb_pre; @@ -140,6 +138,8 @@ pub(crate) unsafe fn init(config: Config) { } }; + let rtc = config.ls.init(); + set_freqs(Clocks { sys: sys_clk, ahb1: ahb_freq, @@ -150,5 +150,6 @@ pub(crate) unsafe fn init(config: Config) { apb7: apb7_freq, apb1_tim: apb1_tim_freq, apb2_tim: apb2_tim_freq, + rtc, }); } diff --git a/embassy-stm32/src/rcc/wl.rs b/embassy-stm32/src/rcc/wl.rs index 6643d278..366ca136 100644 --- a/embassy-stm32/src/rcc/wl.rs +++ b/embassy-stm32/src/rcc/wl.rs @@ -1,136 +1,27 @@ -pub use super::bus::{AHBPrescaler, APBPrescaler}; pub use crate::pac::pwr::vals::Vos as VoltageScale; -use crate::pac::rcc::vals::Adcsel; +use crate::pac::rcc::vals::Sw; +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::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::{set_freqs, Clocks}; 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 pub const HSI_FREQ: Hertz = Hertz(16_000_000); -/// LSI speed -pub const LSI_FREQ: Hertz = Hertz(32_000); - -/// HSE32 speed -pub const HSE32_FREQ: Hertz = Hertz(32_000_000); +/// HSE speed +pub const HSE_FREQ: Hertz = Hertz(32_000_000); /// System clock mux source #[derive(Clone, Copy)] pub enum ClockSrc { MSI(MSIRange), - HSE32, + HSE, 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 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 pub struct Config { pub mux: ClockSrc, @@ -138,91 +29,60 @@ pub struct Config { pub shd_ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, pub apb2_pre: APBPrescaler, - pub rtc_mux: RtcClockSource, - pub lse: Option, - pub lsi: bool, pub adc_clock_source: AdcClockSource, + pub ls: super::LsConfig, } impl Default for Config { #[inline] fn default() -> Config { Config { - mux: ClockSrc::MSI(MSIRange::default()), + mux: ClockSrc::MSI(MSIRange::RANGE4M), ahb_pre: AHBPrescaler::DIV1, shd_ahb_pre: AHBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1, - rtc_mux: RtcClockSource::LSI, - lsi: true, - lse: None, - adc_clock_source: AdcClockSource::default(), + adc_clock_source: AdcClockSource::HSI16, + ls: Default::default(), } } } -#[repr(u8)] -pub enum Lsedrv { - Low = 0, - MediumLow = 1, - MediumHigh = 2, - High = 3, -} - pub(crate) unsafe fn init(config: Config) { let (sys_clk, sw, vos) = match config.mux { - ClockSrc::HSI16 => (HSI_FREQ.0, 0x01, VoltageScale::RANGE2), - ClockSrc::HSE32 => (HSE32_FREQ.0, 0x02, VoltageScale::RANGE1), - ClockSrc::MSI(range) => (range.freq(), 0x00, range.vos()), + ClockSrc::HSI16 => (HSI_FREQ, Sw::HSI16, VoltageScale::RANGE2), + ClockSrc::HSE => (HSE_FREQ, Sw::HSE, VoltageScale::RANGE1), + ClockSrc::MSI(range) => (msirange_to_hertz(range), Sw::MSI, msirange_to_vos(range)), }; - 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 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 ahb_freq = sys_clk / config.ahb_pre; + let shd_ahb_freq = sys_clk / config.shd_ahb_pre; let (apb1_freq, apb1_tim_freq) = match config.apb1_pre { APBPrescaler::DIV1 => (ahb_freq, ahb_freq), pre => { - let pre: u8 = pre.into(); - let pre: u8 = 1 << (pre - 3); - let freq = ahb_freq / pre as u32; - (freq, freq * 2) + 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 pre: u8 = pre.into(); - let pre: u8 = 1 << (pre - 3); - let freq = ahb_freq / pre as u32; - (freq, freq * 2) + let freq = ahb_freq / pre; + (freq, freq * 2u32) } }; // Adjust flash latency - let flash_clk_src_freq: u32 = shd_ahb_freq; + let flash_clk_src_freq = shd_ahb_freq; let ws = match vos { - VoltageScale::RANGE1 => match flash_clk_src_freq { + VoltageScale::RANGE1 => match flash_clk_src_freq.0 { 0..=18_000_000 => 0b000, 18_000_001..=36_000_000 => 0b001, _ => 0b010, }, - VoltageScale::RANGE2 => match flash_clk_src_freq { + VoltageScale::RANGE2 => match flash_clk_src_freq.0 { 0..=6_000_000 => 0b000, 6_000_001..=12_000_000 => 0b001, _ => 0b010, @@ -236,17 +96,14 @@ pub(crate) unsafe fn init(config: Config) { 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 { ClockSrc::HSI16 => { // Enable HSI16 RCC.cr().write(|w| w.set_hsion(true)); while !RCC.cr().read().hsirdy() {} } - ClockSrc::HSE32 => { - // Enable HSE32 + ClockSrc::HSE => { + // Enable HSE RCC.cr().write(|w| { w.set_hsebyppwr(true); w.set_hseon(true); @@ -258,49 +115,70 @@ pub(crate) unsafe fn init(config: Config) { assert!(!cr.msion() || cr.msirdy()); RCC.cr().write(|w| { w.set_msirgsel(true); - w.set_msirange(range.into()); + w.set_msirange(range); w.set_msion(true); - if let RtcClockSource::LSE = config.rtc_mux { - // If LSE is enabled, enable calibration of MSI - w.set_msipllen(true); - } else { - w.set_msipllen(false); - } + // If LSE is enabled, enable calibration of MSI + w.set_msipllen(config.ls.lse.is_some()); }); while !RCC.cr().read().msirdy() {} } } RCC.extcfgr().modify(|w| { - if config.shd_ahb_pre == AHBPrescaler::DIV1 { - w.set_shdhpre(0); - } else { - w.set_shdhpre(config.shd_ahb_pre.into()); - } + w.set_shdhpre(config.shd_ahb_pre); }); RCC.cfgr().modify(|w| { w.set_sw(sw.into()); w.set_hpre(config.ahb_pre); - w.set_ppre1(config.apb1_pre.into()); - w.set_ppre2(config.apb2_pre.into()); + w.set_ppre1(config.apb1_pre); + w.set_ppre2(config.apb2_pre); }); // ADC clock MUX - RCC.ccipr().modify(|w| w.set_adcsel(config.adc_clock_source.adcsel())); + RCC.ccipr().modify(|w| w.set_adcsel(config.adc_clock_source)); // TODO: switch voltage range + let rtc = config.ls.init(); + set_freqs(Clocks { - sys: Hertz(sys_clk), - ahb1: Hertz(ahb_freq), - ahb2: Hertz(ahb_freq), - ahb3: Hertz(shd_ahb_freq), - apb1: Hertz(apb1_freq), - apb2: Hertz(apb2_freq), - apb3: Hertz(shd_ahb_freq), - apb1_tim: Hertz(apb1_tim_freq), - apb2_tim: Hertz(apb2_tim_freq), + sys: sys_clk, + ahb1: ahb_freq, + ahb2: ahb_freq, + ahb3: shd_ahb_freq, + apb1: apb1_freq, + apb2: apb2_freq, + apb3: shd_ahb_freq, + apb1_tim: apb1_tim_freq, + apb2_tim: 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 + } +} diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs index 0979dce8..fc003ebe 100644 --- a/embassy-stm32/src/rng.rs +++ b/embassy-stm32/src/rng.rs @@ -13,6 +13,7 @@ use crate::{interrupt, pac, peripherals, Peripheral}; static RNG_WAKER: AtomicWaker = AtomicWaker::new(); +#[derive(Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { SeedError, @@ -42,8 +43,7 @@ impl<'d, T: Instance> Rng<'d, T> { inner: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, ) -> Self { - T::enable(); - T::reset(); + T::enable_and_reset(); into_ref!(inner); let mut random = Self { _inner: inner }; random.reset(); @@ -164,7 +164,7 @@ impl<'d, T: Instance> Rng<'d, T> { return Err(Error::SeedError); } // write bytes to chunk - for (dest, src) in chunk.iter_mut().zip(random_word.to_be_bytes().iter()) { + for (dest, src) in chunk.iter_mut().zip(random_word.to_ne_bytes().iter()) { *dest = *src } } @@ -195,7 +195,7 @@ impl<'d, T: Instance> RngCore for Rng<'d, T> { fn fill_bytes(&mut self, dest: &mut [u8]) { for chunk in dest.chunks_mut(4) { let rand = self.next_u32(); - for (slot, num) in chunk.iter_mut().zip(rand.to_be_bytes().iter()) { + for (slot, num) in chunk.iter_mut().zip(rand.to_ne_bytes().iter()) { *slot = *num } } diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs index 73b78f25..552dcc76 100644 --- a/embassy-stm32/src/rtc/mod.rs +++ b/embassy-stm32/src/rtc/mod.rs @@ -10,7 +10,6 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; -pub use crate::rcc::RtcClockSource; use crate::time::Hertz; /// refer to AN4759 to compare features of RTC2 and RTC3 @@ -93,21 +92,50 @@ impl RtcTimeProvider { /// /// Will return an `RtcError::InvalidDateTime` if the stored value in the system is not a valid [`DayOfWeek`]. pub fn now(&self) -> Result { - 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(); + // For RM0433 we use BYPSHAD=1 to work around errata ES0392 2.19.1 + #[cfg(rcc_h7rm0433)] + loop { + let r = RTC::regs(); + let ss = r.ssr().read().ss(); + let dr = r.dr().read(); + let tr = r.tr().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; + // If an RTCCLK edge occurs during read we may see inconsistent values + // so read ssr again and see if it has changed. (see RM0433 Rev 7 46.3.9) + let ss_after = r.ssr().read().ss(); + if ss == ss_after { + 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())); - self::datetime::datetime(year, month, day, weekday, hour, minute, second).map_err(RtcError::InvalidDateTime) + 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; + + 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) + } } } @@ -155,8 +183,8 @@ impl Default for RtcCalibrationCyclePeriod { impl Rtc { pub fn new(_rtc: impl Peripheral

, rtc_config: RtcConfig) -> Self { - #[cfg(any(rcc_wle, rcc_wl5, rcc_g4, rcc_g0, rtc_v2l4, rtc_v2wb))] - ::enable(); + #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] + ::enable_and_reset(); let mut this = Self { #[cfg(feature = "low-power")] @@ -175,19 +203,8 @@ impl Rtc { } fn frequency() -> Hertz { - #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] let freqs = unsafe { crate::rcc::get_freqs() }; - - // Load the clock frequency from the rcc mod, if supported - #[cfg(any(rcc_wb, rcc_f4, rcc_f410))] - match freqs.rtc { - Some(hertz) => hertz, - None => freqs.rtc_hse.unwrap(), - } - - // Assume the default value, if not supported - #[cfg(not(any(rcc_wb, rcc_f4, rcc_f410)))] - Hertz(32_768) + freqs.rtc.unwrap() } /// Acquire a [`RtcTimeProvider`] instance. diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index 4608d311..eeb23e1f 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -112,25 +112,26 @@ impl super::Rtc { pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option { use crate::interrupt::typelevel::Interrupt; - trace!("rtc: stop wakeup alarm at {}", self.instant()); + if RTC::regs().cr().read().wute() { + trace!("rtc: stop wakeup alarm at {}", self.instant()); - self.write(false, |regs| { - regs.cr().modify(|w| w.set_wutie(false)); - regs.cr().modify(|w| w.set_wute(false)); - regs.isr().modify(|w| w.set_wutf(false)); + self.write(false, |regs| { + regs.cr().modify(|w| w.set_wutie(false)); + regs.cr().modify(|w| w.set_wute(false)); + regs.isr().modify(|w| w.set_wutf(false)); - crate::pac::EXTI - .pr(0) - .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); + crate::pac::EXTI + .pr(0) + .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true)); - ::WakeupInterrupt::unpend(); - }); - - if let Some(stop_time) = self.stop_time.borrow(cs).take() { - Some(self.instant() - stop_time) - } else { - None + ::WakeupInterrupt::unpend(); + }); } + + self.stop_time + .borrow(cs) + .take() + .map(|stop_time| self.instant() - stop_time) } #[cfg(feature = "low-power")] @@ -156,6 +157,8 @@ impl super::Rtc { w.set_fmt(stm32_metapac::rtc::vals::Fmt::TWENTY_FOUR_HOUR); w.set_osel(Osel::DISABLED); w.set_pol(Pol::HIGH); + #[cfg(rcc_h7rm0433)] + w.set_bypshad(true); }); rtc.prer().modify(|w| { diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs index 5eecb637..a0b4ddac 100644 --- a/embassy-stm32/src/sai/mod.rs +++ b/embassy-stm32/src/sai/mod.rs @@ -11,7 +11,7 @@ use crate::pac::sai::{vals, Sai as Regs}; use crate::rcc::RccPeripheral; use crate::{peripherals, Peripheral}; -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { NotATransmitter, @@ -531,10 +531,13 @@ pub struct SubBlock<'d, T: Instance, C: Channel, W: word::Word> { pub struct SubBlockA {} pub struct SubBlockB {} +pub struct SubBlockAPeripheral<'d, T>(PeripheralRef<'d, T>); +pub struct SubBlockBPeripheral<'d, T>(PeripheralRef<'d, T>); + pub struct Sai<'d, T: Instance> { _peri: PeripheralRef<'d, T>, - sub_block_a_peri: Option>, - sub_block_b_peri: Option>, + sub_block_a_peri: Option>, + sub_block_b_peri: Option>, } // return the type for (sd, sck) @@ -577,17 +580,16 @@ fn get_ring_buffer<'d, T: Instance, C: Channel, W: word::Word>( impl<'d, T: Instance> Sai<'d, T> { pub fn new(peri: impl Peripheral

+ 'd) -> Self { - T::enable(); - T::reset(); + T::enable_and_reset(); Self { _peri: unsafe { peri.clone_unchecked().into_ref() }, - sub_block_a_peri: Some(unsafe { peri.clone_unchecked().into_ref() }), - sub_block_b_peri: Some(peri.into_ref()), + sub_block_a_peri: Some(SubBlockAPeripheral(unsafe { peri.clone_unchecked().into_ref() })), + sub_block_b_peri: Some(SubBlockBPeripheral(peri.into_ref())), } } - pub fn take_sub_block_a(self: &mut Self) -> Option> { + pub fn take_sub_block_a(self: &mut Self) -> Option> { if self.sub_block_a_peri.is_some() { self.sub_block_a_peri.take() } else { @@ -595,7 +597,7 @@ impl<'d, T: Instance> Sai<'d, T> { } } - pub fn take_sub_block_b(self: &mut Self) -> Option> { + pub fn take_sub_block_b(self: &mut Self) -> Option> { if self.sub_block_b_peri.is_some() { self.sub_block_b_peri.take() } else { @@ -623,7 +625,7 @@ fn update_synchronous_config(config: &mut Config) { impl SubBlockA { pub fn new_asynchronous_with_mclk<'d, T: Instance, C: Channel, W: word::Word>( - peri: impl Peripheral

+ 'd, + peri: SubBlockAPeripheral<'d, T>, sck: impl Peripheral

> + 'd, sd: impl Peripheral

> + 'd, fs: impl Peripheral

> + 'd, @@ -631,7 +633,7 @@ impl SubBlockA { dma: impl Peripheral

+ 'd, dma_buf: &'d mut [W], mut config: Config, - ) -> SubBlock + ) -> SubBlock<'d, T, C, W> where C: Channel + DmaA, { @@ -650,17 +652,18 @@ impl SubBlockA { } pub fn new_asynchronous<'d, T: Instance, C: Channel, W: word::Word>( - peri: impl Peripheral

+ 'd, + peri: SubBlockAPeripheral<'d, T>, sck: impl Peripheral

> + 'd, sd: impl Peripheral

> + 'd, fs: impl Peripheral

> + 'd, dma: impl Peripheral

+ 'd, dma_buf: &'d mut [W], config: Config, - ) -> SubBlock + ) -> SubBlock<'d, T, C, W> where C: Channel + DmaA, { + let peri = peri.0; into_ref!(peri, dma, sck, sd, fs); let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); @@ -688,17 +691,18 @@ impl SubBlockA { } pub fn new_synchronous<'d, T: Instance, C: Channel, W: word::Word>( - peri: impl Peripheral

+ 'd, + peri: SubBlockAPeripheral<'d, T>, sd: impl Peripheral

> + 'd, dma: impl Peripheral

+ 'd, dma_buf: &'d mut [W], mut config: Config, - ) -> SubBlock + ) -> SubBlock<'d, T, C, W> where C: Channel + DmaA, { update_synchronous_config(&mut config); + let peri = peri.0; into_ref!(dma, peri, sd); let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx); @@ -724,7 +728,7 @@ impl SubBlockA { impl SubBlockB { pub fn new_asynchronous_with_mclk<'d, T: Instance, C: Channel, W: word::Word>( - peri: impl Peripheral

+ 'd, + peri: SubBlockBPeripheral<'d, T>, sck: impl Peripheral

> + 'd, sd: impl Peripheral

> + 'd, fs: impl Peripheral

> + 'd, @@ -732,7 +736,7 @@ impl SubBlockB { dma: impl Peripheral

+ 'd, dma_buf: &'d mut [W], mut config: Config, - ) -> SubBlock + ) -> SubBlock<'d, T, C, W> where C: Channel + DmaB, { @@ -751,17 +755,18 @@ impl SubBlockB { } pub fn new_asynchronous<'d, T: Instance, C: Channel, W: word::Word>( - peri: impl Peripheral

+ 'd, + peri: SubBlockBPeripheral<'d, T>, sck: impl Peripheral

> + 'd, sd: impl Peripheral

> + 'd, fs: impl Peripheral

> + 'd, dma: impl Peripheral

+ 'd, dma_buf: &'d mut [W], config: Config, - ) -> SubBlock + ) -> SubBlock<'d, T, C, W> where C: Channel + DmaB, { + let peri = peri.0; into_ref!(dma, peri, sck, sd, fs); let (sd_af_type, ck_af_type) = get_af_types(config.mode, config.tx_rx); @@ -790,17 +795,17 @@ impl SubBlockB { } pub fn new_synchronous<'d, T: Instance, C: Channel, W: word::Word>( - peri: impl Peripheral

+ 'd, + peri: SubBlockBPeripheral<'d, T>, sd: impl Peripheral

> + 'd, dma: impl Peripheral

+ 'd, dma_buf: &'d mut [W], mut config: Config, - ) -> SubBlock + ) -> SubBlock<'d, T, C, W> where C: Channel + DmaB, { update_synchronous_config(&mut config); - + let peri = peri.0; into_ref!(dma, peri, sd); let (sd_af_type, _ck_af_type) = get_af_types(config.mode, config.tx_rx); @@ -853,10 +858,6 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> { ring_buffer: RingBuffer<'d, C, W>, config: Config, ) -> Self { - T::enable(); - - // can't reset here because the other sub-block might be in use - #[cfg(any(sai_v1, sai_v2, sai_v3, sai_v4))] { let ch = T::REGS.ch(sub_block as usize); @@ -959,8 +960,7 @@ impl<'d, T: Instance, C: Channel, W: word::Word> SubBlock<'d, T, C, W> { } pub fn reset() { - T::enable(); - T::reset(); + T::enable_and_reset(); } pub fn flush(&mut self) { diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 9fb380fd..bc29fe54 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -452,8 +452,7 @@ impl<'d, T: Instance, Dma: SdmmcDma + 'd> Sdmmc<'d, T, Dma> { ) -> Self { into_ref!(sdmmc, dma); - T::enable(); - T::reset(); + T::enable_and_reset(); T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 14333ba2..c391e0a5 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -15,7 +15,7 @@ use crate::rcc::RccPeripheral; use crate::time::Hertz; use crate::{peripherals, Peripheral}; -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { Framing, @@ -230,8 +230,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { let lsbfirst = config.raw_byte_order(); - T::enable(); - T::reset(); + T::enable_and_reset(); #[cfg(any(spi_v1, spi_f1))] { @@ -323,7 +322,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { } /// Reconfigures it with the supplied config. - fn set_config(&mut self, config: Config) { + pub fn set_config(&mut self, config: &Config) -> Result<(), ()> { let cpha = config.raw_phase(); let cpol = config.raw_polarity(); @@ -352,6 +351,7 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { w.set_mbr(br); }); } + Ok(()) } pub fn get_current_config(&self) -> Config { @@ -1063,8 +1063,6 @@ impl<'d, T: Instance, Tx, Rx> SetConfig for Spi<'d, T, Tx, Rx> { type Config = Config; type ConfigError = (); fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { - self.set_config(*config); - - Ok(()) + self.set_config(config) } } diff --git a/embassy-stm32/src/time.rs b/embassy-stm32/src/time.rs index 604503e6..a0bc3394 100644 --- a/embassy-stm32/src/time.rs +++ b/embassy-stm32/src/time.rs @@ -77,3 +77,10 @@ impl Div for Hertz { self / (rhs as u32) } } + +impl Div for Hertz { + type Output = u32; + fn div(self, rhs: Hertz) -> Self::Output { + self.0 / rhs.0 + } +} diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs index 5b01937f..add8be83 100644 --- a/embassy-stm32/src/time_driver.rs +++ b/embassy-stm32/src/time_driver.rs @@ -1,9 +1,8 @@ use core::cell::Cell; use core::convert::TryInto; -use core::sync::atomic::{compiler_fence, Ordering}; +use core::sync::atomic::{compiler_fence, AtomicU32, AtomicU8, Ordering}; use core::{mem, ptr}; -use atomic_polyfill::{AtomicU32, AtomicU8}; use critical_section::CriticalSection; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::blocking_mutex::Mutex; @@ -153,46 +152,43 @@ embassy_time::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver { }); impl RtcDriver { - fn init(&'static self) { + fn init(&'static self, cs: critical_section::CriticalSection) { let r = T::regs_gp16(); - ::enable(); - ::reset(); + ::enable_and_reset_with_cs(cs); let timer_freq = T::frequency(); - critical_section::with(|_| { - r.cr1().modify(|w| w.set_cen(false)); - r.cnt().write(|w| w.set_cnt(0)); + r.cr1().modify(|w| w.set_cen(false)); + r.cnt().write(|w| w.set_cnt(0)); - let psc = timer_freq.0 / TICK_HZ as u32 - 1; - let psc: u16 = match psc.try_into() { - Err(_) => panic!("psc division overflow: {}", psc), - Ok(n) => n, - }; + let psc = timer_freq.0 / TICK_HZ as u32 - 1; + let psc: u16 = match psc.try_into() { + Err(_) => panic!("psc division overflow: {}", psc), + Ok(n) => n, + }; - r.psc().write(|w| w.set_psc(psc)); - r.arr().write(|w| w.set_arr(u16::MAX)); + r.psc().write(|w| w.set_psc(psc)); + r.arr().write(|w| w.set_arr(u16::MAX)); - // Set URS, generate update and clear URS - r.cr1().modify(|w| w.set_urs(vals::Urs::COUNTERONLY)); - r.egr().write(|w| w.set_ug(true)); - r.cr1().modify(|w| w.set_urs(vals::Urs::ANYEVENT)); + // Set URS, generate update and clear URS + r.cr1().modify(|w| w.set_urs(vals::Urs::COUNTERONLY)); + r.egr().write(|w| w.set_ug(true)); + r.cr1().modify(|w| w.set_urs(vals::Urs::ANYEVENT)); - // Mid-way point - r.ccr(0).write(|w| w.set_ccr(0x8000)); + // Mid-way point + r.ccr(0).write(|w| w.set_ccr(0x8000)); - // Enable overflow and half-overflow interrupts - r.dier().write(|w| { - w.set_uie(true); - w.set_ccie(0, true); - }); + // Enable overflow and half-overflow interrupts + r.dier().write(|w| { + w.set_uie(true); + w.set_ccie(0, true); + }); - ::Interrupt::unpend(); - unsafe { ::Interrupt::enable() }; + ::Interrupt::unpend(); + unsafe { ::Interrupt::enable() }; - r.cr1().modify(|w| w.set_cen(true)); - }) + r.cr1().modify(|w| w.set_cen(true)); } fn on_interrupt(&self) { @@ -229,7 +225,9 @@ impl RtcDriver { fn next_period(&self) { let r = T::regs_gp16(); - let period = self.period.fetch_add(1, Ordering::Relaxed) + 1; + // We only modify the period from the timer interrupt, so we know this can't race. + let period = self.period.load(Ordering::Relaxed) + 1; + self.period.store(period, Ordering::Relaxed); let t = (period as u64) << 15; critical_section::with(move |cs| { @@ -340,7 +338,11 @@ impl RtcDriver { #[cfg(feature = "low-power")] /// Set the rtc but panic if it's already been set pub(crate) fn set_rtc(&self, rtc: &'static Rtc) { - critical_section::with(|cs| assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none())); + critical_section::with(|cs| { + rtc.stop_wakeup_alarm(cs); + + assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none()) + }); } #[cfg(feature = "low-power")] @@ -399,18 +401,15 @@ impl Driver for RtcDriver { } unsafe fn allocate_alarm(&self) -> Option { - let id = self.alarm_count.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| { - if x < ALARM_COUNT as u8 { - Some(x + 1) + critical_section::with(|_| { + let id = self.alarm_count.load(Ordering::Relaxed); + if id < ALARM_COUNT as u8 { + self.alarm_count.store(id + 1, Ordering::Relaxed); + Some(AlarmHandle::new(id)) } else { None } - }); - - match id { - Ok(id) => Some(AlarmHandle::new(id)), - Err(_) => None, - } + }) } fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { @@ -461,6 +460,6 @@ pub(crate) fn get_driver() -> &'static RtcDriver { &DRIVER } -pub(crate) fn init() { - DRIVER.init() +pub(crate) fn init(cs: CriticalSection) { + DRIVER.init(cs) } diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 4f033e3a..e1baf6b2 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -64,15 +64,14 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { fn new_inner(tim: impl Peripheral

+ 'd, freq: Hertz) -> Self { into_ref!(tim); - T::enable(); - ::reset(); + T::enable_and_reset(); let mut this = Self { inner: tim }; this.inner.set_frequency(freq); this.inner.start(); - this.inner.enable_outputs(true); + this.inner.enable_outputs(); this.inner .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1); @@ -122,6 +121,46 @@ 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

(&mut self, period: P) + where + P: Into, + { + self.inner.set_frequency(period.into()); + } +} + fn compute_dead_time_value(value: u16) -> (Ckd, u8) { /* Dead-time = T_clk * T_dts * T_dtg diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index d88fbcfd..4b88834c 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -70,6 +70,16 @@ pub(crate) mod sealed { fn set_autoreload_preload(&mut self, enable: vals::Arpe) { 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 { @@ -103,6 +113,16 @@ pub(crate) mod sealed { regs.egr().write(|r| r.set_ug(true)); 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 { @@ -153,7 +173,7 @@ pub(crate) mod sealed { } }); } - fn enable_outputs(&mut self, _enable: bool) {} + fn enable_outputs(&mut self); fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { let r = Self::regs_gp16(); @@ -183,6 +203,10 @@ pub(crate) mod sealed { fn get_max_compare_value(&self) -> u16 { 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 { @@ -219,6 +243,10 @@ pub(crate) mod sealed { fn get_max_compare_value(&self) -> u32 { Self::regs_gp32().arr().read().arr() } + + fn get_compare_value(&self, channel: Channel) -> u32 { + Self::regs_gp32().ccr(channel.raw()).read().ccr() + } } } @@ -373,7 +401,9 @@ macro_rules! impl_32bit_timer { #[allow(unused)] macro_rules! impl_compare_capable_16bit { ($inst:ident) => { - impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { + fn enable_outputs(&mut self) {} + } }; } @@ -422,7 +452,13 @@ foreach_interrupt! { impl CaptureCompare16bitInstance for crate::peripherals::$inst {} impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} impl AdvancedControlInstance for crate::peripherals::$inst {} - impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { + fn enable_outputs(&mut self) { + use crate::timer::sealed::AdvancedControlInstance; + let r = Self::regs_advanced(); + r.bdtr().modify(|w| w.set_moe(true)); + } + } impl sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { fn regs_gp16() -> crate::pac::timer::TimGp16 { diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index 15f2c3a7..01d028bf 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs @@ -55,8 +55,7 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { fn new_inner(tim: impl Peripheral

+ 'd) -> Self { into_ref!(tim); - T::enable(); - ::reset(); + T::enable_and_reset(); // Configure TxC1 and TxC2 as captures T::regs_gp16().ccmr_input(0).modify(|w| { diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 9e28878b..01773ff3 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -63,15 +63,14 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { fn new_inner(tim: impl Peripheral

+ 'd, freq: Hertz) -> Self { into_ref!(tim); - T::enable(); - ::reset(); + T::enable_and_reset(); let mut this = Self { inner: tim }; this.inner.set_frequency(freq); this.inner.start(); - this.inner.enable_outputs(true); + this.inner.enable_outputs(); this.inner .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1); @@ -109,3 +108,41 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { 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

(&mut self, period: P) + where + P: Into, + { + self.inner.set_frequency(period.into()); + } +} diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs index 445ca0ed..cbc13a34 100644 --- a/embassy-stm32/src/usart/buffered.rs +++ b/embassy-stm32/src/usart/buffered.rs @@ -152,9 +152,8 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { config: Config, ) -> Result { // UartRx and UartTx have one refcount ea. - T::enable(); - T::enable(); - T::reset(); + T::enable_and_reset(); + T::enable_and_reset(); Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) } @@ -173,9 +172,8 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { into_ref!(cts, rts); // UartRx and UartTx have one refcount ea. - T::enable(); - T::enable(); - T::reset(); + T::enable_and_reset(); + T::enable_and_reset(); rts.set_as_af(rts.af_num(), AFType::OutputPushPull); cts.set_as_af(cts.af_num(), AFType::Input); @@ -201,9 +199,8 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { into_ref!(de); // UartRx and UartTx have one refcount ea. - T::enable(); - T::enable(); - T::reset(); + T::enable_and_reset(); + T::enable_and_reset(); de.set_as_af(de.af_num(), AFType::OutputPushPull); T::regs().cr3().write(|w| { @@ -256,7 +253,7 @@ impl<'d, T: BasicInstance> BufferedUart<'d, T> { (self.tx, self.rx) } - fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { + pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config) } } @@ -336,7 +333,7 @@ impl<'d, T: BasicInstance> BufferedUartRx<'d, T> { } } - fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { + pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config) } } @@ -410,7 +407,7 @@ impl<'d, T: BasicInstance> BufferedUartTx<'d, T> { } } - fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { + pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config) } } diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 2eb2e4e8..880ca416 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -228,8 +228,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { tx_dma: impl Peripheral

+ 'd, config: Config, ) -> Result { - T::enable(); - T::reset(); + T::enable_and_reset(); Self::new_inner(peri, tx, tx_dma, config) } @@ -243,8 +242,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { ) -> Result { into_ref!(cts); - T::enable(); - T::reset(); + T::enable_and_reset(); cts.set_as_af(cts.af_num(), AFType::Input); T::regs().cr3().write(|w| { @@ -276,7 +274,7 @@ impl<'d, T: BasicInstance, TxDma> UartTx<'d, T, TxDma> { }) } - fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { + pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config) } @@ -321,8 +319,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { rx_dma: impl Peripheral

+ 'd, config: Config, ) -> Result { - T::enable(); - T::reset(); + T::enable_and_reset(); Self::new_inner(peri, rx, rx_dma, config) } @@ -337,8 +334,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { ) -> Result { into_ref!(rts); - T::enable(); - T::reset(); + T::enable_and_reset(); rts.set_as_af(rts.af_num(), AFType::OutputPushPull); T::regs().cr3().write(|w| { @@ -377,7 +373,7 @@ impl<'d, T: BasicInstance, RxDma> UartRx<'d, T, RxDma> { }) } - fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { + pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { reconfigure::(config) } @@ -695,9 +691,8 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { config: Config, ) -> Result { // UartRx and UartTx have one refcount ea. - T::enable(); - T::enable(); - T::reset(); + T::enable_and_reset(); + T::enable_and_reset(); Self::new_inner(peri, rx, tx, tx_dma, rx_dma, config) } @@ -716,9 +711,8 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { into_ref!(cts, rts); // UartRx and UartTx have one refcount ea. - T::enable(); - T::enable(); - T::reset(); + T::enable_and_reset(); + T::enable_and_reset(); rts.set_as_af(rts.af_num(), AFType::OutputPushPull); cts.set_as_af(cts.af_num(), AFType::Input); @@ -743,9 +737,8 @@ impl<'d, T: BasicInstance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { into_ref!(de); // UartRx and UartTx have one refcount ea. - T::enable(); - T::enable(); - T::reset(); + T::enable_and_reset(); + T::enable_and_reset(); de.set_as_af(de.af_num(), AFType::OutputPushPull); T::regs().cr3().write(|w| { diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs index 535d1b1f..55489f2e 100644 --- a/embassy-stm32/src/usart/ringbuffered.rs +++ b/embassy-stm32/src/usart/ringbuffered.rs @@ -64,7 +64,7 @@ impl<'d, T: BasicInstance, RxDma: super::RxDma> RingBufferedUartRx<'d, T, RxD Err(err) } - fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { + pub fn set_config(&mut self, config: &Config) -> Result<(), ConfigError> { self.teardown_uart(); reconfigure::(config) } diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index b24fc74e..9269ddd8 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -269,8 +269,7 @@ impl<'d, T: Instance> Driver<'d, T> { #[cfg(pwr_h5)] crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true)); - ::enable(); - ::reset(); + ::enable_and_reset(); regs.cntr().write(|w| { w.set_pdwn(false); diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs index 1fe010bb..e45e4ac4 100644 --- a/embassy-stm32/src/usb_otg/usb.rs +++ b/embassy-stm32/src/usb_otg/usb.rs @@ -632,8 +632,7 @@ impl<'d, T: Instance> Bus<'d, T> { }); } - ::enable(); - ::reset(); + ::enable_and_reset(); T::Interrupt::unpend(); unsafe { T::Interrupt::enable() }; diff --git a/embassy-sync/Cargo.toml b/embassy-sync/Cargo.toml index f7739f30..7d3d2c58 100644 --- a/embassy-sync/Cargo.toml +++ b/embassy-sync/Cargo.toml @@ -35,7 +35,7 @@ futures-util = { version = "0.3.17", default-features = false } critical-section = "1.1" heapless = "0.7.5" cfg-if = "1.0.0" -embedded-io-async = { version = "0.5.0", optional = true } +embedded-io-async = { version = "0.6.0", optional = true } [dev-dependencies] futures-executor = { version = "0.3.17", features = [ "thread-pool" ] } diff --git a/embassy-sync/src/lib.rs b/embassy-sync/src/lib.rs index 8a9f841e..aca6ff38 100644 --- a/embassy-sync/src/lib.rs +++ b/embassy-sync/src/lib.rs @@ -1,5 +1,5 @@ #![cfg_attr(not(any(feature = "std", feature = "wasm")), no_std)] -#![cfg_attr(feature = "nightly", feature(async_fn_in_trait, impl_trait_projections))] +#![cfg_attr(feature = "nightly", feature(async_fn_in_trait))] #![allow(clippy::new_without_default)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] diff --git a/embassy-time/CHANGELOG.md b/embassy-time/CHANGELOG.md index e3b38455..0dd938c2 100644 --- a/embassy-time/CHANGELOG.md +++ b/embassy-time/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 0.1.4 - ??? +## 0.1.4 - 2023-10-12 - Added more tick rates diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml index 8f034a9d..e4b88d78 100644 --- a/embassy-time/Cargo.toml +++ b/embassy-time/Cargo.toml @@ -218,7 +218,6 @@ embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1", optional = embedded-hal-async = { version = "=1.0.0-rc.1", optional = true} futures-util = { version = "0.3.17", default-features = false } -atomic-polyfill = "1.0.1" critical-section = "1.1" cfg-if = "1.0.0" heapless = "0.7" diff --git a/embassy-usb/src/class/cdc_acm.rs b/embassy-usb/src/class/cdc_acm.rs index a341e10d..0c708464 100644 --- a/embassy-usb/src/class/cdc_acm.rs +++ b/embassy-usb/src/class/cdc_acm.rs @@ -1,10 +1,13 @@ //! CDC-ACM class implementation, aka Serial over USB. -use core::cell::Cell; +use core::cell::{Cell, RefCell}; +use core::future::poll_fn; use core::mem::{self, MaybeUninit}; use core::sync::atomic::{AtomicBool, Ordering}; +use core::task::Poll; use embassy_sync::blocking_mutex::CriticalSectionMutex; +use embassy_sync::waitqueue::WakerRegistration; use crate::control::{self, InResponse, OutResponse, Recipient, Request, RequestType}; use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; @@ -76,6 +79,9 @@ struct ControlShared { line_coding: CriticalSectionMutex>, dtr: AtomicBool, rts: AtomicBool, + + waker: RefCell, + changed: AtomicBool, } impl Default for ControlShared { @@ -89,10 +95,28 @@ impl Default for ControlShared { parity_type: ParityType::None, data_rate: 8_000, })), + waker: RefCell::new(WakerRegistration::new()), + changed: AtomicBool::new(false), } } } +impl ControlShared { + async fn changed(&self) { + poll_fn(|cx| match self.changed.load(Ordering::Relaxed) { + true => { + self.changed.store(false, Ordering::Relaxed); + Poll::Ready(()) + } + false => { + self.waker.borrow_mut().register(cx.waker()); + Poll::Pending + } + }) + .await + } +} + impl<'a> Control<'a> { fn shared(&mut self) -> &'a ControlShared { self.shared @@ -105,6 +129,9 @@ impl<'d> Handler for Control<'d> { shared.line_coding.lock(|x| x.set(LineCoding::default())); shared.dtr.store(false, Ordering::Relaxed); shared.rts.store(false, Ordering::Relaxed); + + shared.changed.store(true, Ordering::Relaxed); + shared.waker.borrow_mut().wake(); } fn control_out(&mut self, req: control::Request, data: &[u8]) -> Option { @@ -127,9 +154,13 @@ impl<'d> Handler for Control<'d> { parity_type: data[5].into(), data_bits: data[6], }; - self.shared().line_coding.lock(|x| x.set(coding)); + let shared = self.shared(); + shared.line_coding.lock(|x| x.set(coding)); debug!("Set line coding to: {:?}", coding); + shared.changed.store(true, Ordering::Relaxed); + shared.waker.borrow_mut().wake(); + Some(OutResponse::Accepted) } REQ_SET_CONTROL_LINE_STATE => { @@ -141,6 +172,9 @@ impl<'d> Handler for Control<'d> { shared.rts.store(rts, Ordering::Relaxed); debug!("Set dtr {}, rts {}", dtr, rts); + shared.changed.store(true, Ordering::Relaxed); + shared.waker.borrow_mut().wake(); + Some(OutResponse::Accepted) } _ => Some(OutResponse::Rejected), @@ -292,6 +326,38 @@ impl<'d, D: Driver<'d>> CdcAcmClass<'d, D> { }, ) } + + /// Split the class into sender, receiver and control + /// + /// Allows concurrently sending and receiving packets whilst monitoring for + /// control changes (dtr, rts) + pub fn split_with_control(self) -> (Sender<'d, D>, Receiver<'d, D>, ControlChanged<'d>) { + ( + Sender { + write_ep: self.write_ep, + control: self.control, + }, + Receiver { + read_ep: self.read_ep, + control: self.control, + }, + ControlChanged { control: self.control }, + ) + } +} + +/// CDC ACM Control status change monitor +/// +/// You can obtain a `ControlChanged` with [`CdcAcmClass::split_with_control`] +pub struct ControlChanged<'d> { + control: &'d ControlShared, +} + +impl<'d> ControlChanged<'d> { + /// Return a future for when the control settings change + pub async fn control_changed(&self) { + self.control.changed().await + } } /// CDC ACM class packet sender. diff --git a/embassy-usb/src/class/midi.rs b/embassy-usb/src/class/midi.rs new file mode 100644 index 00000000..c5cf8d87 --- /dev/null +++ b/embassy-usb/src/class/midi.rs @@ -0,0 +1,227 @@ +//! MIDI class implementation. + +use crate::driver::{Driver, Endpoint, EndpointError, EndpointIn, EndpointOut}; +use crate::Builder; + +/// This should be used as `device_class` when building the `UsbDevice`. +pub const USB_AUDIO_CLASS: u8 = 0x01; + +const USB_AUDIOCONTROL_SUBCLASS: u8 = 0x01; +const USB_MIDISTREAMING_SUBCLASS: u8 = 0x03; +const MIDI_IN_JACK_SUBTYPE: u8 = 0x02; +const MIDI_OUT_JACK_SUBTYPE: u8 = 0x03; +const EMBEDDED: u8 = 0x01; +const EXTERNAL: u8 = 0x02; +const CS_INTERFACE: u8 = 0x24; +const CS_ENDPOINT: u8 = 0x25; +const HEADER_SUBTYPE: u8 = 0x01; +const MS_HEADER_SUBTYPE: u8 = 0x01; +const MS_GENERAL: u8 = 0x01; +const PROTOCOL_NONE: u8 = 0x00; +const MIDI_IN_SIZE: u8 = 0x06; +const MIDI_OUT_SIZE: u8 = 0x09; + +/// Packet level implementation of a USB MIDI device. +/// +/// This class can be used directly and it has the least overhead due to directly reading and +/// writing USB packets with no intermediate buffers, but it will not act like a stream-like port. +/// The following constraints must be followed if you use this class directly: +/// +/// - `read_packet` must be called with a buffer large enough to hold max_packet_size bytes. +/// - `write_packet` must not be called with a buffer larger than max_packet_size bytes. +/// - If you write a packet that is exactly max_packet_size bytes long, it won't be processed by the +/// host operating system until a subsequent shorter packet is sent. A zero-length packet (ZLP) +/// can be sent if there is no other data to send. This is because USB bulk transactions must be +/// terminated with a short packet, even if the bulk endpoint is used for stream-like data. +pub struct MidiClass<'d, D: Driver<'d>> { + read_ep: D::EndpointOut, + write_ep: D::EndpointIn, +} + +impl<'d, D: Driver<'d>> MidiClass<'d, D> { + /// Creates a new MidiClass with the provided UsbBus, number of input and output jacks and max_packet_size in bytes. + /// For full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64. + pub fn new(builder: &mut Builder<'d, D>, n_in_jacks: u8, n_out_jacks: u8, max_packet_size: u16) -> Self { + let mut func = builder.function(USB_AUDIO_CLASS, USB_AUDIOCONTROL_SUBCLASS, PROTOCOL_NONE); + + // Audio control interface + let mut iface = func.interface(); + let audio_if = iface.interface_number(); + let midi_if = u8::from(audio_if) + 1; + let mut alt = iface.alt_setting(USB_AUDIO_CLASS, USB_AUDIOCONTROL_SUBCLASS, PROTOCOL_NONE, None); + alt.descriptor(CS_INTERFACE, &[HEADER_SUBTYPE, 0x00, 0x01, 0x09, 0x00, 0x01, midi_if]); + + // MIDIStreaming interface + let mut iface = func.interface(); + let _midi_if = iface.interface_number(); + let mut alt = iface.alt_setting(USB_AUDIO_CLASS, USB_MIDISTREAMING_SUBCLASS, PROTOCOL_NONE, None); + + let midi_streaming_total_length = 7 + + (n_in_jacks + n_out_jacks) as usize * (MIDI_IN_SIZE + MIDI_OUT_SIZE) as usize + + 7 + + (4 + n_out_jacks as usize) + + 7 + + (4 + n_in_jacks as usize); + + alt.descriptor( + CS_INTERFACE, + &[ + MS_HEADER_SUBTYPE, + 0x00, + 0x01, + (midi_streaming_total_length & 0xFF) as u8, + ((midi_streaming_total_length >> 8) & 0xFF) as u8, + ], + ); + + // Calculates the index'th external midi in jack id + let in_jack_id_ext = |index| 2 * index + 1; + // Calculates the index'th embedded midi out jack id + let out_jack_id_emb = |index| 2 * index + 2; + // Calculates the index'th external midi out jack id + let out_jack_id_ext = |index| 2 * n_in_jacks + 2 * index + 1; + // Calculates the index'th embedded midi in jack id + let in_jack_id_emb = |index| 2 * n_in_jacks + 2 * index + 2; + + for i in 0..n_in_jacks { + alt.descriptor(CS_INTERFACE, &[MIDI_IN_JACK_SUBTYPE, EXTERNAL, in_jack_id_ext(i), 0x00]); + } + + for i in 0..n_out_jacks { + alt.descriptor(CS_INTERFACE, &[MIDI_IN_JACK_SUBTYPE, EMBEDDED, in_jack_id_emb(i), 0x00]); + } + + for i in 0..n_out_jacks { + alt.descriptor( + CS_INTERFACE, + &[ + MIDI_OUT_JACK_SUBTYPE, + EXTERNAL, + out_jack_id_ext(i), + 0x01, + in_jack_id_emb(i), + 0x01, + 0x00, + ], + ); + } + + for i in 0..n_in_jacks { + alt.descriptor( + CS_INTERFACE, + &[ + MIDI_OUT_JACK_SUBTYPE, + EMBEDDED, + out_jack_id_emb(i), + 0x01, + in_jack_id_ext(i), + 0x01, + 0x00, + ], + ); + } + + let mut endpoint_data = [ + MS_GENERAL, 0, // Number of jacks + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Jack mappings + ]; + endpoint_data[1] = n_out_jacks; + for i in 0..n_out_jacks { + endpoint_data[2 + i as usize] = in_jack_id_emb(i); + } + let read_ep = alt.endpoint_bulk_out(max_packet_size); + alt.descriptor(CS_ENDPOINT, &endpoint_data[0..2 + n_out_jacks as usize]); + + endpoint_data[1] = n_in_jacks; + for i in 0..n_in_jacks { + endpoint_data[2 + i as usize] = out_jack_id_emb(i); + } + let write_ep = alt.endpoint_bulk_in(max_packet_size); + alt.descriptor(CS_ENDPOINT, &endpoint_data[0..2 + n_in_jacks as usize]); + + MidiClass { read_ep, write_ep } + } + + /// Gets the maximum packet size in bytes. + pub fn max_packet_size(&self) -> u16 { + // The size is the same for both endpoints. + self.read_ep.info().max_packet_size + } + + /// Writes a single packet into the IN endpoint. + pub async fn write_packet(&mut self, data: &[u8]) -> Result<(), EndpointError> { + self.write_ep.write(data).await + } + + /// Reads a single packet from the OUT endpoint. + pub async fn read_packet(&mut self, data: &mut [u8]) -> Result { + self.read_ep.read(data).await + } + + /// Waits for the USB host to enable this interface + pub async fn wait_connection(&mut self) { + self.read_ep.wait_enabled().await + } + + /// Split the class into a sender and receiver. + /// + /// This allows concurrently sending and receiving packets from separate tasks. + pub fn split(self) -> (Sender<'d, D>, Receiver<'d, D>) { + ( + Sender { + write_ep: self.write_ep, + }, + Receiver { read_ep: self.read_ep }, + ) + } +} + +/// Midi class packet sender. +/// +/// You can obtain a `Sender` with [`MidiClass::split`] +pub struct Sender<'d, D: Driver<'d>> { + write_ep: D::EndpointIn, +} + +impl<'d, D: Driver<'d>> Sender<'d, D> { + /// Gets the maximum packet size in bytes. + pub fn max_packet_size(&self) -> u16 { + // The size is the same for both endpoints. + self.write_ep.info().max_packet_size + } + + /// Writes a single packet. + pub async fn write_packet(&mut self, data: &[u8]) -> Result<(), EndpointError> { + self.write_ep.write(data).await + } + + /// Waits for the USB host to enable this interface + pub async fn wait_connection(&mut self) { + self.write_ep.wait_enabled().await + } +} + +/// Midi class packet receiver. +/// +/// You can obtain a `Receiver` with [`MidiClass::split`] +pub struct Receiver<'d, D: Driver<'d>> { + read_ep: D::EndpointOut, +} + +impl<'d, D: Driver<'d>> Receiver<'d, D> { + /// Gets the maximum packet size in bytes. + pub fn max_packet_size(&self) -> u16 { + // The size is the same for both endpoints. + self.read_ep.info().max_packet_size + } + + /// Reads a single packet. + pub async fn read_packet(&mut self, data: &mut [u8]) -> Result { + self.read_ep.read(data).await + } + + /// Waits for the USB host to enable this interface + pub async fn wait_connection(&mut self) { + self.read_ep.wait_enabled().await + } +} diff --git a/embassy-usb/src/class/mod.rs b/embassy-usb/src/class/mod.rs index b23e03d4..452eedf1 100644 --- a/embassy-usb/src/class/mod.rs +++ b/embassy-usb/src/class/mod.rs @@ -2,3 +2,4 @@ pub mod cdc_acm; pub mod cdc_ncm; pub mod hid; +pub mod midi; diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml index 435a3391..4c570cf2 100644 --- a/examples/boot/application/nrf/Cargo.toml +++ b/examples/boot/application/nrf/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] } -embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly"] } +embassy-time = { version = "0.1.4", path = "../../../../embassy-time", features = ["nightly"] } embassy-nrf = { version = "0.1.0", path = "../../../../embassy-nrf", features = ["time-driver-rtc1", "gpiote", "nightly"] } embassy-boot = { version = "0.1.0", path = "../../../../embassy-boot/boot", features = ["nightly"] } embassy-boot-nrf = { version = "0.1.0", path = "../../../../embassy-boot/nrf", features = ["nightly"] } diff --git a/examples/boot/application/rp/Cargo.toml b/examples/boot/application/rp/Cargo.toml index 01cfc599..330eac41 100644 --- a/examples/boot/application/rp/Cargo.toml +++ b/examples/boot/application/rp/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers", "arch-cortex-m", "executor-thread"] } -embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly"] } +embassy-time = { version = "0.1.4", path = "../../../../embassy-time", features = ["nightly"] } embassy-rp = { version = "0.1.0", path = "../../../../embassy-rp", features = ["time-driver", "unstable-traits", "nightly"] } embassy-boot-rp = { version = "0.1.0", path = "../../../../embassy-boot/rp", features = ["nightly"] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml index a0649cf8..0ee7241a 100644 --- a/examples/boot/application/stm32f3/Cargo.toml +++ b/examples/boot/application/stm32f3/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } -embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } +embassy-time = { version = "0.1.4", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f303re", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml index ca1c0c42..fdc02c28 100644 --- a/examples/boot/application/stm32f7/Cargo.toml +++ b/examples/boot/application/stm32f7/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } -embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } +embassy-time = { version = "0.1.4", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32f767zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml index e50c8c41..de309ae0 100644 --- a/examples/boot/application/stm32h7/Cargo.toml +++ b/examples/boot/application/stm32h7/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } -embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } +embassy-time = { version = "0.1.4", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32h743zi", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml index 1f1a0f3c..5bee7458 100644 --- a/examples/boot/application/stm32l0/Cargo.toml +++ b/examples/boot/application/stm32l0/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } -embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } +embassy-time = { version = "0.1.4", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l072cz", "time-driver-any", "exti", "memory-x"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml index 45b12813..cc0b4509 100644 --- a/examples/boot/application/stm32l1/Cargo.toml +++ b/examples/boot/application/stm32l1/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } -embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } +embassy-time = { version = "0.1.4", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l151cb-a", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml index d0d0d0fb..85fff4bf 100644 --- a/examples/boot/application/stm32l4/Cargo.toml +++ b/examples/boot/application/stm32l4/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } -embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } +embassy-time = { version = "0.1.4", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32l475vg", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml index 3265b9f1..78d92468 100644 --- a/examples/boot/application/stm32wl/Cargo.toml +++ b/examples/boot/application/stm32wl/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.3.0", path = "../../../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "nightly", "integrated-timers"] } -embassy-time = { version = "0.1.3", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } +embassy-time = { version = "0.1.4", path = "../../../../embassy-time", features = ["nightly", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../../../embassy-stm32", features = ["unstable-traits", "nightly", "stm32wl55jc-cm4", "time-driver-any", "exti"] } embassy-boot-stm32 = { version = "0.1.0", path = "../../../../embassy-boot/stm32", features = ["nightly"] } embassy-embedded-hal = { version = "0.1.0", path = "../../../../embassy-embedded-hal" } diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml index e402e49f..01983005 100644 --- a/examples/nrf-rtos-trace/Cargo.toml +++ b/examples/nrf-rtos-trace/Cargo.toml @@ -18,7 +18,7 @@ log = [ [dependencies] embassy-sync = { version = "0.3.0", path = "../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "rtos-trace", "rtos-trace-interrupt", "integrated-timers"] } -embassy-time = { version = "0.1.3", path = "../../embassy-time" } +embassy-time = { version = "0.1.4", path = "../../embassy-time" } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } diff --git a/examples/nrf52840-rtic/Cargo.toml b/examples/nrf52840-rtic/Cargo.toml index c588b807..7428f85f 100644 --- a/examples/nrf52840-rtic/Cargo.toml +++ b/examples/nrf52840-rtic/Cargo.toml @@ -9,7 +9,7 @@ rtic = { version = "2", features = ["thumbv7-backend"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } -embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "generic-queue"] } +embassy-time = { version = "0.1.4", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "generic-queue"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nightly", "unstable-traits", "defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } defmt = "0.3" diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index d45e006c..7a3ef54f 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -31,12 +31,12 @@ nightly = [ embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-time = { version = "0.1.4", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 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-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt", "msos-descriptor",], optional = true } -embedded-io = { version = "0.5.0", features = ["defmt-03"] } -embedded-io-async = { version = "0.5.0", optional = true, features = ["defmt-03"] } +embedded-io = { version = "0.6.0", features = ["defmt-03"] } +embedded-io-async = { version = "0.6.0", optional = true, features = ["defmt-03"] } embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"], optional = true } lora-phy = { version = "2", optional = true } lorawan-device = { version = "0.11.0", default-features = false, features = ["async", "external-lora-phy"], optional = true } diff --git a/examples/nrf5340/Cargo.toml b/examples/nrf5340/Cargo.toml index 86d969ed..5824d57b 100644 --- a/examples/nrf5340/Cargo.toml +++ b/examples/nrf5340/Cargo.toml @@ -14,7 +14,7 @@ embassy-executor = { version = "0.3.0", path = "../../embassy-executor", feature "defmt", "integrated-timers", ] } -embassy-time = { version = "0.1.3", path = "../../embassy-time", features = [ +embassy-time = { version = "0.1.4", path = "../../embassy-time", features = [ "defmt", "defmt-timestamp-uptime", ] } @@ -37,7 +37,7 @@ embassy-net = { version = "0.1.0", path = "../../embassy-net", features = [ embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = [ "defmt", ] } -embedded-io-async = { version = "0.5.0" } +embedded-io-async = { version = "0.6.0" } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 2677e040..6eeb1ceb 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal", 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", "executor-interrupt", "defmt", "integrated-timers"] } -embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime"] } +embassy-time = { version = "0.1.4", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "critical-section-impl"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "udp", "dhcpv4", "medium-ethernet"] } @@ -45,7 +45,7 @@ usbd-hid = "0.6.1" embedded-hal-1 = { package = "embedded-hal", version = "=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-io-async = { version = "0.5.0", features = ["defmt-03"] } +embedded-io-async = { version = "0.6.0", features = ["defmt-03"] } embedded-storage = { version = "0.3" } static_cell = { version = "1.1", features = ["nightly"]} log = "0.4" diff --git a/examples/rp/src/bin/usb_hid_keyboard.rs b/examples/rp/src/bin/usb_hid_keyboard.rs index 99af1f02..cc2090d2 100644 --- a/examples/rp/src/bin/usb_hid_keyboard.rs +++ b/examples/rp/src/bin/usb_hid_keyboard.rs @@ -78,6 +78,9 @@ async fn main(_spawner: Spawner) { // Set up the signal pin that will be used to trigger the keyboard. let mut signal_pin = Input::new(p.PIN_16, Pull::None); + // Enable the schmitt trigger to slightly debounce. + signal_pin.set_schmitt(true); + let (reader, mut writer) = hid.split(); // Do stuff with the class! diff --git a/examples/rp/src/bin/usb_midi.rs b/examples/rp/src/bin/usb_midi.rs new file mode 100644 index 00000000..f0b03c81 --- /dev/null +++ b/examples/rp/src/bin/usb_midi.rs @@ -0,0 +1,110 @@ +//! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip. +//! +//! This creates a USB MIDI device that echoes MIDI messages back to the host. + +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::{info, panic}; +use embassy_executor::Spawner; +use embassy_futures::join::join; +use embassy_rp::bind_interrupts; +use embassy_rp::peripherals::USB; +use embassy_rp::usb::{Driver, Instance, InterruptHandler}; +use embassy_usb::class::midi::MidiClass; +use embassy_usb::driver::EndpointError; +use embassy_usb::{Builder, Config}; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + USBCTRL_IRQ => InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + info!("Hello world!"); + + let p = embassy_rp::init(Default::default()); + + // Create the driver, from the HAL. + let driver = Driver::new(p.USB, Irqs); + + // Create embassy-usb Config + let mut config = Config::new(0xc0de, 0xcafe); + config.manufacturer = Some("Embassy"); + config.product = Some("USB-MIDI example"); + config.serial_number = Some("12345678"); + config.max_power = 100; + config.max_packet_size_0 = 64; + + // Required for windows compatibility. + // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help + config.device_class = 0xEF; + config.device_sub_class = 0x02; + config.device_protocol = 0x01; + config.composite_with_iads = true; + + // Create embassy-usb DeviceBuilder using the driver and config. + // It needs some buffers for building the descriptors. + let mut device_descriptor = [0; 256]; + let mut config_descriptor = [0; 256]; + let mut bos_descriptor = [0; 256]; + let mut control_buf = [0; 64]; + + let mut builder = Builder::new( + driver, + config, + &mut device_descriptor, + &mut config_descriptor, + &mut bos_descriptor, + &mut control_buf, + ); + + // Create classes on the builder. + let mut class = MidiClass::new(&mut builder, 1, 1, 64); + + // The `MidiClass` can be split into `Sender` and `Receiver`, to be used in separate tasks. + // let (sender, receiver) = class.split(); + + // Build the builder. + let mut usb = builder.build(); + + // Run the USB device. + let usb_fut = usb.run(); + + // Use the Midi class! + let midi_fut = async { + loop { + class.wait_connection().await; + info!("Connected"); + let _ = midi_echo(&mut class).await; + info!("Disconnected"); + } + }; + + // Run everything concurrently. + // If we had made everything `'static` above instead, we could do this using separate tasks instead. + join(usb_fut, midi_fut).await; +} + +struct Disconnected {} + +impl From for Disconnected { + fn from(val: EndpointError) -> Self { + match val { + EndpointError::BufferOverflow => panic!("Buffer overflow"), + EndpointError::Disabled => Disconnected {}, + } + } +} + +async fn midi_echo<'d, T: Instance + 'd>(class: &mut MidiClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> { + let mut buf = [0; 64]; + loop { + let n = class.read_packet(&mut buf).await?; + let data = &buf[..n]; + info!("data: {:x}", data); + class.write_packet(data).await?; + } +} diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs index cd61ad78..98cae53f 100644 --- a/examples/rp/src/bin/wifi_ap_tcp_server.rs +++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs @@ -52,7 +52,7 @@ async fn main(spawner: Spawner) { // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 - //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) }; + //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) }; //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; let pwr = Output::new(p.PIN_23, Level::Low); diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs index 33d43788..14ace74e 100644 --- a/examples/rp/src/bin/wifi_blinky.rs +++ b/examples/rp/src/bin/wifi_blinky.rs @@ -38,7 +38,7 @@ async fn main(spawner: Spawner) { // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 - //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) }; + //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) }; //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; let pwr = Output::new(p.PIN_23, Level::Low); diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs index 743fab61..dbbbf6c8 100644 --- a/examples/rp/src/bin/wifi_scan.rs +++ b/examples/rp/src/bin/wifi_scan.rs @@ -49,7 +49,7 @@ async fn main(spawner: Spawner) { // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 - //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) }; + //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) }; //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; let pwr = Output::new(p.PIN_23, Level::Low); diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs index 55fcb4a6..64cf9517 100644 --- a/examples/rp/src/bin/wifi_tcp_server.rs +++ b/examples/rp/src/bin/wifi_tcp_server.rs @@ -18,7 +18,7 @@ use embassy_rp::bind_interrupts; use embassy_rp::gpio::{Level, Output}; use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0}; use embassy_rp::pio::{InterruptHandler, Pio}; -use embassy_time::Duration; +use embassy_time::{Duration, Timer}; use embedded_io_async::Write; use static_cell::make_static; use {defmt_rtt as _, panic_probe as _}; @@ -55,7 +55,7 @@ async fn main(spawner: Spawner) { // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 - //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) }; + //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) }; //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; let pwr = Output::new(p.PIN_23, Level::Low); @@ -102,6 +102,13 @@ async fn main(spawner: Spawner) { } } + // Wait for DHCP, not necessary when using static IP + info!("waiting for DHCP..."); + while !stack.is_config_up() { + Timer::after(Duration::from_millis(100)).await; + } + info!("DHCP is now up!"); + // And now we can use it! let mut rx_buffer = [0; 4096]; diff --git a/examples/std/Cargo.toml b/examples/std/Cargo.toml index e54f3698..444dd500 100644 --- a/examples/std/Cargo.toml +++ b/examples/std/Cargo.toml @@ -7,12 +7,12 @@ license = "MIT OR Apache-2.0" [dependencies] embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["log"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-std", "executor-thread", "log", "nightly", "integrated-timers"] } -embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["log", "std", "nightly"] } +embassy-time = { version = "0.1.4", path = "../../embassy-time", features = ["log", "std", "nightly"] } 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-ppp = { version = "0.1.0", path = "../../embassy-net-ppp", features = ["log"]} -embedded-io-async = { version = "0.5.0" } -embedded-io-adapters = { version = "0.5.0", features = ["futures-03"] } +embedded-io-async = { version = "0.6.0" } +embedded-io-adapters = { version = "0.6.0", features = ["futures-03"] } critical-section = { version = "1.1", features = ["std"] } smoltcp = { version = "0.10.0", features = ["dns-max-server-count-4"] } diff --git a/examples/std/src/bin/net_ppp.rs b/examples/std/src/bin/net_ppp.rs index 9cf6e19d..9ea07b29 100644 --- a/examples/std/src/bin/net_ppp.rs +++ b/examples/std/src/bin/net_ppp.rs @@ -8,7 +8,7 @@ //! nc 192.168.7.10 1234 #![feature(type_alias_impl_trait)] -#![feature(async_fn_in_trait, impl_trait_projections)] +#![feature(async_fn_in_trait)] #[path = "../serial_port.rs"] mod serial_port; diff --git a/examples/stm32c0/Cargo.toml b/examples/stm32c0/Cargo.toml index 89ecc499..8d65a399 100644 --- a/examples/stm32c0/Cargo.toml +++ b/examples/stm32c0/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32c031c6", "memory-x", "unstable-pac", "exti"] } 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-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.4", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml index db9a24d7..750d5304 100644 --- a/examples/stm32f0/Cargo.toml +++ b/examples/stm32f0/Cargo.toml @@ -16,7 +16,7 @@ defmt-rtt = "0.4" panic-probe = "0.3" 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", "executor-interrupt", "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.4", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } static_cell = { version = "1.1", features = ["nightly"]} [profile.release] diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml index b032ba81..664be1f9 100644 --- a/examples/stm32f1/Cargo.toml +++ b/examples/stm32f1/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-any", "unstable-traits" ] } 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-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.4", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f2/Cargo.toml b/examples/stm32f2/Cargo.toml index 1314b6b1..7330eef3 100644 --- a/examples/stm32f2/Cargo.toml +++ b/examples/stm32f2/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f207zg", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 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-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.4", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32f2/src/bin/pll.rs b/examples/stm32f2/src/bin/pll.rs index 89493761..62aaa980 100644 --- a/examples/stm32f2/src/bin/pll.rs +++ b/examples/stm32f2/src/bin/pll.rs @@ -7,7 +7,7 @@ use core::convert::TryFrom; use defmt::*; use embassy_executor::Spawner; use embassy_stm32::rcc::{ - APBPrescaler, ClockSrc, HSEConfig, HSESrc, PLL48Div, PLLConfig, PLLMainDiv, PLLMul, PLLPreDiv, PLLSrc, + APBPrescaler, ClockSrc, HSEConfig, HSESrc, PLLConfig, PLLMul, PLLPDiv, PLLPreDiv, PLLQDiv, PLLSrc, }; use embassy_stm32::time::Hertz; use embassy_stm32::Config; @@ -32,9 +32,9 @@ async fn main(_spawner: Spawner) { // 1 MHz PLL input * 240 = 240 MHz PLL VCO mul: unwrap!(PLLMul::try_from(240)), // 240 MHz PLL VCO / 2 = 120 MHz main PLL output - main_div: PLLMainDiv::Div2, + p_div: PLLPDiv::DIV2, // 240 MHz PLL VCO / 5 = 48 MHz PLL48 output - pll48_div: unwrap!(PLL48Div::try_from(5)), + q_div: PLLQDiv::DIV5, }; // System clock comes from PLL (= the 120 MHz main PLL output) config.rcc.mux = ClockSrc::PLL; diff --git a/examples/stm32f3/Cargo.toml b/examples/stm32f3/Cargo.toml index 534e783d..6ff425fa 100644 --- a/examples/stm32f3/Cargo.toml +++ b/examples/stm32f3/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f303ze", "unstable-pac", "memory-x", "time-driver-any", "exti"] } 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", "executor-interrupt", "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.4", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs index ed246a7d..a9286c44 100644 --- a/examples/stm32f334/src/bin/adc.rs +++ b/examples/stm32f334/src/bin/adc.rs @@ -6,7 +6,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::peripherals::ADC1; -use embassy_stm32::rcc::AdcClockSource; +use embassy_stm32::rcc::{AdcClockSource, Adcpres}; use embassy_stm32::time::mhz; use embassy_stm32::{adc, bind_interrupts, Config}; use embassy_time::{Delay, Duration, Timer}; @@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) -> ! { config.rcc.hclk = Some(mhz(64)); config.rcc.pclk1 = Some(mhz(32)); config.rcc.pclk2 = Some(mhz(64)); - config.rcc.adc = Some(AdcClockSource::PllDiv1); + config.rcc.adc = Some(AdcClockSource::Pll(Adcpres::DIV1)); let mut p = embassy_stm32::init(config); diff --git a/examples/stm32f334/src/bin/opamp.rs b/examples/stm32f334/src/bin/opamp.rs new file mode 100644 index 00000000..fb5a85bc --- /dev/null +++ b/examples/stm32f334/src/bin/opamp.rs @@ -0,0 +1,59 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::info; +use embassy_executor::Spawner; +use embassy_stm32::adc::{Adc, SampleTime}; +use embassy_stm32::opamp::{OpAmp, OpAmpGain}; +use embassy_stm32::peripherals::ADC2; +use embassy_stm32::rcc::{AdcClockSource, Adcpres}; +use embassy_stm32::time::mhz; +use embassy_stm32::{adc, bind_interrupts, Config}; +use embassy_time::{Delay, Duration, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + ADC1_2 => adc::InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + let mut config = Config::default(); + config.rcc.sysclk = Some(mhz(64)); + config.rcc.hclk = Some(mhz(64)); + config.rcc.pclk1 = Some(mhz(32)); + config.rcc.pclk2 = Some(mhz(64)); + config.rcc.adc = Some(AdcClockSource::Pll(Adcpres::DIV1)); + + let mut p = embassy_stm32::init(config); + + info!("create adc..."); + + let mut adc = Adc::new(p.ADC2, Irqs, &mut Delay); + let mut opamp = OpAmp::new(p.OPAMP2); + + adc.set_sample_time(SampleTime::Cycles601_5); + + info!("enable vrefint..."); + + let mut vrefint = adc.enable_vref(&mut Delay); + let mut temperature = adc.enable_temperature(); + let mut buffer = opamp.buffer_for(&mut p.PA7, OpAmpGain::Mul1); + + loop { + let vref = adc.read(&mut vrefint).await; + info!("read vref: {} (should be {})", vref, vrefint.value()); + + let temp = adc.read(&mut temperature).await; + info!("read temperature: {}", temp); + + let buffer = adc.read(&mut buffer).await; + info!("read buffer: {}", buffer); + + let pin_mv = (buffer as u32 * vrefint.value() as u32 / vref as u32) * 3300 / 4095; + info!("computed pin mv: {}", pin_mv); + + Timer::after(Duration::from_millis(500)).await; + } +} diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml index 4b4fb479..b76238ee 100644 --- a/examples/stm32f4/Cargo.toml +++ b/examples/stm32f4/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32f429zi", "unstable-pac", "memory-x", "time-driver-any", "exti", "embedded-sdmmc", "chrono"] } 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", "executor-interrupt", "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.4", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"] } @@ -19,8 +19,8 @@ defmt-rtt = "0.4" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" -embedded-io = { version = "0.5.0" } -embedded-io-async = { version = "0.5.0" } +embedded-io = { version = "0.6.0" } +embedded-io-async = { version = "0.6.0" } panic-probe = { version = "0.3", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.7.5", default-features = false } diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs index 16bf5d94..6a1d4b08 100644 --- a/examples/stm32f4/src/bin/eth.rs +++ b/examples/stm32f4/src/bin/eth.rs @@ -58,9 +58,8 @@ async fn main(spawner: Spawner) -> ! { p.PG13, p.PB13, p.PG11, - GenericSMI::new(), + GenericSMI::new(0), mac_addr, - 0, ); let config = embassy_net::Config::dhcpv4(Default::default()); diff --git a/examples/stm32f4/src/bin/i2c.rs b/examples/stm32f4/src/bin/i2c.rs index a9295732..032bd97e 100644 --- a/examples/stm32f4/src/bin/i2c.rs +++ b/examples/stm32f4/src/bin/i2c.rs @@ -5,10 +5,9 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::dma::NoDma; -use embassy_stm32::i2c::{Error, I2c, TimeoutI2c}; +use embassy_stm32::i2c::{Error, I2c}; use embassy_stm32::time::Hertz; use embassy_stm32::{bind_interrupts, i2c, peripherals}; -use embassy_time::Duration; use {defmt_rtt as _, panic_probe as _}; const ADDRESS: u8 = 0x5F; @@ -34,13 +33,9 @@ async fn main(_spawner: Spawner) { Default::default(), ); - // I2C bus can freeze if SCL line is shorted or due to a broken device that clock stretches for too long. - // TimeoutI2c allows recovering from such errors by throwing `Error::Timeout` after a given delay. - let mut timeout_i2c = TimeoutI2c::new(&mut i2c, Duration::from_millis(1000)); - let mut data = [0u8; 1]; - match timeout_i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) { + match i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) { Ok(()) => info!("Whoami: {}", data[0]), Err(Error::Timeout) => error!("Operation timed out"), Err(e) => error!("I2c Error: {:?}", e), diff --git a/examples/stm32f4/src/bin/mco.rs b/examples/stm32f4/src/bin/mco.rs index 2b9ceebc..5144a78c 100644 --- a/examples/stm32f4/src/bin/mco.rs +++ b/examples/stm32f4/src/bin/mco.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::gpio::{Level, Output, Speed}; -use embassy_stm32::rcc::{Mco, Mco1Source, Mco2Source, McoClock}; +use embassy_stm32::rcc::{Mco, Mco1Source, Mco2Source, McoPrescaler}; use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -14,8 +14,8 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let _mco1 = Mco::new(p.MCO1, p.PA8, Mco1Source::Hsi, McoClock::DIV1); - let _mco2 = Mco::new(p.MCO2, p.PC9, Mco2Source::Pll, McoClock::DIV4); + let _mco1 = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, McoPrescaler::DIV1); + let _mco2 = Mco::new(p.MCO2, p.PC9, Mco2Source::PLL, McoPrescaler::DIV4); let mut led = Output::new(p.PB7, Level::High, Speed::Low); loop { diff --git a/examples/stm32f4/src/bin/rtc.rs b/examples/stm32f4/src/bin/rtc.rs index e3374600..e95ad577 100644 --- a/examples/stm32f4/src/bin/rtc.rs +++ b/examples/stm32f4/src/bin/rtc.rs @@ -5,16 +5,14 @@ use chrono::{NaiveDate, NaiveDateTime}; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::rtc::{Rtc, RtcClockSource, RtcConfig}; +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.lsi = true; - config.rcc.rtc = Option::Some(RtcClockSource::LSI); + let config = Config::default(); let p = embassy_stm32::init(config); info!("Hello World!"); diff --git a/examples/stm32f7/Cargo.toml b/examples/stm32f7/Cargo.toml index bf8f413d..01549f11 100644 --- a/examples/stm32f7/Cargo.toml +++ b/examples/stm32f7/Cargo.toml @@ -9,9 +9,9 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f767zi", "memory-x", "unstable-pac", "time-driver-any", "exti"] } 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-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.4", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] } -embedded-io-async = { version = "0.5.0" } +embedded-io-async = { version = "0.6.0" } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } defmt = "0.3" diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index 93c97c8e..7c9ee159 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs @@ -59,9 +59,8 @@ async fn main(spawner: Spawner) -> ! { p.PG13, p.PB13, p.PG11, - GenericSMI::new(), + GenericSMI::new(0), mac_addr, - 0, ); let config = embassy_net::Config::dhcpv4(Default::default()); diff --git a/examples/stm32g0/Cargo.toml b/examples/stm32g0/Cargo.toml index b4b423d5..4d10e82d 100644 --- a/examples/stm32g0/Cargo.toml +++ b/examples/stm32g0/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g071rb", "memory-x", "unstable-pac", "exti"] } 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-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.4", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml index 59da0628..4b0b1084 100644 --- a/examples/stm32g4/Cargo.toml +++ b/examples/stm32g4/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } 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-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.4", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } usbd-hid = "0.6.0" diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs index a792748b..30a112b7 100644 --- a/examples/stm32g4/src/bin/adc.rs +++ b/examples/stm32g4/src/bin/adc.rs @@ -16,15 +16,15 @@ async fn main(_spawner: Spawner) { config.rcc.pll = Some(Pll { source: PllSrc::HSI16, - prediv_m: PllM::Div4, - mul_n: PllN::Mul85, + prediv_m: PllM::DIV4, + mul_n: PllN::MUL85, div_p: None, div_q: None, // 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; let mut p = embassy_stm32::init(config); diff --git a/examples/stm32g4/src/bin/pll.rs b/examples/stm32g4/src/bin/pll.rs index ef7d4800..f8159cb5 100644 --- a/examples/stm32g4/src/bin/pll.rs +++ b/examples/stm32g4/src/bin/pll.rs @@ -15,12 +15,12 @@ async fn main(_spawner: Spawner) { config.rcc.pll = Some(Pll { source: PllSrc::HSI16, - prediv_m: PllM::Div4, - mul_n: PllN::Mul85, + prediv_m: PllM::DIV4, + mul_n: PllN::MUL85, div_p: None, div_q: None, // Main system clock at 170 MHz - div_r: Some(PllR::Div2), + div_r: Some(PllR::DIV2), }); config.rcc.mux = ClockSrc::PLL; diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs index 77cfa67d..9099b609 100644 --- a/examples/stm32g4/src/bin/usb_serial.rs +++ b/examples/stm32g4/src/bin/usb_serial.rs @@ -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. 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 { source: PllSrc::HSE(Hertz(8_000_000)), - prediv_m: PllM::Div2, - mul_n: PllN::Mul72, + prediv_m: PllM::DIV2, + mul_n: PllN::MUL72, div_p: None, div_q: pllq_div, // Main system clock at 144 MHz - div_r: Some(PllR::Div2), + div_r: Some(PllR::DIV2), }); config.rcc.mux = ClockSrc::PLL; diff --git a/examples/stm32h5/Cargo.toml b/examples/stm32h5/Cargo.toml index 42a42618..bc6d5898 100644 --- a/examples/stm32h5/Cargo.toml +++ b/examples/stm32h5/Cargo.toml @@ -9,9 +9,9 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32h563zi", "memory-x", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } 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-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } +embassy-time = { version = "0.1.4", 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"] } -embedded-io-async = { version = "0.5.0" } +embedded-io-async = { version = "0.6.0" } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } defmt = "0.3" @@ -22,7 +22,7 @@ cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" } embedded-hal-async = { version = "=1.0.0-rc.1" } -embedded-nal-async = { version = "0.5.0" } +embedded-nal-async = { version = "0.6.0" } panic-probe = { version = "0.3", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.7.5", default-features = false } diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs index 4e92d064..2535c6a6 100644 --- a/examples/stm32h5/src/bin/eth.rs +++ b/examples/stm32h5/src/bin/eth.rs @@ -9,7 +9,9 @@ use embassy_net::{Ipv4Address, Stack, StackResources}; use embassy_stm32::eth::generic_smi::GenericSMI; use embassy_stm32::eth::{Ethernet, PacketQueue}; use embassy_stm32::peripherals::ETH; -use embassy_stm32::rcc::{AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllSource, Sysclk, VoltageScale}; +use embassy_stm32::rcc::{ + AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllDiv, PllMul, PllPreDiv, PllSource, Sysclk, VoltageScale, +}; use embassy_stm32::rng::Rng; use embassy_stm32::time::Hertz; use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; @@ -42,10 +44,10 @@ async fn main(spawner: Spawner) -> ! { }); config.rcc.pll1 = Some(Pll { source: PllSource::Hse, - prediv: 2, - mul: 125, - divp: Some(2), - divq: Some(2), + prediv: PllPreDiv::DIV2, + mul: PllMul::MUL125, + divp: Some(PllDiv::DIV2), + divq: Some(PllDiv::DIV2), divr: None, }); config.rcc.ahb_pre = AHBPrescaler::DIV1; @@ -78,9 +80,8 @@ async fn main(spawner: Spawner) -> ! { p.PG13, p.PB15, p.PG11, - GenericSMI::new(), + GenericSMI::new(0), mac_addr, - 0, ); let config = embassy_net::Config::dhcpv4(Default::default()); diff --git a/examples/stm32h5/src/bin/i2c.rs b/examples/stm32h5/src/bin/i2c.rs index 8b6fe71a..8b1662f3 100644 --- a/examples/stm32h5/src/bin/i2c.rs +++ b/examples/stm32h5/src/bin/i2c.rs @@ -4,10 +4,9 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::i2c::{Error, I2c, TimeoutI2c}; +use embassy_stm32::i2c::{Error, I2c}; use embassy_stm32::time::Hertz; use embassy_stm32::{bind_interrupts, i2c, peripherals}; -use embassy_time::Duration; use {defmt_rtt as _, panic_probe as _}; const ADDRESS: u8 = 0x5F; @@ -33,13 +32,9 @@ async fn main(_spawner: Spawner) { Default::default(), ); - // I2C bus can freeze if SCL line is shorted or due to a broken device that clock stretches for too long. - // TimeoutI2c allows recovering from such errors by throwing `Error::Timeout` after a given delay. - let mut timeout_i2c = TimeoutI2c::new(&mut i2c, Duration::from_millis(1000)); - let mut data = [0u8; 1]; - match timeout_i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) { + match i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) { Ok(()) => info!("Whoami: {}", data[0]), Err(Error::Timeout) => error!("Operation timed out"), Err(e) => error!("I2c Error: {:?}", e), diff --git a/examples/stm32h5/src/bin/usb_serial.rs b/examples/stm32h5/src/bin/usb_serial.rs index cbe540a0..3b3c38e1 100644 --- a/examples/stm32h5/src/bin/usb_serial.rs +++ b/examples/stm32h5/src/bin/usb_serial.rs @@ -4,7 +4,9 @@ use defmt::{panic, *}; use embassy_executor::Spawner; -use embassy_stm32::rcc::{AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllSource, Sysclk, VoltageScale}; +use embassy_stm32::rcc::{ + AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllDiv, PllMul, PllPreDiv, PllSource, Sysclk, VoltageScale, +}; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{Driver, Instance}; use embassy_stm32::{bind_interrupts, pac, peripherals, usb, Config}; @@ -29,9 +31,9 @@ async fn main(_spawner: Spawner) { }); config.rcc.pll1 = Some(Pll { source: PllSource::Hse, - prediv: 2, - mul: 125, - divp: Some(2), // 250mhz + prediv: PllPreDiv::DIV2, + mul: PllMul::MUL125, + divp: Some(PllDiv::DIV2), // 250mhz divq: None, divr: None, }); diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml index c1d49963..adc99024 100644 --- a/examples/stm32h7/Cargo.toml +++ b/examples/stm32h7/Cargo.toml @@ -6,12 +6,12 @@ license = "MIT OR Apache-2.0" [dependencies] # 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"] } +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-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-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "unstable-traits", "tick-hz-32_768"] } +embassy-time = { version = "0.1.4", 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"] } -embedded-io-async = { version = "0.5.0" } +embedded-io-async = { version = "0.6.0" } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } defmt = "0.3" @@ -22,7 +22,7 @@ cortex-m-rt = "0.7.0" embedded-hal = "0.2.6" embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-rc.1" } embedded-hal-async = { version = "=1.0.0-rc.1" } -embedded-nal-async = { version = "0.5.0" } +embedded-nal-async = { version = "0.6.0" } panic-probe = { version = "0.3", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.7.5", default-features = false } @@ -32,6 +32,7 @@ micromath = "2.0.0" stm32-fmc = "0.3.0" embedded-storage = "0.3.0" static_cell = { version = "1.1", features = ["nightly"]} +chrono = { version = "^0.4", default-features = false } # cargo build/run [profile.dev] diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs index 77922d4b..7859b86d 100644 --- a/examples/stm32h7/src/bin/adc.rs +++ b/examples/stm32h7/src/bin/adc.rs @@ -18,16 +18,16 @@ async fn main(_spawner: Spawner) { config.rcc.csi = true; config.rcc.pll_src = PllSource::Hsi; config.rcc.pll1 = Some(Pll { - prediv: 4, - mul: 50, - divp: Some(2), - divq: Some(8), // SPI1 cksel defaults to pll1_q + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV2), + divq: Some(PllDiv::DIV8), // SPI1 cksel defaults to pll1_q divr: None, }); config.rcc.pll2 = Some(Pll { - prediv: 4, - mul: 50, - divp: Some(8), // 100mhz + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV8), // 100mhz divq: None, divr: None, }); diff --git a/examples/stm32h7/src/bin/camera.rs b/examples/stm32h7/src/bin/camera.rs index de8ddc29..40ef16cf 100644 --- a/examples/stm32h7/src/bin/camera.rs +++ b/examples/stm32h7/src/bin/camera.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_stm32::dcmi::{self, *}; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::i2c::I2c; -use embassy_stm32::rcc::{Mco, Mco1Source}; +use embassy_stm32::rcc::{Mco, Mco1Source, McoPrescaler}; use embassy_stm32::time::khz; use embassy_stm32::{bind_interrupts, i2c, peripherals, Config}; use embassy_time::{Duration, Timer}; @@ -32,10 +32,10 @@ async fn main(_spawner: Spawner) { config.rcc.csi = true; config.rcc.pll_src = PllSource::Hsi; config.rcc.pll1 = Some(Pll { - prediv: 4, - mul: 50, - divp: Some(2), - divq: Some(8), // 100mhz + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV2), + divq: Some(PllDiv::DIV8), // 100mhz divr: None, }); config.rcc.sys = Sysclk::Pll1P; // 400 Mhz @@ -49,7 +49,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(config); defmt::info!("Hello World!"); - let mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, 3); + let mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, McoPrescaler::DIV3); let mut led = Output::new(p.PE3, Level::High, Speed::Low); let cam_i2c = I2c::new( @@ -184,7 +184,7 @@ mod ov7725 { const CAM_ADDR: u8 = 0x21; - #[derive(Format)] + #[derive(Format, PartialEq, Eq)] pub enum Error { I2c(I2cError), } diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs index 93df7a31..82122189 100644 --- a/examples/stm32h7/src/bin/dac.rs +++ b/examples/stm32h7/src/bin/dac.rs @@ -20,16 +20,16 @@ fn main() -> ! { config.rcc.csi = true; config.rcc.pll_src = PllSource::Hsi; config.rcc.pll1 = Some(Pll { - prediv: 4, - mul: 50, - divp: Some(2), - divq: Some(8), // SPI1 cksel defaults to pll1_q + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV2), + divq: Some(PllDiv::DIV8), // 100mhz divr: None, }); config.rcc.pll2 = Some(Pll { - prediv: 4, - mul: 50, - divp: Some(8), // 100mhz + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV8), // 100mhz divq: None, divr: None, }); diff --git a/examples/stm32h7/src/bin/dac_dma.rs b/examples/stm32h7/src/bin/dac_dma.rs index 8c921abc..334986a0 100644 --- a/examples/stm32h7/src/bin/dac_dma.rs +++ b/examples/stm32h7/src/bin/dac_dma.rs @@ -28,16 +28,16 @@ async fn main(spawner: Spawner) { config.rcc.csi = true; config.rcc.pll_src = PllSource::Hsi; config.rcc.pll1 = Some(Pll { - prediv: 4, - mul: 50, - divp: Some(2), - divq: Some(8), // SPI1 cksel defaults to pll1_q + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV2), + divq: Some(PllDiv::DIV8), // 100mhz divr: None, }); config.rcc.pll2 = Some(Pll { - prediv: 4, - mul: 50, - divp: Some(8), // 100mhz + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV8), // 100mhz divq: None, divr: None, }); @@ -79,7 +79,7 @@ async fn dac_task1(mut dac: Dac1Type) { dac.select_trigger(embassy_stm32::dac::Ch1Trigger::Tim6).unwrap(); dac.enable_channel().unwrap(); - TIM6::enable(); + TIM6::enable_and_reset(); TIM6::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); TIM6::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); TIM6::regs().cr1().modify(|w| { @@ -118,7 +118,7 @@ async fn dac_task2(mut dac: Dac2Type) { error!("Reload value {} below threshold!", reload); } - TIM7::enable(); + TIM7::enable_and_reset(); TIM7::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); TIM7::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); TIM7::regs().cr1().modify(|w| { diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs index 1b5d71ed..6fbf4344 100644 --- a/examples/stm32h7/src/bin/eth.rs +++ b/examples/stm32h7/src/bin/eth.rs @@ -39,9 +39,9 @@ async fn main(spawner: Spawner) -> ! { config.rcc.hsi48 = true; // needed for RNG config.rcc.pll_src = PllSource::Hsi; config.rcc.pll1 = Some(Pll { - prediv: 4, - mul: 50, - divp: Some(2), + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV2), divq: None, divr: None, }); @@ -77,9 +77,8 @@ async fn main(spawner: Spawner) -> ! { p.PG13, p.PB13, p.PG11, - GenericSMI::new(), + GenericSMI::new(0), mac_addr, - 0, ); let config = embassy_net::Config::dhcpv4(Default::default()); diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs index 3abd31c7..09d27cdb 100644 --- a/examples/stm32h7/src/bin/eth_client.rs +++ b/examples/stm32h7/src/bin/eth_client.rs @@ -40,9 +40,9 @@ async fn main(spawner: Spawner) -> ! { config.rcc.hsi48 = true; // needed for RNG config.rcc.pll_src = PllSource::Hsi; config.rcc.pll1 = Some(Pll { - prediv: 4, - mul: 50, - divp: Some(2), + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV2), divq: None, divr: None, }); @@ -78,9 +78,8 @@ async fn main(spawner: Spawner) -> ! { p.PG13, p.PB13, p.PG11, - GenericSMI::new(), + GenericSMI::new(0), mac_addr, - 0, ); let config = embassy_net::Config::dhcpv4(Default::default()); @@ -106,8 +105,8 @@ async fn main(spawner: Spawner) -> ! { info!("Network task initialized"); - static STATE: TcpClientState<1, 1024, 1024> = TcpClientState::new(); - let client = TcpClient::new(&stack, &STATE); + let state: TcpClientState<1, 1024, 1024> = TcpClientState::new(); + let client = TcpClient::new(&stack, &state); loop { let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(10, 42, 0, 1), 8000)); diff --git a/examples/stm32h7/src/bin/fmc.rs b/examples/stm32h7/src/bin/fmc.rs index de0b351d..7ae87b02 100644 --- a/examples/stm32h7/src/bin/fmc.rs +++ b/examples/stm32h7/src/bin/fmc.rs @@ -18,10 +18,10 @@ async fn main(_spawner: Spawner) { config.rcc.csi = true; config.rcc.pll_src = PllSource::Hsi; config.rcc.pll1 = Some(Pll { - prediv: 4, - mul: 50, - divp: Some(2), - divq: Some(8), // 100mhz + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV2), + divq: Some(PllDiv::DIV8), // 100mhz divr: None, }); config.rcc.sys = Sysclk::Pll1P; // 400 Mhz diff --git a/examples/stm32h7/src/bin/i2c.rs b/examples/stm32h7/src/bin/i2c.rs index c2979c59..9aa0ca08 100644 --- a/examples/stm32h7/src/bin/i2c.rs +++ b/examples/stm32h7/src/bin/i2c.rs @@ -4,10 +4,9 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::i2c::{Error, I2c, TimeoutI2c}; +use embassy_stm32::i2c::{Error, I2c}; use embassy_stm32::time::Hertz; use embassy_stm32::{bind_interrupts, i2c, peripherals}; -use embassy_time::Duration; use {defmt_rtt as _, panic_probe as _}; const ADDRESS: u8 = 0x5F; @@ -33,13 +32,9 @@ async fn main(_spawner: Spawner) { Default::default(), ); - // I2C bus can freeze if SCL line is shorted or due to a broken device that clock stretches for too long. - // TimeoutI2c allows recovering from such errors by throwing `Error::Timeout` after a given delay. - let mut timeout_i2c = TimeoutI2c::new(&mut i2c, Duration::from_millis(1000)); - let mut data = [0u8; 1]; - match timeout_i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) { + match i2c.blocking_write_read(ADDRESS, &[WHOAMI], &mut data) { Ok(()) => info!("Whoami: {}", data[0]), Err(Error::Timeout) => error!("Operation timed out"), Err(e) => error!("I2c Error: {:?}", e), diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs index a1e955c3..5841efb2 100644 --- a/examples/stm32h7/src/bin/low_level_timer_api.rs +++ b/examples/stm32h7/src/bin/low_level_timer_api.rs @@ -22,10 +22,10 @@ async fn main(_spawner: Spawner) { config.rcc.hsi48 = true; // needed for RNG config.rcc.pll_src = PllSource::Hsi; config.rcc.pll1 = Some(Pll { - prediv: 4, - mul: 50, - divp: Some(2), - divq: Some(8), // 100 Mhz + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV2), + divq: Some(PllDiv::DIV8), // 100mhz divr: None, }); config.rcc.sys = Sysclk::Pll1P; // 400 Mhz @@ -73,8 +73,7 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> { ) -> Self { into_ref!(tim, ch1, ch2, ch3, ch4); - T::enable(); - ::reset(); + T::enable_and_reset(); ch1.set_speed(Speed::VeryHigh); ch1.set_as_af(ch1.af_num(), AFType::OutputPushPull); diff --git a/examples/stm32h7/src/bin/mco.rs b/examples/stm32h7/src/bin/mco.rs index 9d6d805a..de89aee2 100644 --- a/examples/stm32h7/src/bin/mco.rs +++ b/examples/stm32h7/src/bin/mco.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::gpio::{Level, Output, Speed}; -use embassy_stm32::rcc::{Mco, Mco1Source}; +use embassy_stm32::rcc::{Mco, Mco1Source, McoPrescaler}; use embassy_time::{Duration, Timer}; 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 _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, 8); + let _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, McoPrescaler::DIV8); loop { info!("high"); diff --git a/examples/stm32h7/src/bin/pwm.rs b/examples/stm32h7/src/bin/pwm.rs index 5c8e57aa..37e4c92c 100644 --- a/examples/stm32h7/src/bin/pwm.rs +++ b/examples/stm32h7/src/bin/pwm.rs @@ -21,9 +21,9 @@ async fn main(_spawner: Spawner) { config.rcc.csi = true; config.rcc.pll_src = PllSource::Hsi; config.rcc.pll1 = Some(Pll { - prediv: 4, - mul: 50, - divp: Some(2), + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV2), divq: None, divr: None, }); diff --git a/examples/stm32h7/src/bin/rtc.rs b/examples/stm32h7/src/bin/rtc.rs new file mode 100644 index 00000000..f2a19af8 --- /dev/null +++ b/examples/stm32h7/src/bin/rtc.rs @@ -0,0 +1,37 @@ +#![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()); +} diff --git a/examples/stm32h7/src/bin/sdmmc.rs b/examples/stm32h7/src/bin/sdmmc.rs index 752aefdf..ecb8d654 100644 --- a/examples/stm32h7/src/bin/sdmmc.rs +++ b/examples/stm32h7/src/bin/sdmmc.rs @@ -22,10 +22,10 @@ async fn main(_spawner: Spawner) -> ! { config.rcc.csi = true; config.rcc.pll_src = PllSource::Hsi; config.rcc.pll1 = Some(Pll { - prediv: 4, - mul: 50, - divp: Some(2), - divq: Some(4), // default clock chosen by SDMMCSEL. 200 Mhz + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV2), + divq: Some(PllDiv::DIV4), // default clock chosen by SDMMCSEL. 200 Mhz divr: None, }); config.rcc.sys = Sysclk::Pll1P; // 400 Mhz diff --git a/examples/stm32h7/src/bin/spi.rs b/examples/stm32h7/src/bin/spi.rs index 9fe46f03..f128d4a5 100644 --- a/examples/stm32h7/src/bin/spi.rs +++ b/examples/stm32h7/src/bin/spi.rs @@ -44,10 +44,10 @@ fn main() -> ! { config.rcc.csi = true; config.rcc.pll_src = PllSource::Hsi; config.rcc.pll1 = Some(Pll { - prediv: 4, - mul: 50, - divp: Some(2), - divq: Some(4), // used by SPI3. 100Mhz. + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV2), + divq: Some(PllDiv::DIV8), // used by SPI3. 100Mhz. divr: None, }); config.rcc.sys = Sysclk::Pll1P; // 400 Mhz diff --git a/examples/stm32h7/src/bin/spi_dma.rs b/examples/stm32h7/src/bin/spi_dma.rs index 88d65d5b..d4c0bcdb 100644 --- a/examples/stm32h7/src/bin/spi_dma.rs +++ b/examples/stm32h7/src/bin/spi_dma.rs @@ -40,10 +40,10 @@ fn main() -> ! { config.rcc.csi = true; config.rcc.pll_src = PllSource::Hsi; config.rcc.pll1 = Some(Pll { - prediv: 4, - mul: 50, - divp: Some(2), - divq: Some(4), // used by SPI3. 100Mhz. + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV2), + divq: Some(PllDiv::DIV8), // used by SPI3. 100Mhz. divr: None, }); config.rcc.sys = Sysclk::Pll1P; // 400 Mhz diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs index 14de4356..c1e5144b 100644 --- a/examples/stm32h7/src/bin/usb_serial.rs +++ b/examples/stm32h7/src/bin/usb_serial.rs @@ -28,9 +28,9 @@ async fn main(_spawner: Spawner) { config.rcc.hsi48 = true; // needed for USB config.rcc.pll_src = PllSource::Hsi; config.rcc.pll1 = Some(Pll { - prediv: 4, - mul: 50, - divp: Some(2), + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV2), divq: None, divr: None, }); diff --git a/examples/stm32l0/Cargo.toml b/examples/stm32l0/Cargo.toml index 502ebfc8..f70ecc06 100644 --- a/examples/stm32l0/Cargo.toml +++ b/examples/stm32l0/Cargo.toml @@ -14,7 +14,7 @@ nightly = ["embassy-stm32/nightly", "embassy-time/nightly", "embassy-time/unstab embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32l072cz", "time-driver-any", "exti", "unstable-traits", "memory-x"] } embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["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.4", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["time", "defmt"], optional = true } lora-phy = { version = "2", optional = true } lorawan-device = { version = "0.11.0", default-features = false, features = ["async", "external-lora-phy"], optional = true } @@ -24,8 +24,8 @@ defmt = "0.3" defmt-rtt = "0.4" embedded-storage = "0.3.0" -embedded-io = { version = "0.5.0" } -embedded-io-async = { version = "0.5.0", optional = true } +embedded-io = { version = "0.6.0" } +embedded-io-async = { version = "0.6.0", optional = true } cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" diff --git a/examples/stm32l1/Cargo.toml b/examples/stm32l1/Cargo.toml index a75275a0..472e1b7a 100644 --- a/examples/stm32l1/Cargo.toml +++ b/examples/stm32l1/Cargo.toml @@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0" [dependencies] 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-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.4", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32l151cb-a", "time-driver-any", "memory-x"] } defmt = "0.3" diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 59e89c53..5456efe8 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -9,14 +9,14 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l4s5qi", "memory-x", "time-driver-any", "exti", "unstable-traits", "chrono"] } 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-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", "unstable-traits", "nightly"] } +embassy-time = { version = "0.1.4", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768", "unstable-traits", "nightly"] } embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net-adin1110 = { version = "0.2.0", path = "../../embassy-net-adin1110" } embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "udp", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } -embedded-io-async = { version = "0.5.0", features = ["defmt-03"] } -embedded-io = { version = "0.5.0", features = ["defmt-03"] } +embedded-io-async = { version = "0.6.0", features = ["defmt-03"] } +embedded-io = { version = "0.6.0", features = ["defmt-03"] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs index c27cc03e..98f37f90 100644 --- a/examples/stm32l4/src/bin/dac_dma.rs +++ b/examples/stm32l4/src/bin/dac_dma.rs @@ -51,7 +51,7 @@ async fn dac_task1(mut dac: Dac1Type) { dac.select_trigger(embassy_stm32::dac::Ch1Trigger::Tim6).unwrap(); dac.enable_channel().unwrap(); - TIM6::enable(); + TIM6::enable_and_reset(); TIM6::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); TIM6::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); TIM6::regs().cr1().modify(|w| { @@ -90,7 +90,7 @@ async fn dac_task2(mut dac: Dac2Type) { error!("Reload value {} below threshold!", reload); } - TIM7::enable(); + TIM7::enable_and_reset(); TIM7::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); TIM7::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); TIM7::regs().cr1().modify(|w| { diff --git a/examples/stm32l4/src/bin/mco.rs b/examples/stm32l4/src/bin/mco.rs index dea0c66e..8d35af78 100644 --- a/examples/stm32l4/src/bin/mco.rs +++ b/examples/stm32l4/src/bin/mco.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::gpio::{Level, Output, Speed}; -use embassy_stm32::rcc::{Mco, Mco1Source, McoClock}; +use embassy_stm32::rcc::{Mco, McoPrescaler, McoSource}; use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let _mco = Mco::new(p.MCO, p.PA8, Mco1Source::Hsi16, McoClock::DIV1); + let _mco = Mco::new(p.MCO, p.PA8, McoSource::HSI16, McoPrescaler::DIV1); let mut led = Output::new(p.PB14, Level::High, Speed::Low); diff --git a/examples/stm32l4/src/bin/rng.rs b/examples/stm32l4/src/bin/rng.rs index 806e49f5..d0208d8a 100644 --- a/examples/stm32l4/src/bin/rng.rs +++ b/examples/stm32l4/src/bin/rng.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::rcc::{ClockSrc, PLLClkDiv, PLLMul, PLLSource, PLLSrcDiv}; +use embassy_stm32::rcc::{ClockSrc, PLLSource, PllMul, PllPreDiv, PllQDiv, PllRDiv}; use embassy_stm32::rng::Rng; use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; use {defmt_rtt as _, panic_probe as _}; @@ -19,10 +19,10 @@ async fn main(_spawner: Spawner) { // 72Mhz clock (16 / 1 * 18 / 4) config.rcc.mux = ClockSrc::PLL( PLLSource::HSI16, - PLLClkDiv::Div4, - PLLSrcDiv::Div1, - PLLMul::Mul18, - Some(PLLClkDiv::Div6), // 48Mhz (16 / 1 * 18 / 6) + PllRDiv::DIV4, + PllPreDiv::DIV1, + PllMul::MUL18, + Some(PllQDiv::DIV6), // 48Mhz (16 / 1 * 18 / 6) ); let p = embassy_stm32::init(config); diff --git a/examples/stm32l4/src/bin/rtc.rs b/examples/stm32l4/src/bin/rtc.rs index eb1eed01..33efc76b 100644 --- a/examples/stm32l4/src/bin/rtc.rs +++ b/examples/stm32l4/src/bin/rtc.rs @@ -5,7 +5,7 @@ use chrono::{NaiveDate, NaiveDateTime}; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::rcc::{self, ClockSrc, PLLClkDiv, PLLMul, PLLSource, PLLSrcDiv}; +use embassy_stm32::rcc::{ClockSrc, LsConfig, PLLSource, PllMul, PllPreDiv, PllRDiv}; use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_stm32::time::Hertz; use embassy_stm32::Config; @@ -18,13 +18,12 @@ async fn main(_spawner: Spawner) { let mut config = Config::default(); config.rcc.mux = ClockSrc::PLL( PLLSource::HSE(Hertz::mhz(8)), - PLLClkDiv::Div2, - PLLSrcDiv::Div1, - PLLMul::Mul20, + PllRDiv::DIV2, + PllPreDiv::DIV1, + PllMul::MUL20, None, ); - config.rcc.lse = Some(Hertz(32_768)); - config.rcc.rtc_mux = rcc::RtcClockSource::LSE; + config.rcc.ls = LsConfig::default_lse(); embassy_stm32::init(config) }; info!("Hello World!"); diff --git a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs index 28752158..7193d1f1 100644 --- a/examples/stm32l4/src/bin/spe_adin1110_http_server.rs +++ b/examples/stm32l4/src/bin/spe_adin1110_http_server.rs @@ -32,7 +32,6 @@ use embedded_io::Write as bWrite; use embedded_io_async::Write; use hal::gpio::{Input, Level, Output, Speed}; use hal::i2c::{self, I2c}; -use hal::rcc::{self}; use hal::rng::{self, Rng}; use hal::{bind_interrupts, exti, pac, peripherals}; use heapless::Vec; @@ -49,7 +48,7 @@ use embassy_net_adin1110::{self, Device, Runner, ADIN1110}; use embedded_hal_bus::spi::ExclusiveDevice; use hal::gpio::Pull; use hal::i2c::Config as I2C_Config; -use hal::rcc::{ClockSrc, PLLClkDiv, PLLMul, PLLSource, PLLSrcDiv}; +use hal::rcc::{ClockSrc, PLLSource, PllMul, PllPreDiv, PllRDiv}; use hal::spi::{Config as SPI_Config, Spi}; use hal::time::Hertz; @@ -80,13 +79,12 @@ async fn main(spawner: Spawner) { // 80MHz highest frequency for flash 0 wait. config.rcc.mux = ClockSrc::PLL( PLLSource::HSE(Hertz(8_000_000)), - PLLClkDiv::Div2, - PLLSrcDiv::Div1, - PLLMul::Mul20, + PllRDiv::DIV2, + PllPreDiv::DIV1, + PllMul::MUL20, None, ); config.rcc.hsi48 = true; // needed for rng - config.rcc.rtc_mux = rcc::RtcClockSource::LSI; let dp = embassy_stm32::init(config); @@ -366,7 +364,7 @@ pub struct ADT7422<'d, BUS: I2cBus> { bus: BUS, } -#[derive(Debug, Format)] +#[derive(Debug, Format, PartialEq, Eq)] pub enum Error { I2c(I2cError), Address, diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs index 410d6891..dc0d98ad 100644 --- a/examples/stm32l4/src/bin/usb_serial.rs +++ b/examples/stm32l4/src/bin/usb_serial.rs @@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let mut config = Config::default(); - config.rcc.mux = ClockSrc::PLL(PLLSource::HSI16, PLLClkDiv::Div2, PLLSrcDiv::Div1, PLLMul::Mul10, None); + config.rcc.mux = ClockSrc::PLL(PLLSource::HSI16, PllRDiv::DIV2, PllPreDiv::DIV1, PllMul::MUL10, None); config.rcc.hsi48 = true; let p = embassy_stm32::init(config); diff --git a/examples/stm32l5/Cargo.toml b/examples/stm32l5/Cargo.toml index 583e1a77..cf8601da 100644 --- a/examples/stm32l5/Cargo.toml +++ b/examples/stm32l5/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32l552ze", "time-driver-any", "exti", "unstable-traits", "memory-x"] } 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-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.4", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "dhcpv4", "medium-ethernet"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } @@ -25,7 +25,7 @@ embedded-hal = "0.2.6" futures = { version = "0.3.17", default-features = false, features = ["async-await"] } heapless = { version = "0.7.5", default-features = false } rand_core = { version = "0.6.3", default-features = false } -embedded-io-async = { version = "0.5.0" } +embedded-io-async = { version = "0.6.0" } static_cell = { version = "1.1", features = ["nightly"]} [profile.release] diff --git a/examples/stm32l5/src/bin/rng.rs b/examples/stm32l5/src/bin/rng.rs index 9549d64d..cc3c99b5 100644 --- a/examples/stm32l5/src/bin/rng.rs +++ b/examples/stm32l5/src/bin/rng.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::rcc::{ClockSrc, PLLClkDiv, PLLMul, PLLSource, PLLSrcDiv}; +use embassy_stm32::rcc::{ClockSrc, PLLSource, PllMul, PllPreDiv, PllQDiv, PllRDiv}; use embassy_stm32::rng::Rng; use embassy_stm32::{bind_interrupts, peripherals, rng, Config}; use {defmt_rtt as _, panic_probe as _}; @@ -18,10 +18,10 @@ async fn main(_spawner: Spawner) { let mut config = Config::default(); config.rcc.mux = ClockSrc::PLL( PLLSource::HSI16, - PLLClkDiv::Div2, - PLLSrcDiv::Div1, - PLLMul::Mul8, - Some(PLLClkDiv::Div2), + PllRDiv::DIV2, + PllPreDiv::DIV1, + PllMul::MUL8, + Some(PllQDiv::DIV2), ); let p = embassy_stm32::init(config); diff --git a/examples/stm32l5/src/bin/usb_ethernet.rs b/examples/stm32l5/src/bin/usb_ethernet.rs index 15b84761..498147f9 100644 --- a/examples/stm32l5/src/bin/usb_ethernet.rs +++ b/examples/stm32l5/src/bin/usb_ethernet.rs @@ -45,7 +45,7 @@ async fn net_task(stack: &'static Stack>) -> ! { #[embassy_executor::main] async fn main(spawner: Spawner) { let mut config = Config::default(); - config.rcc.mux = ClockSrc::PLL(PLLSource::HSI16, PLLClkDiv::Div2, PLLSrcDiv::Div1, PLLMul::Mul10, None); + config.rcc.mux = ClockSrc::PLL(PLLSource::HSI16, PllRDiv::DIV2, PllPreDiv::DIV1, PllMul::MUL10, None); config.rcc.hsi48 = true; let p = embassy_stm32::init(config); diff --git a/examples/stm32l5/src/bin/usb_hid_mouse.rs b/examples/stm32l5/src/bin/usb_hid_mouse.rs index 7e894e40..db6a9c76 100644 --- a/examples/stm32l5/src/bin/usb_hid_mouse.rs +++ b/examples/stm32l5/src/bin/usb_hid_mouse.rs @@ -22,7 +22,7 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - config.rcc.mux = ClockSrc::PLL(PLLSource::HSI16, PLLClkDiv::Div2, PLLSrcDiv::Div1, PLLMul::Mul10, None); + config.rcc.mux = ClockSrc::PLL(PLLSource::HSI16, PllRDiv::DIV2, PllPreDiv::DIV1, PllMul::MUL10, None); config.rcc.hsi48 = true; let p = embassy_stm32::init(config); diff --git a/examples/stm32l5/src/bin/usb_serial.rs b/examples/stm32l5/src/bin/usb_serial.rs index 0c719560..e19ecbf0 100644 --- a/examples/stm32l5/src/bin/usb_serial.rs +++ b/examples/stm32l5/src/bin/usb_serial.rs @@ -20,7 +20,7 @@ bind_interrupts!(struct Irqs { #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = Config::default(); - config.rcc.mux = ClockSrc::PLL(PLLSource::HSI16, PLLClkDiv::Div2, PLLSrcDiv::Div1, PLLMul::Mul10, None); + config.rcc.mux = ClockSrc::PLL(PLLSource::HSI16, PllRDiv::DIV2, PllPreDiv::DIV1, PllMul::MUL10, None); config.rcc.hsi48 = true; let p = embassy_stm32::init(config); diff --git a/examples/stm32u5/Cargo.toml b/examples/stm32u5/Cargo.toml index e361856c..9c139c2e 100644 --- a/examples/stm32u5/Cargo.toml +++ b/examples/stm32u5/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "stm32u585ai", "time-driver-any", "memory-x" ] } 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-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.4", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } defmt = "0.3" diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs index 9e47fb18..9b2adb0a 100644 --- a/examples/stm32u5/src/bin/usb_serial.rs +++ b/examples/stm32u5/src/bin/usb_serial.rs @@ -23,7 +23,12 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let mut config = Config::default(); - config.rcc.mux = ClockSrc::PLL1R(PllSrc::HSI16, PllM::Div2, PllN::Mul10, PllClkDiv::NotDivided); + config.rcc.mux = ClockSrc::PLL1R(PllConfig { + source: PllSrc::HSI16, + m: Pllm::DIV2, + n: Plln::MUL10, + r: Plldiv::DIV1, + }); //config.rcc.mux = ClockSrc::MSI(MSIRange::Range48mhz); config.rcc.hsi48 = true; diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 320678dd..e0711ad0 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -10,7 +10,7 @@ embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [" embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", features = ["defmt", "stm32wb55rg"] } 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-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.4", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", "nightly"], optional=true } defmt = "0.3" diff --git a/examples/stm32wba/Cargo.toml b/examples/stm32wba/Cargo.toml index 26fcce26..7effc09a 100644 --- a/examples/stm32wba/Cargo.toml +++ b/examples/stm32wba/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32wba52cg", "time-driver-any", "memory-x", "exti"] } 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-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.4", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "udp", "proto-ipv6", "medium-ieee802154", "nightly"], optional=true } defmt = "0.3" diff --git a/examples/stm32wl/Cargo.toml b/examples/stm32wl/Cargo.toml index f47a9a90..c106d62b 100644 --- a/examples/stm32wl/Cargo.toml +++ b/examples/stm32wl/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT OR Apache-2.0" embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "unstable-traits", "defmt", "stm32wl55jc-cm4", "time-driver-any", "memory-x", "unstable-pac", "exti", "chrono"] } 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-time = { version = "0.1.3", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-time = { version = "0.1.4", path = "../../embassy-time", features = ["nightly", "unstable-traits", "defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } embassy-embedded-hal = { version = "0.1.0", path = "../../embassy-embedded-hal" } embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["stm32wl", "time", "defmt"] } lora-phy = { version = "2" } diff --git a/examples/stm32wl/src/bin/lora_lorawan.rs b/examples/stm32wl/src/bin/lora_lorawan.rs index fb249532..8c789afb 100644 --- a/examples/stm32wl/src/bin/lora_lorawan.rs +++ b/examples/stm32wl/src/bin/lora_lorawan.rs @@ -33,8 +33,7 @@ bind_interrupts!(struct Irqs{ #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = embassy_stm32::Config::default(); - config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE32; - config.rcc.rtc_mux = embassy_stm32::rcc::RtcClockSource::LSI; + config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE; let p = embassy_stm32::init(config); pac::RCC.ccipr().modify(|w| w.set_rngsel(0b01)); diff --git a/examples/stm32wl/src/bin/lora_p2p_receive.rs b/examples/stm32wl/src/bin/lora_p2p_receive.rs index 3d8c31ff..19b0d853 100644 --- a/examples/stm32wl/src/bin/lora_p2p_receive.rs +++ b/examples/stm32wl/src/bin/lora_p2p_receive.rs @@ -26,7 +26,7 @@ bind_interrupts!(struct Irqs{ #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = embassy_stm32::Config::default(); - config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE32; + config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE; let p = embassy_stm32::init(config); let spi = Spi::new_subghz(p.SUBGHZSPI, p.DMA1_CH1, p.DMA1_CH2); diff --git a/examples/stm32wl/src/bin/lora_p2p_send.rs b/examples/stm32wl/src/bin/lora_p2p_send.rs index fbd0b032..85f6a84b 100644 --- a/examples/stm32wl/src/bin/lora_p2p_send.rs +++ b/examples/stm32wl/src/bin/lora_p2p_send.rs @@ -26,7 +26,7 @@ bind_interrupts!(struct Irqs{ #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = embassy_stm32::Config::default(); - config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE32; + config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE; let p = embassy_stm32::init(config); let spi = Spi::new_subghz(p.SUBGHZSPI, p.DMA1_CH1, p.DMA1_CH2); diff --git a/examples/stm32wl/src/bin/random.rs b/examples/stm32wl/src/bin/random.rs index 18eeac4f..7c7e8a4e 100644 --- a/examples/stm32wl/src/bin/random.rs +++ b/examples/stm32wl/src/bin/random.rs @@ -15,8 +15,7 @@ bind_interrupts!(struct Irqs{ #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = embassy_stm32::Config::default(); - config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE32; - config.rcc.rtc_mux = embassy_stm32::rcc::RtcClockSource::LSI; + config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE; let p = embassy_stm32::init(config); pac::RCC.ccipr().modify(|w| { diff --git a/examples/stm32wl/src/bin/rtc.rs b/examples/stm32wl/src/bin/rtc.rs index 11734e4b..a6bb2801 100644 --- a/examples/stm32wl/src/bin/rtc.rs +++ b/examples/stm32wl/src/bin/rtc.rs @@ -5,9 +5,8 @@ use chrono::{NaiveDate, NaiveDateTime}; use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::rcc::ClockSrc; -use embassy_stm32::rtc::{Rtc, RtcClockSource, RtcConfig}; -use embassy_stm32::time::Hertz; +use embassy_stm32::rcc::{ClockSrc, LsConfig}; +use embassy_stm32::rtc::{Rtc, RtcConfig}; use embassy_stm32::Config; use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -16,9 +15,8 @@ use {defmt_rtt as _, panic_probe as _}; async fn main(_spawner: Spawner) { let p = { let mut config = Config::default(); - config.rcc.mux = ClockSrc::HSE32; - config.rcc.lse = Some(Hertz(32_768)); - config.rcc.rtc_mux = RtcClockSource::LSE; + config.rcc.mux = ClockSrc::HSE; + config.rcc.ls = LsConfig::default_lse(); embassy_stm32::init(config) }; info!("Hello World!"); diff --git a/examples/stm32wl/src/bin/uart_async.rs b/examples/stm32wl/src/bin/uart_async.rs index 2c9b7c69..44e8f83a 100644 --- a/examples/stm32wl/src/bin/uart_async.rs +++ b/examples/stm32wl/src/bin/uart_async.rs @@ -21,7 +21,7 @@ but can be surely changed for your needs. #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = embassy_stm32::Config::default(); - config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE32; + config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSE; let p = embassy_stm32::init(config); defmt::info!("Starting system"); diff --git a/examples/wasm/Cargo.toml b/examples/wasm/Cargo.toml index 12b2e2bd..9136c81c 100644 --- a/examples/wasm/Cargo.toml +++ b/examples/wasm/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["cdylib"] [dependencies] embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["log"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-wasm", "executor-thread", "log", "nightly", "integrated-timers"] } -embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["log", "wasm", "nightly"] } +embassy-time = { version = "0.1.4", path = "../../embassy-time", features = ["log", "wasm", "nightly"] } wasm-logger = "0.2.0" wasm-bindgen = "0.2" diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 7b34afa2..755a9207 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,8 +1,8 @@ # Before upgrading check that everything is available on all tier1 targets here: # https://rust-lang.github.io/rustup-components-history [toolchain] -channel = "nightly-2023-08-19" -components = [ "rust-src", "rustfmt", "llvm-tools-preview" ] +channel = "nightly-2023-10-02" +components = [ "rust-src", "rustfmt", "llvm-tools" ] targets = [ "thumbv7em-none-eabi", "thumbv7m-none-eabi", diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 08fe1a4b..32f296a1 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -10,9 +10,9 @@ teleprobe-meta = "1" embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-sync = { version = "0.3.0", path = "../../embassy-sync", features = ["defmt", "nightly"] } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "nightly", "integrated-timers"] } -embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "nightly", "unstable-traits", "defmt-timestamp-uptime"] } +embassy-time = { version = "0.1.4", path = "../../embassy-time", features = ["defmt", "nightly", "unstable-traits", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nightly", "unstable-traits", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } -embedded-io-async = { version = "0.5.0" } +embedded-io-async = { version = "0.6.0" } embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"] } embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } embassy-net-enc28j60 = { version = "0.1.0", path = "../../embassy-net-enc28j60", features = ["defmt"] } diff --git a/tests/perf-client/Cargo.toml b/tests/perf-client/Cargo.toml index 3284664d..daa8edfb 100644 --- a/tests/perf-client/Cargo.toml +++ b/tests/perf-client/Cargo.toml @@ -7,6 +7,6 @@ edition = "2021" [dependencies] embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4"] } -embassy-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "nightly", "unstable-traits"] } +embassy-time = { version = "0.1.4", path = "../../embassy-time", features = ["defmt", "nightly", "unstable-traits"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } defmt = "0.3.0" diff --git a/tests/perf-client/src/lib.rs b/tests/perf-client/src/lib.rs index a36147db..d709c7bd 100644 --- a/tests/perf-client/src/lib.rs +++ b/tests/perf-client/src/lib.rs @@ -30,6 +30,7 @@ pub async fn run(stack: &Stack, expected: Expected) { } const TEST_DURATION: usize = 10; +const IO_BUFFER_SIZE: usize = 1024; const RX_BUFFER_SIZE: usize = 4096; const TX_BUFFER_SIZE: usize = 4096; const SERVER_ADDRESS: Ipv4Address = Ipv4Address::new(192, 168, 2, 2); @@ -52,7 +53,7 @@ async fn test_download(stack: &Stack) -> usize { } info!("connected, testing..."); - let mut rx_buf = [0; 4096]; + let mut rx_buf = [0; IO_BUFFER_SIZE]; let mut total: usize = 0; with_timeout(Duration::from_secs(TEST_DURATION as _), async { loop { @@ -92,7 +93,7 @@ async fn test_upload(stack: &Stack) -> usize { } info!("connected, testing..."); - let buf = [0; 4096]; + let buf = [0; IO_BUFFER_SIZE]; let mut total: usize = 0; with_timeout(Duration::from_secs(TEST_DURATION as _), async { loop { @@ -134,8 +135,8 @@ async fn test_upload_download(stack: &Stack) -> usize { let (mut reader, mut writer) = socket.split(); - let tx_buf = [0; 4096]; - let mut rx_buf = [0; 4096]; + let tx_buf = [0; IO_BUFFER_SIZE]; + let mut rx_buf = [0; IO_BUFFER_SIZE]; let mut total: usize = 0; let tx_fut = async { loop { diff --git a/tests/riscv32/Cargo.toml b/tests/riscv32/Cargo.toml index 490f037b..ddd83ec2 100644 --- a/tests/riscv32/Cargo.toml +++ b/tests/riscv32/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" critical-section = { version = "1.1.1", features = ["restore-state-bool"] } embassy-sync = { version = "0.3.0", path = "../../embassy-sync" } embassy-executor = { version = "0.3.0", path = "../../embassy-executor", features = ["arch-riscv32", "nightly", "executor-thread"] } -embassy-time = { version = "0.1.3", path = "../../embassy-time" } +embassy-time = { version = "0.1.4", path = "../../embassy-time" } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } riscv-rt = "0.11" diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml index 8bb0de6c..a1e4c085 100644 --- a/tests/rp/Cargo.toml +++ b/tests/rp/Cargo.toml @@ -9,7 +9,7 @@ teleprobe-meta = "1.1" 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-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "nightly", "unstable-traits"] } +embassy-time = { version = "0.1.4", path = "../../embassy-time", features = ["defmt", "nightly", "unstable-traits"] } embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "udp", "dhcpv4", "medium-ethernet"] } @@ -29,7 +29,7 @@ embedded-hal-async = { version = "=1.0.0-rc.1" } embedded-hal-bus = { version = "=0.1.0-rc.1", features = ["async"] } panic-probe = { version = "0.3.0", features = ["print-defmt"] } futures = { version = "0.3.17", default-features = false, features = ["async-await"] } -embedded-io-async = { version = "0.5.0" } +embedded-io-async = { version = "0.6.0" } embedded-storage = { version = "0.3" } static_cell = { version = "1.1", features = ["nightly"]} pio = "0.2" diff --git a/tests/rp/src/bin/bootsel.rs b/tests/rp/src/bin/bootsel.rs new file mode 100644 index 00000000..df1ed8d2 --- /dev/null +++ b/tests/rp/src/bin/bootsel.rs @@ -0,0 +1,26 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] +teleprobe_meta::target!(b"rpi-pico"); + +use defmt::{assert_eq, *}; +use embassy_executor::Spawner; +use embassy_time::{Duration, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let mut p = embassy_rp::init(Default::default()); + info!("Hello World!"); + + // add some delay to give an attached debug probe time to parse the + // defmt RTT header. Reading that header might touch flash memory, which + // interferes with flash write operations. + // https://github.com/knurling-rs/defmt/pull/683 + Timer::after(Duration::from_millis(10)).await; + + assert_eq!(p.BOOTSEL.is_pressed(), false); + + info!("Test OK"); + cortex_m::asm::bkpt(); +} diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index bfe5bc82..fd18cd77 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -7,20 +7,25 @@ autobins = false [features] stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"] # Blue Pill -stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "stop", "can", "not-gpdma", "dac-adc-pin"] # Nucleo "sdmmc" +stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac-adc-pin"] # Nucleo "sdmmc" stm32g071rb = ["embassy-stm32/stm32g071rb", "not-gpdma", "dac-adc-pin"] # Nucleo stm32c031c6 = ["embassy-stm32/stm32c031c6", "not-gpdma"] # Nucleo -stm32g491re = ["embassy-stm32/stm32g491re", "not-gpdma"] # Nucleo -stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "not-gpdma", "dac-adc-pin"] # Nucleo -stm32wb55rg = ["embassy-stm32/stm32wb55rg", "not-gpdma", "ble", "mac" ] # Nucleo -stm32h563zi = ["embassy-stm32/stm32h563zi"] # Nucleo -stm32u585ai = ["embassy-stm32/stm32u585ai"] # IoT board +stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "not-gpdma"] # Nucleo +stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac-adc-pin"] # Nucleo +stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" ] # Nucleo +stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth"] # Nucleo +stm32u585ai = ["embassy-stm32/stm32u585ai", "chrono"] # IoT board stm32l073rz = ["embassy-stm32/stm32l073rz", "not-gpdma"] # Nucleo -stm32l152re = ["embassy-stm32/stm32l152re", "not-gpdma"] # Nucleo -stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "not-gpdma"] # Nucleo -stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "not-gpdma"] # Nucleo +stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"] # Nucleo +stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma"] # Nucleo +stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma"] # Nucleo stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma"] # Nucleo +stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth"] # Nucleo +stm32f207zg = ["embassy-stm32/stm32f207zg", "chrono", "not-gpdma", "eth"] # Nucleo +stm32f303ze = ["embassy-stm32/stm32f303ze", "chrono", "not-gpdma"] # Nucleo +stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma"] # Nucleo +eth = [] sdmmc = [] stop = ["embassy-stm32/low-power"] chrono = ["embassy-stm32/chrono", "dep:chrono"] @@ -36,10 +41,12 @@ teleprobe-meta = "1" 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-time = { version = "0.1.3", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768", "defmt-timestamp-uptime"] } +embassy-time = { version = "0.1.4", path = "../../embassy-time", features = ["defmt", "tick-hz-131_072", "defmt-timestamp-uptime"] } embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "unstable-pac", "memory-x", "time-driver-any"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-stm32-wpan = { version = "0.1.0", path = "../../embassy-stm32-wpan", optional = true, features = ["defmt", "stm32wb55rg", "ble"] } +embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "nightly", "tcp", "udp", "dhcpv4", "medium-ethernet"] } +perf-client = { path = "../perf-client" } defmt = "0.3.0" defmt-rtt = "0.4" @@ -69,6 +76,11 @@ name = "dac" path = "src/bin/dac.rs" required-features = [ "dac-adc-pin",] +[[bin]] +name = "eth" +path = "src/bin/eth.rs" +required-features = [ "eth",] + [[bin]] name = "gpio" path = "src/bin/gpio.rs" diff --git a/tests/stm32/src/bin/dac.rs b/tests/stm32/src/bin/dac.rs index 67a7d5b5..fb7a84b1 100644 --- a/tests/stm32/src/bin/dac.rs +++ b/tests/stm32/src/bin/dac.rs @@ -54,7 +54,7 @@ async fn main(_spawner: Spawner) { // Calibrate and normalize the measurement to get close to the dac_output_val let measured_normalized = ((measured as i32 - offset as i32) / normalization_factor) as i16; - info!("value / measured: {} / {}", dac_output_val, measured_normalized); + //info!("value / measured: {} / {}", dac_output_val, measured_normalized); // The deviations are quite enormous but that does not matter since this is only a quick test assert!((dac_output_val as i16 - measured_normalized).abs() < 15); diff --git a/tests/stm32/src/bin/eth.rs b/tests/stm32/src/bin/eth.rs new file mode 100644 index 00000000..6d5e05cd --- /dev/null +++ b/tests/stm32/src/bin/eth.rs @@ -0,0 +1,122 @@ +// required-features: eth +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../common.rs"] +mod common; +use common::*; +use embassy_executor::Spawner; +use embassy_net::{Stack, StackResources}; +use embassy_stm32::eth::generic_smi::GenericSMI; +use embassy_stm32::eth::{Ethernet, PacketQueue}; +use embassy_stm32::peripherals::ETH; +use embassy_stm32::rng::Rng; +use embassy_stm32::{bind_interrupts, eth, peripherals, rng}; +use rand_core::RngCore; +use static_cell::make_static; +use {defmt_rtt as _, panic_probe as _}; + +teleprobe_meta::timeout!(120); + +#[cfg(not(any(feature = "stm32h563zi", feature = "stm32f767zi", feature = "stm32f207zg")))] +bind_interrupts!(struct Irqs { + ETH => eth::InterruptHandler; + HASH_RNG => rng::InterruptHandler; +}); +#[cfg(any(feature = "stm32h563zi", feature = "stm32f767zi", feature = "stm32f207zg"))] +bind_interrupts!(struct Irqs { + ETH => eth::InterruptHandler; + RNG => rng::InterruptHandler; +}); + +type Device = Ethernet<'static, ETH, GenericSMI>; + +#[embassy_executor::task] +async fn net_task(stack: &'static Stack) -> ! { + stack.run().await +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_stm32::init(config()); + info!("Hello World!"); + + // Generate random seed. + let mut rng = Rng::new(p.RNG, Irqs); + let mut seed = [0; 8]; + rng.fill_bytes(&mut seed); + let seed = u64::from_le_bytes(seed); + + // Ensure different boards get different MAC + // so running tests concurrently doesn't break (they're all in the same LAN) + #[cfg(feature = "stm32f429zi")] + let n = 1; + #[cfg(feature = "stm32h755zi")] + let n = 2; + #[cfg(feature = "stm32h563zi")] + let n = 3; + #[cfg(feature = "stm32f767zi")] + let n = 4; + #[cfg(feature = "stm32f207zg")] + let n = 5; + + let mac_addr = [0x00, n, 0xDE, 0xAD, 0xBE, 0xEF]; + + // F2 runs out of RAM + #[cfg(feature = "stm32f207zg")] + const PACKET_QUEUE_SIZE: usize = 2; + #[cfg(not(feature = "stm32f207zg"))] + const PACKET_QUEUE_SIZE: usize = 4; + + let device = Ethernet::new( + make_static!(PacketQueue::::new()), + p.ETH, + Irqs, + p.PA1, + p.PA2, + p.PC1, + p.PA7, + p.PC4, + p.PC5, + p.PG13, + #[cfg(not(feature = "stm32h563zi"))] + p.PB13, + #[cfg(feature = "stm32h563zi")] + p.PB15, + p.PG11, + GenericSMI::new(0), + mac_addr, + ); + + let config = embassy_net::Config::dhcpv4(Default::default()); + //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { + // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), + // dns_servers: Vec::new(), + // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), + //}); + + // Init network stack + let stack = &*make_static!(Stack::new( + device, + config, + make_static!(StackResources::<2>::new()), + seed + )); + + // Launch network task + unwrap!(spawner.spawn(net_task(&stack))); + + perf_client::run( + stack, + perf_client::Expected { + down_kbps: 1000, + up_kbps: 1000, + updown_kbps: 1000, + }, + ) + .await; + + info!("Test OK"); + cortex_m::asm::bkpt(); +} diff --git a/tests/stm32/src/bin/rtc.rs b/tests/stm32/src/bin/rtc.rs index 22be6fac..46fdbfae 100644 --- a/tests/stm32/src/bin/rtc.rs +++ b/tests/stm32/src/bin/rtc.rs @@ -10,17 +10,14 @@ use chrono::{NaiveDate, NaiveDateTime}; use common::*; use defmt::assert; use embassy_executor::Spawner; -use embassy_stm32::rcc::RtcClockSource; +use embassy_stm32::rcc::LsConfig; use embassy_stm32::rtc::{Rtc, RtcConfig}; -use embassy_stm32::time::Hertz; use embassy_time::{Duration, Timer}; #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut config = config(); - - config.rcc.lse = Some(Hertz(32_768)); - config.rcc.rtc = Some(RtcClockSource::LSE); + config.rcc.ls = LsConfig::default_lse(); let p = embassy_stm32::init(config); info!("Hello World!"); @@ -40,7 +37,7 @@ async fn main(_spawner: Spawner) { let then: NaiveDateTime = rtc.now().unwrap().into(); let seconds = (then - now).num_seconds(); - defmt::info!("measured = {}", seconds); + info!("measured = {}", seconds); assert!(seconds > 3 && seconds < 7); diff --git a/tests/stm32/src/bin/stop.rs b/tests/stm32/src/bin/stop.rs index 48d59b79..929869bc 100644 --- a/tests/stm32/src/bin/stop.rs +++ b/tests/stm32/src/bin/stop.rs @@ -11,9 +11,9 @@ use common::*; use cortex_m_rt::entry; use embassy_executor::Spawner; use embassy_stm32::low_power::{stop_with_rtc, Executor}; -use embassy_stm32::rcc::RtcClockSource; +use embassy_stm32::rcc::LsConfig; use embassy_stm32::rtc::{Rtc, RtcConfig}; -use embassy_stm32::time::Hertz; +use embassy_stm32::Config; use embassy_time::{Duration, Timer}; use static_cell::make_static; @@ -45,10 +45,10 @@ async fn task_2() { #[embassy_executor::task] async fn async_main(spawner: Spawner) { - let mut config = config(); + let _ = config(); - config.rcc.lse = Some(Hertz(32_768)); - config.rcc.rtc = Some(RtcClockSource::LSE); + let mut config = Config::default(); + config.rcc.ls = LsConfig::default_lse(); let p = embassy_stm32::init(config); info!("Hello World!"); diff --git a/tests/stm32/src/common.rs b/tests/stm32/src/common.rs index 9c0b8c39..2bf50079 100644 --- a/tests/stm32/src/common.rs +++ b/tests/stm32/src/common.rs @@ -34,6 +34,14 @@ teleprobe_meta::target!(b"nucleo-stm32l4a6zg"); teleprobe_meta::target!(b"nucleo-stm32l4r5zi"); #[cfg(feature = "stm32l552ze")] teleprobe_meta::target!(b"nucleo-stm32l552ze"); +#[cfg(feature = "stm32f767zi")] +teleprobe_meta::target!(b"nucleo-stm32f767zi"); +#[cfg(feature = "stm32f207zg")] +teleprobe_meta::target!(b"nucleo-stm32f207zg"); +#[cfg(feature = "stm32f303ze")] +teleprobe_meta::target!(b"nucleo-stm32f303ze"); +#[cfg(feature = "stm32l496zg")] +teleprobe_meta::target!(b"nucleo-stm32l496zg"); macro_rules! define_peris { ($($name:ident = $peri:ident,)* $(@irq $irq_name:ident = $irq_code:tt,)*) => { @@ -119,6 +127,12 @@ define_peris!( SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH1, SPI_RX_DMA = DMA1_CH2, @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler;}, ); +#[cfg(feature = "stm32l496zg")] +define_peris!( + UART = USART3, UART_TX = PD8, UART_RX = PD9, UART_TX_DMA = DMA1_CH2, UART_RX_DMA = DMA1_CH3, + SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2, + @irq UART = {USART3 => embassy_stm32::usart::InterruptHandler;}, +); #[cfg(feature = "stm32l4a6zg")] define_peris!( UART = USART3, UART_TX = PD8, UART_RX = PD9, UART_TX_DMA = DMA1_CH2, UART_RX_DMA = DMA1_CH3, @@ -149,28 +163,114 @@ define_peris!( SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH1, SPI_RX_DMA = DMA1_CH2, @irq UART = {USART3 => embassy_stm32::usart::InterruptHandler;}, ); +#[cfg(feature = "stm32f767zi")] +define_peris!( + UART = USART6, UART_TX = PG14, UART_RX = PG9, UART_TX_DMA = DMA2_CH6, UART_RX_DMA = DMA2_CH1, + SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA2_CH3, SPI_RX_DMA = DMA2_CH2, + @irq UART = {USART6 => embassy_stm32::usart::InterruptHandler;}, +); +#[cfg(feature = "stm32f207zg")] +define_peris!( + UART = USART6, UART_TX = PG14, UART_RX = PG9, UART_TX_DMA = DMA2_CH6, UART_RX_DMA = DMA2_CH1, + SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA2_CH3, SPI_RX_DMA = DMA2_CH2, + @irq UART = {USART6 => embassy_stm32::usart::InterruptHandler;}, +); +#[cfg(feature = "stm32f303ze")] +define_peris!( + UART = USART1, UART_TX = PC4, UART_RX = PC5, UART_TX_DMA = DMA1_CH4, UART_RX_DMA = DMA1_CH5, + SPI = SPI1, SPI_SCK = PA5, SPI_MOSI = PA7, SPI_MISO = PA6, SPI_TX_DMA = DMA1_CH3, SPI_RX_DMA = DMA1_CH2, + @irq UART = {USART1 => embassy_stm32::usart::InterruptHandler;}, +); pub fn config() -> Config { #[allow(unused_mut)] let mut config = Config::default(); + #[cfg(feature = "stm32f207zg")] + { + use embassy_stm32::rcc::*; + // By default, HSE on the board comes from a 8 MHz clock signal (not a crystal) + config.rcc.hse = Some(HSEConfig { + frequency: Hertz(8_000_000), + source: HSESrc::Bypass, + }); + // PLL uses HSE as the clock source + config.rcc.pll_mux = PLLSrc::HSE; + config.rcc.pll = PLLConfig { + // 8 MHz clock source / 8 = 1 MHz PLL input + pre_div: unwrap!(PLLPreDiv::try_from(8)), + // 1 MHz PLL input * 240 = 240 MHz PLL VCO + mul: unwrap!(PLLMul::try_from(240)), + // 240 MHz PLL VCO / 2 = 120 MHz main PLL output + p_div: PLLPDiv::DIV2, + // 240 MHz PLL VCO / 5 = 48 MHz PLL48 output + q_div: PLLQDiv::DIV5, + }; + // System clock comes from PLL (= the 120 MHz main PLL output) + config.rcc.mux = ClockSrc::PLL; + // 120 MHz / 4 = 30 MHz APB1 frequency + config.rcc.apb1_pre = APBPrescaler::DIV4; + // 120 MHz / 2 = 60 MHz APB2 frequency + config.rcc.apb2_pre = APBPrescaler::DIV2; + } + + #[cfg(feature = "stm32f429zi")] + { + // TODO: stm32f429zi can do up to 180mhz, but that makes tests fail. + // perhaps we have some bug w.r.t overdrive. + config.rcc.sys_ck = Some(Hertz(168_000_000)); + config.rcc.pclk1 = Some(Hertz(42_000_000)); + config.rcc.pclk2 = Some(Hertz(84_000_000)); + } + + #[cfg(feature = "stm32f767zi")] + { + config.rcc.sys_ck = Some(Hertz(200_000_000)); + } + + #[cfg(feature = "stm32h563zi")] + { + use embassy_stm32::rcc::*; + config.rcc.hsi = None; + config.rcc.hsi48 = true; // needed for rng + config.rcc.hse = Some(Hse { + freq: Hertz(8_000_000), + mode: HseMode::BypassDigital, + }); + config.rcc.pll1 = Some(Pll { + source: PllSource::Hse, + prediv: PllPreDiv::DIV2, + mul: PllMul::MUL125, + divp: Some(PllDiv::DIV2), + divq: Some(PllDiv::DIV2), + divr: None, + }); + config.rcc.ahb_pre = AHBPrescaler::DIV1; + config.rcc.apb1_pre = APBPrescaler::DIV1; + config.rcc.apb2_pre = APBPrescaler::DIV1; + config.rcc.apb3_pre = APBPrescaler::DIV1; + config.rcc.sys = Sysclk::Pll1P; + config.rcc.voltage_scale = VoltageScale::Scale0; + } + #[cfg(feature = "stm32h755zi")] { use embassy_stm32::rcc::*; config.rcc.hsi = Some(Hsi::Mhz64); config.rcc.csi = true; + config.rcc.hsi48 = true; // needed for RNG config.rcc.pll_src = PllSource::Hsi; config.rcc.pll1 = Some(Pll { - prediv: 4, - mul: 50, - divp: Some(2), - divq: Some(8), // SPI1 cksel defaults to pll1_q + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV2), + divq: Some(PllDiv::DIV8), // SPI1 cksel defaults to pll1_q divr: None, }); config.rcc.pll2 = Some(Pll { - prediv: 4, - mul: 50, - divp: Some(8), // 100mhz + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV8), // 100mhz divq: None, divr: None, }); @@ -190,10 +290,10 @@ pub fn config() -> Config { config.rcc.mux = ClockSrc::PLL( // 72Mhz clock (16 / 1 * 18 / 4) PLLSource::HSI16, - PLLClkDiv::Div4, - PLLSrcDiv::Div1, - PLLMul::Mul18, - Some(PLLClkDiv::Div6), // 48Mhz (16 / 1 * 18 / 6) + PllRDiv::DIV4, + PllPreDiv::DIV1, + PllMul::MUL18, + Some(PllQDiv::DIV6), // 48Mhz (16 / 1 * 18 / 6) ); } @@ -203,9 +303,9 @@ pub fn config() -> Config { config.rcc.mux = ClockSrc::PLL( // 110Mhz clock (16 / 4 * 55 / 2) PLLSource::HSI16, - PLLClkDiv::Div2, - PLLSrcDiv::Div4, - PLLMul::Mul55, + PllRDiv::DIV2, + PllPreDiv::DIV4, + PllMul::MUL55, None, ); } @@ -213,7 +313,7 @@ pub fn config() -> Config { #[cfg(feature = "stm32u585ai")] { use embassy_stm32::rcc::*; - config.rcc.mux = ClockSrc::MSI(MSIRange::Range48mhz); + config.rcc.mux = ClockSrc::MSI(Msirange::RANGE_48MHZ); } #[cfg(feature = "stm32l073rz")] @@ -222,8 +322,8 @@ pub fn config() -> Config { config.rcc.mux = ClockSrc::PLL( // 32Mhz clock (16 * 4 / 2) PLLSource::HSI16, - PLLMul::Mul4, - PLLDiv::Div2, + PLLMul::MUL4, + PLLDiv::DIV2, ); } @@ -232,9 +332,9 @@ pub fn config() -> Config { use embassy_stm32::rcc::*; config.rcc.mux = ClockSrc::PLL( // 32Mhz clock (16 * 4 / 2) - PLLSource::HSI, - PLLMul::Mul4, - PLLDiv::Div2, + PLLSource::HSI16, + PLLMul::MUL4, + PLLDiv::DIV2, ); }