Compare commits

..

14 Commits

Author SHA1 Message Date
c8aa9c3b98 wip 2023-10-11 20:53:33 -05:00
7810ef1c5e wip 2023-10-11 20:22:00 -05:00
c1dc1741f6 wip 2023-10-11 20:21:32 -05:00
6deec1b853 wip 2023-10-11 20:17:47 -05:00
ba5b5e98fe wip 2023-10-11 20:15:43 -05:00
158aeac438 wip 2023-10-11 20:12:13 -05:00
f27c929cb8 wip 2023-10-11 19:59:42 -05:00
0d0fbe957e Merge branch 'rcc-mux' of github.com:xoviat/embassy; branch 'main' of github.com:embassy-rs/embassy into rcc-mux 2023-10-11 19:58:38 -05:00
e1a1c51d00 remove disable variant 2023-10-11 19:35:45 -05:00
e25c7c23d0 wip 2023-10-09 20:49:44 -05:00
4ee39f6dce Merge branch 'main' of github.com:embassy-rs/embassy into rcc-mux 2023-10-09 20:10:16 -05:00
a4b6bc31f8 wip 2023-10-08 18:26:27 -05:00
2ae9d28d47 wip 2023-10-07 09:34:12 -05:00
1457b53e48 wip 2023-10-07 09:31:09 -05:00
384 changed files with 4349 additions and 4358 deletions

View File

@ -62,9 +62,9 @@ async fn blink(pin: AnyPin) {
loop {
// Timekeeping is globally available, no need to mess with hardware timers.
led.set_high();
Timer::after_millis(150).await;
Timer::after(Duration::from_millis(150)).await;
led.set_low();
Timer::after_millis(150).await;
Timer::after(Duration::from_millis(150)).await;
}
}

116
ci.sh
View File

@ -69,68 +69,62 @@ 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,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,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,time-driver-any \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt,exti,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,defmt \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,time-driver-any \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,time-driver-any \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt,exti,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32l552ze,nightly,defmt \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f401ve,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f405zg,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f407zg,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,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 embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f410tb,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f411ce,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f412zg,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f413vh,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f415zg,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f417zg,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f423zh,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f427zi,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f429zi,log,exti,time-driver-any,unstable-traits,embedded-sdmmc \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f437zi,log,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f439zi,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f446ze,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f469zi,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f479zi,defmt,exti,time-driver-any,unstable-traits,embedded-sdmmc \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32f730i8,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h753zi,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h735zg,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h755zi-cm7,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32h7b3ai,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l476vg,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32l422cb,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wb15cc,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l072cz,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l041f6,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32l073cz,defmt,exti,time-driver-any,unstable-traits,low-power \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32l151cb-a,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f398ve,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f378cc,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32g0c1ve,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f217zg,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features nightly,stm32l552ze,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features nightly,stm32wl54jc-cm0p,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32wle5jb,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features nightly,stm32g474pe,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f107vc,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f103re,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32f100c4,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32h503rb,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7m-none-eabi --features nightly,stm32h562ag,defmt,exti,time-driver-any,unstable-traits \
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features ''\
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log' \
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \
@ -192,13 +186,9 @@ cargo batch \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32g071rb --out-dir out/tests/stm32g071rb \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32c031c6 --out-dir out/tests/stm32c031c6 \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h755zi --out-dir out/tests/stm32h755zi \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h753zi --out-dir out/tests/stm32h753zi \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h7a3zi --out-dir out/tests/stm32h7a3zi \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb55rg --out-dir out/tests/stm32wb55rg \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32h563zi --out-dir out/tests/stm32h563zi \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u585ai --out-dir out/tests/stm32u585ai \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32u5a5zj --out-dir out/tests/stm32u5a5zj \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wba52cg --out-dir out/tests/stm32wba52cg \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32l073rz --out-dir out/tests/stm32l073rz \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7m-none-eabi --features stm32l152re --out-dir out/tests/stm32l152re \
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l4a6zg --out-dir out/tests/stm32l4a6zg \
@ -208,7 +198,6 @@ cargo batch \
--- 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/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55jc --out-dir out/tests/stm32wl55jc \
--- 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 \
@ -217,13 +206,8 @@ cargo batch \
rm out/tests/stm32wb55rg/wpan_mac
rm out/tests/stm32wb55rg/wpan_ble
# unstable, I think it's running out of RAM?
rm out/tests/stm32f207zg/eth
# doesn't work, gives "noise error", no idea why. usart_dma does pass.
rm out/tests/stm32u5a5zj/usart
if [[ -z "${TELEPROBE_TOKEN-}" ]]; then
echo No teleprobe token found, skipping running HIL tests
exit

View File

@ -40,38 +40,33 @@ 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 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 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 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 \

View File

@ -11,10 +11,10 @@ log = ["dep:log"]
firmware-logs = []
[dependencies]
embassy-time = { version = "0.1.5", path = "../embassy-time"}
embassy-time = { version = "0.1.3", 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.2.0", path = "../embassy-net-driver-channel"}
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"}
defmt = { version = "0.3", optional = true }
log = { version = "0.4.17", optional = true }

View File

@ -1,5 +1,5 @@
use embassy_futures::yield_now;
use embassy_time::Timer;
use embassy_time::{Duration, Timer};
use embedded_hal_1::digital::OutputPin;
use futures::FutureExt;
@ -51,9 +51,9 @@ where
pub async fn init(&mut self) {
// Reset
self.pwr.set_low().unwrap();
Timer::after_millis(20).await;
Timer::after(Duration::from_millis(20)).await;
self.pwr.set_high().unwrap();
Timer::after_millis(250).await;
Timer::after(Duration::from_millis(250)).await;
while self
.read32_swapped(REG_BUS_TEST_RO)

View File

@ -1,8 +1,8 @@
use core::cmp::{max, min};
use ch::driver::LinkState;
use embassy_net_driver_channel as ch;
use embassy_net_driver_channel::driver::{HardwareAddress, LinkState};
use embassy_time::Timer;
use embassy_time::{Duration, Timer};
pub use crate::bus::SpiBusCyw43;
use crate::consts::*;
@ -87,22 +87,22 @@ impl<'a> Control<'a> {
self.set_iovar("country", &country_info.to_bytes()).await;
// set country takes some time, next ioctls fail if we don't wait.
Timer::after_millis(100).await;
Timer::after(Duration::from_millis(100)).await;
// Set antenna to chip antenna
self.ioctl_set_u32(IOCTL_CMD_ANTDIV, 0, 0).await;
self.set_iovar_u32("bus:txglom", 0).await;
Timer::after_millis(100).await;
Timer::after(Duration::from_millis(100)).await;
//self.set_iovar_u32("apsta", 1).await; // this crashes, also we already did it before...??
//Timer::after_millis(100).await;
//Timer::after(Duration::from_millis(100)).await;
self.set_iovar_u32("ampdu_ba_wsize", 8).await;
Timer::after_millis(100).await;
Timer::after(Duration::from_millis(100)).await;
self.set_iovar_u32("ampdu_mpdu", 4).await;
Timer::after_millis(100).await;
Timer::after(Duration::from_millis(100)).await;
//self.set_iovar_u32("ampdu_rx_factor", 0).await; // this crashes
//Timer::after_millis(100).await;
//Timer::after(Duration::from_millis(100)).await;
// evts
let mut evts = EventMask {
@ -121,19 +121,19 @@ impl<'a> Control<'a> {
self.set_iovar("bsscfg:event_msgs", &evts.to_bytes()).await;
Timer::after_millis(100).await;
Timer::after(Duration::from_millis(100)).await;
// set wifi up
self.up().await;
Timer::after_millis(100).await;
Timer::after(Duration::from_millis(100)).await;
self.ioctl_set_u32(110, 0, 1).await; // SET_GMODE = auto
self.ioctl_set_u32(142, 0, 0).await; // SET_BAND = any
Timer::after_millis(100).await;
Timer::after(Duration::from_millis(100)).await;
self.state_ch.set_hardware_address(HardwareAddress::Ethernet(mac_addr));
self.state_ch.set_ethernet_address(mac_addr);
debug!("INIT DONE");
}
@ -185,7 +185,7 @@ impl<'a> Control<'a> {
self.set_iovar_u32x2("bsscfg:sup_wpa2_eapver", 0, 0xFFFF_FFFF).await;
self.set_iovar_u32x2("bsscfg:sup_wpa_tmo", 0, 2500).await;
Timer::after_millis(100).await;
Timer::after(Duration::from_millis(100)).await;
let mut pfi = PassphraseInfo {
len: passphrase.len() as _,
@ -297,7 +297,7 @@ impl<'a> Control<'a> {
if security != Security::OPEN {
self.set_iovar_u32x2("bsscfg:wpa_auth", 0, 0x0084).await; // wpa_auth = WPA2_AUTH_PSK | WPA_AUTH_PSK
Timer::after_millis(100).await;
Timer::after(Duration::from_millis(100)).await;
// Set passphrase
let mut pfi = PassphraseInfo {

View File

@ -555,14 +555,14 @@ where
self.bus.bp_write8(base + AI_RESETCTRL_OFFSET, 0).await;
Timer::after_millis(1).await;
Timer::after(Duration::from_millis(1)).await;
self.bus
.bp_write8(base + AI_IOCTRL_OFFSET, AI_IOCTRL_BIT_CLOCK_EN)
.await;
let _ = self.bus.bp_read8(base + AI_IOCTRL_OFFSET).await;
Timer::after_millis(1).await;
Timer::after(Duration::from_millis(1)).await;
}
async fn core_is_up(&mut self, core: Core) -> bool {

View File

@ -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.4", path = "../../../../../embassy-time", features = ["defmt", "nightly"] }
embassy-time = { version = "0.1.0", 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"

View File

@ -48,7 +48,7 @@ The `Spawner` is the way the main application spawns other tasks. The `Periphera
include::example$basic/src/main.rs[lines="22..-1"]
----
What happens when the `blinker` task has been spawned and main returns? Well, the main entry point is actually just like any other task, except that you can only have one and it takes some specific type arguments. The magic lies within the `#[embassy_executor::main]` macro. The macro does the following:
What happens when the `blinker` task has been spawned and main returns? Well, the main entry point is actually just like any other task, except that you can only have one and it takes some specific type arguments. The magic lies within the `#[embassy::main]` macro. The macro does the following:
. Creates an Embassy Executor
. Initializes the microcontroller HAL to get the `Peripherals`

View File

@ -6,7 +6,7 @@ The Embassy executor is an async/await executor designed for embedded usage alon
* No `alloc`, no heap needed. Task are statically allocated.
* No "fixed capacity" data structures, executor works with 1 or 1000 tasks without needing config/tuning.
* Integrated timer queue: sleeping is easy, just do `Timer::after_secs(1).await;`.
* Integrated timer queue: sleeping is easy, just do `Timer::after(Duration::from_secs(1)).await;`.
* No busy-loop polling: CPU sleeps when there's no work to do, using interrupts or `WFE/SEV`.
* Efficient polling: a wake will only poll the woken task, not all of them.
* Fair: a task can't monopolize CPU time even if it's constantly being woken. All other tasks get a chance to run before a given task gets polled for the second time.

View File

@ -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.5", path = "../embassy-time", optional = true }
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [
"unproven",
] }

View File

@ -76,7 +76,9 @@ where
#[cfg(not(feature = "time"))]
Operation::DelayUs(_) => return Err(SpiDeviceError::DelayUsNotSupported),
#[cfg(feature = "time")]
Operation::DelayUs(us) => embassy_time::Timer::after_micros(*us as _).await,
Operation::DelayUs(us) => {
embassy_time::Timer::after(embassy_time::Duration::from_micros(*us as _)).await
}
}
}
};
@ -141,7 +143,9 @@ where
#[cfg(not(feature = "time"))]
Operation::DelayUs(_) => return Err(SpiDeviceError::DelayUsNotSupported),
#[cfg(feature = "time")]
Operation::DelayUs(us) => embassy_time::Timer::after_micros(*us as _).await,
Operation::DelayUs(us) => {
embassy_time::Timer::after(embassy_time::Duration::from_micros(*us as _)).await
}
}
}
};

View File

@ -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.5", path = "../embassy-time", optional = true}
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true}
atomic-polyfill = "1.0.1"
critical-section = "1.1"
static_cell = "1.1"

View File

@ -4,7 +4,7 @@ An async/await executor designed for embedded usage.
- No `alloc`, no heap needed. Task futures are statically allocated.
- No "fixed capacity" data structures, executor works with 1 or 1000 tasks without needing config/tuning.
- Integrated timer queue: sleeping is easy, just do `Timer::after_secs(1).await;`.
- Integrated timer queue: sleeping is easy, just do `Timer::after(Duration::from_secs(1)).await;`.
- No busy-loop polling: CPU sleeps when there's no work to do, using interrupts or `WFE/SEV`.
- Efficient polling: a wake will only poll the woken task, not all of them.
- Fair: a task can't monopolize CPU time even if it's constantly being woken. All other tasks get a chance to run before a given task gets polled for the second time.

View File

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

View File

@ -4,7 +4,6 @@ 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]
@ -92,12 +91,6 @@ 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)
}
}
$(
@ -202,29 +195,10 @@ pub unsafe trait InterruptExt: InterruptNumber + Copy {
/// Set the interrupt priority.
#[inline]
fn set_priority(self, prio: Priority) {
unsafe {
critical_section::with(|_| unsafe {
let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(());
// 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());
}
nvic.set_priority(self, prio.into())
})
}
}

View File

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

View File

@ -48,23 +48,17 @@ 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;
// safety: OK because we're inside a CS.
unsafe {
critical_section::with(|_| unsafe {
if _EMBASSY_DEVICE_PERIPHERALS {
panic!("init called more than once!")
}
_EMBASSY_DEVICE_PERIPHERALS = true;
Self::steal()
}
})
}
}

View File

@ -0,0 +1,136 @@
pub struct RingBuffer<'a> {
buf: &'a mut [u8],
start: usize,
end: usize,
empty: bool,
}
impl<'a> RingBuffer<'a> {
pub fn new(buf: &'a mut [u8]) -> Self {
Self {
buf,
start: 0,
end: 0,
empty: true,
}
}
pub fn push_buf(&mut self) -> &mut [u8] {
if self.start == self.end && !self.empty {
trace!(" ringbuf: push_buf empty");
return &mut self.buf[..0];
}
let n = if self.start <= self.end {
self.buf.len() - self.end
} else {
self.start - self.end
};
trace!(" ringbuf: push_buf {:?}..{:?}", self.end, self.end + n);
&mut self.buf[self.end..self.end + n]
}
pub fn push(&mut self, n: usize) {
trace!(" ringbuf: push {:?}", n);
if n == 0 {
return;
}
self.end = self.wrap(self.end + n);
self.empty = false;
}
pub fn pop_buf(&mut self) -> &mut [u8] {
if self.empty {
trace!(" ringbuf: pop_buf empty");
return &mut self.buf[..0];
}
let n = if self.end <= self.start {
self.buf.len() - self.start
} else {
self.end - self.start
};
trace!(" ringbuf: pop_buf {:?}..{:?}", self.start, self.start + n);
&mut self.buf[self.start..self.start + n]
}
pub fn pop(&mut self, n: usize) {
trace!(" ringbuf: pop {:?}", n);
if n == 0 {
return;
}
self.start = self.wrap(self.start + n);
self.empty = self.start == self.end;
}
pub fn is_full(&self) -> bool {
self.start == self.end && !self.empty
}
pub fn is_empty(&self) -> bool {
self.empty
}
pub fn clear(&mut self) {
self.start = 0;
self.end = 0;
self.empty = true;
}
fn wrap(&self, n: usize) -> usize {
assert!(n <= self.buf.len());
if n == self.buf.len() {
0
} else {
n
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn push_pop() {
let mut b = [0; 4];
let mut rb = RingBuffer::new(&mut b);
let buf = rb.push_buf();
assert_eq!(4, buf.len());
buf[0] = 1;
buf[1] = 2;
buf[2] = 3;
buf[3] = 4;
rb.push(4);
let buf = rb.pop_buf();
assert_eq!(4, buf.len());
assert_eq!(1, buf[0]);
rb.pop(1);
let buf = rb.pop_buf();
assert_eq!(3, buf.len());
assert_eq!(2, buf[0]);
rb.pop(1);
let buf = rb.pop_buf();
assert_eq!(2, buf.len());
assert_eq!(3, buf[0]);
rb.pop(1);
let buf = rb.pop_buf();
assert_eq!(1, buf.len());
assert_eq!(4, buf[0]);
rb.pop(1);
let buf = rb.pop_buf();
assert_eq!(0, buf.len());
let buf = rb.push_buf();
assert_eq!(4, buf.len());
}
}

View File

@ -20,7 +20,7 @@ defmt = ["dep:defmt", "lorawan-device/defmt"]
defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true }
embassy-time = { version = "0.1.5", path = "../embassy-time", optional = true }
embassy-time = { version = "0.1.3", 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" }

View File

@ -34,6 +34,6 @@ impl lorawan_device::async_device::radio::Timer for LoraTimer {
}
async fn delay_ms(&mut self, millis: u64) {
Timer::after_millis(millis).await
Timer::after(Duration::from_millis(millis)).await
}
}

View File

@ -16,8 +16,8 @@ log = { version = "0.4", default-features = false, optional = true }
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.2.0", path = "../embassy-net-driver-channel" }
embassy-time = { version = "0.1.5", path = "../embassy-time" }
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
embassy-time = { version = "0.1.3" }
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
bitfield = "0.14.0"

View File

@ -20,7 +20,7 @@ pub use crc32::ETH_FCS;
use crc8::crc8;
use embassy_futures::select::{select, Either};
use embassy_net_driver_channel as ch;
use embassy_time::Timer;
use embassy_time::{Duration, Timer};
use embedded_hal_1::digital::OutputPin;
use embedded_hal_async::digital::Wait;
use embedded_hal_async::spi::{Error, Operation, SpiDevice};
@ -609,12 +609,12 @@ pub async fn new<const N_RX: usize, const N_TX: usize, SPI: SpiDevice, INT: Wait
reset.set_low().unwrap();
// Wait t1: 20-43mS
Timer::after_millis(30).await;
Timer::after(Duration::from_millis(30)).await;
reset.set_high().unwrap();
// Wait t3: 50mS
Timer::after_millis(50).await;
Timer::after(Duration::from_millis(50)).await;
// Create device
let mut mac = ADIN1110::new(spi_dev, spi_crc, append_fcs_on_tx);

View File

@ -1,16 +0,0 @@
# Changelog
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.2.0 - 2023-10-18
- Update `embassy-net-driver` to v0.2
- `Runner::new` now takes an `embassy_net_driver::HardwareAddress` parameter.
- `Runner::set_ethernet_address` is now `set_hardware_address`.
## 0.1.0 - 2023-06-29
- First release

View File

@ -1,6 +1,6 @@
[package]
name = "embassy-net-driver-channel"
version = "0.2.0"
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "High-level channel-based driver for the `embassy-net` async TCP/IP network stack."
@ -26,4 +26,4 @@ log = { version = "0.4.14", optional = true }
embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }

View File

@ -7,9 +7,7 @@ The `embassy-net-driver` trait is polling-based. To implement it, you must write
hand, and hook up the `Waker`s provided by `embassy-net` to the right interrupt handlers so that `embassy-net`
knows when to poll your driver again to make more progress.
With `embassy-net-driver-channel` you get a "channel-like" interface instead, where you can send/receive packets
to/from embassy-net. The intended usage is to spawn a "driver task" in the background that does this, passing
packets between the hardware and the channel.
With `embassy-net-driver-channel`
## A note about deadlocks
@ -20,19 +18,19 @@ loop {
// Wait for either..
match select(
// ... the chip signaling an interrupt, indicating a packet is available to receive, or
irq_pin.wait_for_low(),
irq_pin.wait_for_low(),
// ... a TX buffer becoming available, i.e. embassy-net wants to send a packet
tx_chan.tx_buf(),
).await {
Either::First(_) => {
// a packet is ready to be received!
let buf = rx_chan.rx_buf().await; // allocate a rx buf from the packet queue
let n = receive_packet_over_spi(buf).await;
let n = receive_packet_over_spi(buf).await;
rx_chan.rx_done(n);
}
Either::Second(buf) => {
// a packet is ready to be sent!
send_packet_over_spi(buf).await;
send_packet_over_spi(buf).await;
tx_chan.tx_done();
}
}
@ -43,7 +41,7 @@ However, this code has a latent deadlock bug. The symptom is it can hang at `rx_
The reason is that, under load, both the TX and RX queues can get full at the same time. When this happens, the `embassy-net` task stalls trying to send because the TX queue is full, therefore it stops processing packets in the RX queue. Your driver task also stalls because the RX queue is full, therefore it stops processing packets in the TX queue.
The fix is to make sure to always service the TX queue while you're waiting for space to become available in the RX queue. For example, select on either "tx_chan.tx_buf() available" or "INT is low AND rx_chan.rx_buf() available":
The fix is to make sure to always service the TX queue while you're waiting for space to become available in the TX queue. For example, select on either "tx_chan.tx_buf() available" or "INT is low AND rx_chan.rx_buf() available":
```rust,ignore
loop {
@ -60,12 +58,12 @@ loop {
).await {
Either::First(buf) => {
// a packet is ready to be received!
let n = receive_packet_over_spi(buf).await;
let n = receive_packet_over_spi(buf).await;
rx_chan.rx_done(n);
}
Either::Second(buf) => {
// a packet is ready to be sent!
send_packet_over_spi(buf).await;
send_packet_over_spi(buf).await;
tx_chan.tx_done();
}
}
@ -81,10 +79,12 @@ These `embassy-net` drivers are implemented using this crate. You can look at th
- [`embassy-net-wiznet`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-wiznet) for Wiznet SPI Ethernet MAC+PHY chips.
- [`embassy-net-esp-hosted`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-esp-hosted) for using ESP32 chips with the [`esp-hosted`](https://github.com/espressif/esp-hosted) firmware as WiFi adapters for another non-ESP32 MCU.
## Interoperability
This crate can run on any executor.
## License
This work is licensed under either of

View File

@ -8,8 +8,9 @@ use core::cell::RefCell;
use core::mem::MaybeUninit;
use core::task::{Context, Poll};
use driver::HardwareAddress;
pub use embassy_net_driver as driver;
use embassy_net_driver::{Capabilities, LinkState};
use embassy_net_driver::{Capabilities, LinkState, Medium};
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
use embassy_sync::blocking_mutex::Mutex;
use embassy_sync::waitqueue::WakerRegistration;
@ -160,10 +161,18 @@ impl<'d> StateRunner<'d> {
});
}
pub fn set_hardware_address(&self, address: driver::HardwareAddress) {
pub fn set_ethernet_address(&self, address: [u8; 6]) {
self.shared.lock(|s| {
let s = &mut *s.borrow_mut();
s.hardware_address = address;
s.hardware_address = driver::HardwareAddress::Ethernet(address);
s.waker.wake();
});
}
pub fn set_ieee802154_address(&self, address: [u8; 8]) {
self.shared.lock(|s| {
let s = &mut *s.borrow_mut();
s.hardware_address = driver::HardwareAddress::Ieee802154(address);
s.waker.wake();
});
}
@ -223,6 +232,11 @@ pub fn new<'d, const MTU: usize, const N_RX: usize, const N_TX: usize>(
) -> (Runner<'d, MTU>, Device<'d, MTU>) {
let mut caps = Capabilities::default();
caps.max_transmission_unit = MTU;
caps.medium = match &hardware_address {
HardwareAddress::Ethernet(_) => Medium::Ethernet,
HardwareAddress::Ieee802154(_) => Medium::Ieee802154,
HardwareAddress::Ip => Medium::Ip,
};
// safety: this is a self-referential struct, however:
// - it can't move while the `'d` borrow is active.

View File

@ -1,17 +0,0 @@
# Changelog
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.2.0 - 2023-10-18
- Added support for IEEE 802.15.4 mediums.
- Added `Driver::hardware_address()`, `HardwareAddress`.
- Removed `Medium` enum. The medium is deduced out of the hardware address.
- Removed `Driver::ethernet_address()`. Replacement is `hardware_address()`.
## 0.1.0 - 2023-06-29
- First release

View File

@ -1,6 +1,6 @@
[package]
name = "embassy-net-driver"
version = "0.2.0"
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "Driver trait for the `embassy-net` async TCP/IP network stack."

View File

@ -7,23 +7,12 @@ use core::task::Context;
/// Representation of an hardware address, such as an Ethernet address or an IEEE802.15.4 address.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum HardwareAddress {
/// Ethernet medium, with a A six-octet Ethernet address.
///
/// Devices of this type send and receive Ethernet frames,
/// and interfaces using it must do neighbor discovery via ARP or NDISC.
///
/// Examples of devices of this type are Ethernet, WiFi (802.11), Linux `tap`, and VPNs in tap (layer 2) mode.
/// A six-octet Ethernet address
Ethernet([u8; 6]),
/// 6LoWPAN over IEEE802.15.4, with an eight-octet address.
/// An eight-octet IEEE802.15.4 address
Ieee802154([u8; 8]),
/// Indicates that a Driver is IP-native, and has no hardware address.
///
/// Devices of this type send and receive IP frames, without an
/// Ethernet header. MAC addresses are not used, and no neighbor discovery (ARP, NDISC) is done.
///
/// Examples of devices of this type are the Linux `tun`, PPP interfaces, VPNs in tun (layer 3) mode.
/// Indicates that a Driver is IP-native, and has no hardware address
Ip,
}
@ -75,10 +64,6 @@ pub trait Driver {
fn capabilities(&self) -> Capabilities;
/// Get the device's hardware address.
///
/// The returned hardware address also determines the "medium" of this driver. This indicates
/// what kind of packet the sent/received bytes are, and determines some behaviors of
/// the interface. For example, ARP/NDISC address resolution is only done for Ethernet mediums.
fn hardware_address(&self) -> HardwareAddress;
}
@ -139,6 +124,13 @@ pub trait TxToken {
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub struct Capabilities {
/// Medium of the device.
///
/// This indicates what kind of packet the sent/received bytes are, and determines
/// some behaviors of Interface. For example, ARP/NDISC address resolution is only done
/// for Ethernet mediums.
pub medium: Medium,
/// Maximum transmission unit.
///
/// The network device is unable to send or receive frames larger than the value returned
@ -169,6 +161,32 @@ pub struct Capabilities {
pub checksum: ChecksumCapabilities,
}
/// Type of medium of a device.
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Medium {
/// Ethernet medium. Devices of this type send and receive Ethernet frames,
/// and interfaces using it must do neighbor discovery via ARP or NDISC.
///
/// Examples of devices of this type are Ethernet, WiFi (802.11), Linux `tap`, and VPNs in tap (layer 2) mode.
Ethernet,
/// IP medium. Devices of this type send and receive IP frames, without an
/// Ethernet header. MAC addresses are not used, and no neighbor discovery (ARP, NDISC) is done.
///
/// Examples of devices of this type are the Linux `tun`, PPP interfaces, VPNs in tun (layer 3) mode.
Ip,
/// IEEE 802_15_4 medium
Ieee802154,
}
impl Default for Medium {
fn default() -> Medium {
Medium::Ethernet
}
}
/// A description of checksum behavior for every supported protocol.
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]

View File

@ -10,8 +10,8 @@ edition = "2021"
[dependencies]
embedded-hal = { version = "1.0.0-rc.1" }
embedded-hal-async = { version = "=1.0.0-rc.1" }
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
embassy-time = { version = "0.1.5", path = "../embassy-time" }
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
embassy-time = { version = "0.1.3", path = "../embassy-time" }
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
defmt = { version = "0.3", optional = true }

View File

@ -19,7 +19,7 @@ mod traits;
use core::cmp;
use core::convert::TryInto;
use embassy_net_driver::{Capabilities, HardwareAddress, LinkState};
use embassy_net_driver::{Capabilities, HardwareAddress, LinkState, Medium};
use embassy_time::Duration;
use embedded_hal::digital::OutputPin;
use embedded_hal::spi::{Operation, SpiDevice};
@ -671,6 +671,7 @@ where
fn capabilities(&self) -> Capabilities {
let mut caps = Capabilities::default();
caps.max_transmission_unit = MTU;
caps.medium = Medium::Ethernet;
caps
}

View File

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

View File

@ -1,5 +1,5 @@
use ch::driver::LinkState;
use embassy_net_driver_channel as ch;
use embassy_net_driver_channel::driver::{HardwareAddress, LinkState};
use heapless::String;
use crate::ioctl::Shared;
@ -77,7 +77,7 @@ impl<'a> Control<'a> {
let mac_addr = self.get_mac_addr().await?;
debug!("mac addr: {:02x}", mac_addr);
self.state_ch.set_hardware_address(HardwareAddress::Ethernet(mac_addr));
self.state_ch.set_ethernet_address(mac_addr);
Ok(())
}

View File

@ -169,9 +169,9 @@ where
pub async fn run(mut self) -> ! {
debug!("resetting...");
self.reset.set_low().unwrap();
Timer::after_millis(100).await;
Timer::after(Duration::from_millis(100)).await;
self.reset.set_high().unwrap();
Timer::after_millis(1000).await;
Timer::after(Duration::from_millis(1000)).await;
let mut tx_buf = [0u8; MAX_SPI_BUFFER_SIZE];
let mut rx_buf = [0u8; MAX_SPI_BUFFER_SIZE];

View File

@ -16,7 +16,7 @@ defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true }
embedded-io-async = { version = "0.6.0" }
embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" }
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
ppproto = { version = "0.1.2"}
embassy-sync = { version = "0.3.0", path = "../embassy-sync" }

View File

@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
edition = "2021"
[dependencies]
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
async-io = "1.6.0"
log = "0.4.14"
libc = "0.2.101"

View File

@ -10,8 +10,8 @@ edition = "2021"
[dependencies]
embedded-hal = { version = "1.0.0-rc.1" }
embedded-hal-async = { version = "=1.0.0-rc.1" }
embassy-net-driver-channel = { version = "0.2.0", path = "../embassy-net-driver-channel" }
embassy-time = { version = "0.1.5", path = "../embassy-time" }
embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel" }
embassy-time = { version = "0.1.3", path = "../embassy-time" }
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
defmt = { version = "0.3", optional = true }

View File

@ -1,14 +1,14 @@
//! [`embassy-net`](https://crates.io/crates/embassy-net) driver for WIZnet ethernet chips.
#![no_std]
#![feature(async_fn_in_trait)]
#![doc = include_str!("../README.md")]
pub mod chip;
mod device;
use embassy_futures::select::{select3, Either3};
use embassy_futures::select::{select, Either};
use embassy_net_driver_channel as ch;
use embassy_net_driver_channel::driver::LinkState;
use embassy_time::{Duration, Ticker, Timer};
use embassy_time::{Duration, Timer};
use embedded_hal::digital::OutputPin;
use embedded_hal_async::digital::Wait;
use embedded_hal_async::spi::SpiDevice;
@ -49,34 +49,32 @@ pub struct Runner<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> {
impl<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, C, SPI, INT, RST> {
pub async fn run(mut self) -> ! {
let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split();
let mut tick = Ticker::every(Duration::from_millis(500));
loop {
match select3(
async {
self.int.wait_for_low().await.ok();
rx_chan.rx_buf().await
},
tx_chan.tx_buf(),
tick.next(),
)
.await
{
Either3::First(p) => {
if let Ok(n) = self.mac.read_frame(p).await {
rx_chan.rx_done(n);
}
}
Either3::Second(p) => {
self.mac.write_frame(p).await.ok();
tx_chan.tx_done();
}
Either3::Third(()) => {
if self.mac.is_link_up().await {
state_chan.set_link_state(LinkState::Up);
} else {
state_chan.set_link_state(LinkState::Down);
if self.mac.is_link_up().await {
state_chan.set_link_state(LinkState::Up);
loop {
match select(
async {
self.int.wait_for_low().await.ok();
rx_chan.rx_buf().await
},
tx_chan.tx_buf(),
)
.await
{
Either::First(p) => {
if let Ok(n) = self.mac.read_frame(p).await {
rx_chan.rx_done(n);
}
}
Either::Second(p) => {
self.mac.write_frame(p).await.ok();
tx_chan.tx_done();
}
}
}
} else {
state_chan.set_link_state(LinkState::Down);
}
}
}
@ -97,12 +95,12 @@ pub async fn new<'a, const N_RX: usize, const N_TX: usize, C: Chip, SPI: SpiDevi
// Reset the chip.
reset.set_low().ok();
// Ensure the reset is registered.
Timer::after_millis(1).await;
Timer::after(Duration::from_millis(1)).await;
reset.set_high().ok();
// Wait for PLL lock. Some chips are slower than others.
// Slowest is w5100s which is 100ms, so let's just wait that.
Timer::after_millis(100).await;
Timer::after(Duration::from_millis(100)).await;
let mac = WiznetDevice::new(spi_dev, mac_addr).await.unwrap();

View File

@ -1,29 +0,0 @@
# Changelog
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.2.0 - 2023-10-18
- Re-export `smoltcp::wire::IpEndpoint`
- Add poll functions on UdpSocket
- Make dual-stack work in embassy-net
- Fix multicast support
- Allow ethernet and 802.15.4 to coexist
- Add IEEE802.15.4 address to embassy net Stack
- Use HardwareAddress in Driver
- Add async versions of smoltcp's `send` and `recv` closure based API
- add error translation to tcp errors
- Forward TCP/UDP socket capacity impls
- allow changing IP config at runtime
- allow non-'static drivers
- Remove impl_trait_projections
- update embedded-io, embedded-nal-async
- add support for dhcp hostname option
- Wake stack's task after queueing a DNS query
## 0.1.0 - 2023-06-29
- First release

View File

@ -1,6 +1,6 @@
[package]
name = "embassy-net"
version = "0.2.0"
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "Async TCP/IP network stack for embedded systems"
@ -51,8 +51,8 @@ smoltcp = { version = "0.10.0", default-features = false, features = [
"async",
] }
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
embassy-time = { version = "0.1.5", path = "../embassy-time" }
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
embassy-time = { version = "0.1.3", path = "../embassy-time" }
embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
embedded-io-async = { version = "0.6.0", optional = true }

View File

@ -1,7 +1,7 @@
use core::task::Context;
use embassy_net_driver::{Capabilities, Checksum, Driver, RxToken, TxToken};
use smoltcp::phy::{self, Medium};
use embassy_net_driver::{Capabilities, Checksum, Driver, Medium, RxToken, TxToken};
use smoltcp::phy;
use smoltcp::time::Instant;
pub(crate) struct DriverAdapter<'d, 'c, T>
@ -11,7 +11,6 @@ where
// must be Some when actually using this to rx/tx
pub cx: Option<&'d mut Context<'c>>,
pub inner: &'d mut T,
pub medium: Medium,
}
impl<'d, 'c, T> phy::Device for DriverAdapter<'d, 'c, T>
@ -47,7 +46,19 @@ where
smolcaps.max_transmission_unit = caps.max_transmission_unit;
smolcaps.max_burst_size = caps.max_burst_size;
smolcaps.medium = self.medium;
smolcaps.medium = match caps.medium {
#[cfg(feature = "medium-ethernet")]
Medium::Ethernet => phy::Medium::Ethernet,
#[cfg(feature = "medium-ip")]
Medium::Ip => phy::Medium::Ip,
#[cfg(feature = "medium-ieee802154")]
Medium::Ieee802154 => phy::Medium::Ieee802154,
#[allow(unreachable_patterns)]
_ => panic!(
"Unsupported medium {:?}. Make sure to enable it in embassy-net's Cargo features.",
caps.medium
),
};
smolcaps.checksum.ipv4 = convert(caps.checksum.ipv4);
smolcaps.checksum.tcp = convert(caps.checksum.tcp);
smolcaps.checksum.udp = convert(caps.checksum.udp);

View File

@ -33,7 +33,6 @@ use heapless::Vec;
pub use smoltcp::iface::MulticastError;
#[allow(unused_imports)]
use smoltcp::iface::{Interface, SocketHandle, SocketSet, SocketStorage};
use smoltcp::phy::Medium;
#[cfg(feature = "dhcpv4")]
use smoltcp::socket::dhcpv4::{self, RetryConfig};
#[cfg(feature = "medium-ethernet")]
@ -265,17 +264,14 @@ pub(crate) struct SocketStack {
next_local_port: u16,
}
fn to_smoltcp_hardware_address(addr: driver::HardwareAddress) -> (HardwareAddress, Medium) {
fn to_smoltcp_hardware_address(addr: driver::HardwareAddress) -> HardwareAddress {
match addr {
#[cfg(feature = "medium-ethernet")]
driver::HardwareAddress::Ethernet(eth) => (HardwareAddress::Ethernet(EthernetAddress(eth)), Medium::Ethernet),
driver::HardwareAddress::Ethernet(eth) => HardwareAddress::Ethernet(EthernetAddress(eth)),
#[cfg(feature = "medium-ieee802154")]
driver::HardwareAddress::Ieee802154(ieee) => (
HardwareAddress::Ieee802154(Ieee802154Address::Extended(ieee)),
Medium::Ieee802154,
),
driver::HardwareAddress::Ieee802154(ieee) => HardwareAddress::Ieee802154(Ieee802154Address::Extended(ieee)),
#[cfg(feature = "medium-ip")]
driver::HardwareAddress::Ip => (HardwareAddress::Ip, Medium::Ip),
driver::HardwareAddress::Ip => HardwareAddress::Ip,
#[allow(unreachable_patterns)]
_ => panic!(
@ -293,8 +289,7 @@ impl<D: Driver> Stack<D> {
resources: &'static mut StackResources<SOCK>,
random_seed: u64,
) -> Self {
let (hardware_addr, medium) = to_smoltcp_hardware_address(device.hardware_address());
let mut iface_cfg = smoltcp::iface::Config::new(hardware_addr);
let mut iface_cfg = smoltcp::iface::Config::new(to_smoltcp_hardware_address(device.hardware_address()));
iface_cfg.random_seed = random_seed;
let iface = Interface::new(
@ -302,7 +297,6 @@ impl<D: Driver> Stack<D> {
&mut DriverAdapter {
inner: &mut device,
cx: None,
medium,
},
instant_to_smoltcp(Instant::now()),
);
@ -362,7 +356,7 @@ impl<D: Driver> Stack<D> {
/// Get the hardware address of the network interface.
pub fn hardware_address(&self) -> HardwareAddress {
self.with(|_s, i| to_smoltcp_hardware_address(i.device.hardware_address()).0)
self.with(|_s, i| to_smoltcp_hardware_address(i.device.hardware_address()))
}
/// Get whether the link is up.
@ -515,10 +509,7 @@ impl<D: Driver> Stack<D> {
self.with_mut(|s, i| {
let socket = s.sockets.get_mut::<dns::Socket>(i.dns_socket);
match socket.start_query(s.iface.context(), name, qtype) {
Ok(handle) => {
s.waker.wake();
Poll::Ready(Ok(handle))
}
Ok(handle) => Poll::Ready(Ok(handle)),
Err(dns::StartQueryError::NoFreeSlot) => {
i.dns_waker.register(cx.waker());
Poll::Pending
@ -818,28 +809,18 @@ impl<D: Driver> Inner<D> {
fn poll(&mut self, cx: &mut Context<'_>, s: &mut SocketStack) {
s.waker.register(cx.waker());
let (_hardware_addr, medium) = to_smoltcp_hardware_address(self.device.hardware_address());
#[cfg(any(feature = "medium-ethernet", feature = "medium-ieee802154"))]
if self.device.capabilities().medium == embassy_net_driver::Medium::Ethernet
|| self.device.capabilities().medium == embassy_net_driver::Medium::Ieee802154
{
let do_set = match medium {
#[cfg(feature = "medium-ethernet")]
Medium::Ethernet => true,
#[cfg(feature = "medium-ieee802154")]
Medium::Ieee802154 => true,
#[allow(unreachable_patterns)]
_ => false,
};
if do_set {
s.iface.set_hardware_addr(_hardware_addr);
}
s.iface
.set_hardware_addr(to_smoltcp_hardware_address(self.device.hardware_address()));
}
let timestamp = instant_to_smoltcp(Instant::now());
let mut smoldev = DriverAdapter {
cx: Some(cx),
inner: &mut self.device,
medium,
};
s.iface.poll(timestamp, &mut smoldev, &mut s.sockets);
@ -860,9 +841,6 @@ impl<D: Driver> Inner<D> {
let socket = s.sockets.get_mut::<dhcpv4::Socket>(dhcp_handle);
if self.link_up {
if old_link_up != self.link_up {
socket.reset();
}
match socket.poll() {
None => {}
Some(dhcpv4::Event::Deconfigured) => {

View File

@ -94,7 +94,7 @@ _gpio-p1 = []
_nrf52832_anomaly_109 = []
[dependencies]
embassy-time = { version = "0.1.5", path = "../embassy-time", optional = true }
embassy-time = { version = "0.1.3", 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" }

View File

@ -6,13 +6,10 @@ pub mod pac {
// To avoid cfg spam, we remove _ns or _s suffixes here.
pub use nrf5340_app_pac::NVIC_PRIO_BITS;
#[cfg(feature="rt")]
#[doc(no_inline)]
pub use nrf5340_app_pac::interrupt;
#[doc(no_inline)]
pub use nrf5340_app_pac::{
interrupt,
Interrupt,
Peripherals,
@ -63,167 +60,156 @@ pub mod pac {
wdt0_ns as wdt0,
};
/// Non-Secure mode (NS) peripherals
pub mod ns {
#[cfg(feature = "nrf5340-app-ns")]
#[doc(no_inline)]
pub use nrf5340_app_pac::{
CLOCK_NS as CLOCK,
COMP_NS as COMP,
CTRLAP_NS as CTRLAP,
DCNF_NS as DCNF,
DPPIC_NS as DPPIC,
EGU0_NS as EGU0,
EGU1_NS as EGU1,
EGU2_NS as EGU2,
EGU3_NS as EGU3,
EGU4_NS as EGU4,
EGU5_NS as EGU5,
FPU_NS as FPU,
GPIOTE1_NS as GPIOTE1,
I2S0_NS as I2S0,
IPC_NS as IPC,
KMU_NS as KMU,
LPCOMP_NS as LPCOMP,
MUTEX_NS as MUTEX,
NFCT_NS as NFCT,
NVMC_NS as NVMC,
OSCILLATORS_NS as OSCILLATORS,
P0_NS as P0,
P1_NS as P1,
PDM0_NS as PDM0,
POWER_NS as POWER,
PWM0_NS as PWM0,
PWM1_NS as PWM1,
PWM2_NS as PWM2,
PWM3_NS as PWM3,
QDEC0_NS as QDEC0,
QDEC1_NS as QDEC1,
QSPI_NS as QSPI,
REGULATORS_NS as REGULATORS,
RESET_NS as RESET,
RTC0_NS as RTC0,
RTC1_NS as RTC1,
SAADC_NS as SAADC,
SPIM0_NS as SPIM0,
SPIM1_NS as SPIM1,
SPIM2_NS as SPIM2,
SPIM3_NS as SPIM3,
SPIM4_NS as SPIM4,
SPIS0_NS as SPIS0,
SPIS1_NS as SPIS1,
SPIS2_NS as SPIS2,
SPIS3_NS as SPIS3,
TIMER0_NS as TIMER0,
TIMER1_NS as TIMER1,
TIMER2_NS as TIMER2,
TWIM0_NS as TWIM0,
TWIM1_NS as TWIM1,
TWIM2_NS as TWIM2,
TWIM3_NS as TWIM3,
TWIS0_NS as TWIS0,
TWIS1_NS as TWIS1,
TWIS2_NS as TWIS2,
TWIS3_NS as TWIS3,
UARTE0_NS as UARTE0,
UARTE1_NS as UARTE1,
UARTE2_NS as UARTE2,
UARTE3_NS as UARTE3,
USBD_NS as USBD,
USBREGULATOR_NS as USBREGULATOR,
VMC_NS as VMC,
WDT0_NS as WDT0,
WDT1_NS as WDT1,
};
}
#[cfg(feature = "nrf5340-app-ns")]
#[doc(no_inline)]
pub use nrf5340_app_pac::{
CLOCK_NS as CLOCK,
COMP_NS as COMP,
CTRLAP_NS as CTRLAP,
DCNF_NS as DCNF,
DPPIC_NS as DPPIC,
EGU0_NS as EGU0,
EGU1_NS as EGU1,
EGU2_NS as EGU2,
EGU3_NS as EGU3,
EGU4_NS as EGU4,
EGU5_NS as EGU5,
FPU_NS as FPU,
GPIOTE1_NS as GPIOTE1,
I2S0_NS as I2S0,
IPC_NS as IPC,
KMU_NS as KMU,
LPCOMP_NS as LPCOMP,
MUTEX_NS as MUTEX,
NFCT_NS as NFCT,
NVMC_NS as NVMC,
OSCILLATORS_NS as OSCILLATORS,
P0_NS as P0,
P1_NS as P1,
PDM0_NS as PDM0,
POWER_NS as POWER,
PWM0_NS as PWM0,
PWM1_NS as PWM1,
PWM2_NS as PWM2,
PWM3_NS as PWM3,
QDEC0_NS as QDEC0,
QDEC1_NS as QDEC1,
QSPI_NS as QSPI,
REGULATORS_NS as REGULATORS,
RESET_NS as RESET,
RTC0_NS as RTC0,
RTC1_NS as RTC1,
SAADC_NS as SAADC,
SPIM0_NS as SPIM0,
SPIM1_NS as SPIM1,
SPIM2_NS as SPIM2,
SPIM3_NS as SPIM3,
SPIM4_NS as SPIM4,
SPIS0_NS as SPIS0,
SPIS1_NS as SPIS1,
SPIS2_NS as SPIS2,
SPIS3_NS as SPIS3,
TIMER0_NS as TIMER0,
TIMER1_NS as TIMER1,
TIMER2_NS as TIMER2,
TWIM0_NS as TWIM0,
TWIM1_NS as TWIM1,
TWIM2_NS as TWIM2,
TWIM3_NS as TWIM3,
TWIS0_NS as TWIS0,
TWIS1_NS as TWIS1,
TWIS2_NS as TWIS2,
TWIS3_NS as TWIS3,
UARTE0_NS as UARTE0,
UARTE1_NS as UARTE1,
UARTE2_NS as UARTE2,
UARTE3_NS as UARTE3,
USBD_NS as USBD,
USBREGULATOR_NS as USBREGULATOR,
VMC_NS as VMC,
WDT0_NS as WDT0,
WDT1_NS as WDT1,
};
/// Secure mode (S) peripherals
pub mod s {
#[cfg(feature = "nrf5340-app-s")]
#[doc(no_inline)]
pub use nrf5340_app_pac::{
CACHEDATA_S as CACHEDATA,
CACHEINFO_S as CACHEINFO,
CACHE_S as CACHE,
CLOCK_S as CLOCK,
COMP_S as COMP,
CRYPTOCELL_S as CRYPTOCELL,
CTI_S as CTI,
CTRLAP_S as CTRLAP,
DCNF_S as DCNF,
DPPIC_S as DPPIC,
EGU0_S as EGU0,
EGU1_S as EGU1,
EGU2_S as EGU2,
EGU3_S as EGU3,
EGU4_S as EGU4,
EGU5_S as EGU5,
FICR_S as FICR,
FPU_S as FPU,
GPIOTE0_S as GPIOTE0,
I2S0_S as I2S0,
IPC_S as IPC,
KMU_S as KMU,
LPCOMP_S as LPCOMP,
MUTEX_S as MUTEX,
NFCT_S as NFCT,
NVMC_S as NVMC,
OSCILLATORS_S as OSCILLATORS,
P0_S as P0,
P1_S as P1,
PDM0_S as PDM0,
POWER_S as POWER,
PWM0_S as PWM0,
PWM1_S as PWM1,
PWM2_S as PWM2,
PWM3_S as PWM3,
QDEC0_S as QDEC0,
QDEC1_S as QDEC1,
QSPI_S as QSPI,
REGULATORS_S as REGULATORS,
RESET_S as RESET,
RTC0_S as RTC0,
RTC1_S as RTC1,
SAADC_S as SAADC,
SPIM0_S as SPIM0,
SPIM1_S as SPIM1,
SPIM2_S as SPIM2,
SPIM3_S as SPIM3,
SPIM4_S as SPIM4,
SPIS0_S as SPIS0,
SPIS1_S as SPIS1,
SPIS2_S as SPIS2,
SPIS3_S as SPIS3,
SPU_S as SPU,
TAD_S as TAD,
TIMER0_S as TIMER0,
TIMER1_S as TIMER1,
TIMER2_S as TIMER2,
TWIM0_S as TWIM0,
TWIM1_S as TWIM1,
TWIM2_S as TWIM2,
TWIM3_S as TWIM3,
TWIS0_S as TWIS0,
TWIS1_S as TWIS1,
TWIS2_S as TWIS2,
TWIS3_S as TWIS3,
UARTE0_S as UARTE0,
UARTE1_S as UARTE1,
UARTE2_S as UARTE2,
UARTE3_S as UARTE3,
UICR_S as UICR,
USBD_S as USBD,
USBREGULATOR_S as USBREGULATOR,
VMC_S as VMC,
WDT0_S as WDT0,
WDT1_S as WDT1,
};
}
#[cfg(feature = "_ns")]
pub use ns::*;
#[cfg(feature = "_s")]
pub use s::*;
#[cfg(feature = "nrf5340-app-s")]
#[doc(no_inline)]
pub use nrf5340_app_pac::{
CACHEDATA_S as CACHEDATA,
CACHEINFO_S as CACHEINFO,
CACHE_S as CACHE,
CLOCK_S as CLOCK,
COMP_S as COMP,
CRYPTOCELL_S as CRYPTOCELL,
CTI_S as CTI,
CTRLAP_S as CTRLAP,
DCNF_S as DCNF,
DPPIC_S as DPPIC,
EGU0_S as EGU0,
EGU1_S as EGU1,
EGU2_S as EGU2,
EGU3_S as EGU3,
EGU4_S as EGU4,
EGU5_S as EGU5,
FICR_S as FICR,
FPU_S as FPU,
GPIOTE0_S as GPIOTE0,
I2S0_S as I2S0,
IPC_S as IPC,
KMU_S as KMU,
LPCOMP_S as LPCOMP,
MUTEX_S as MUTEX,
NFCT_S as NFCT,
NVMC_S as NVMC,
OSCILLATORS_S as OSCILLATORS,
P0_S as P0,
P1_S as P1,
PDM0_S as PDM0,
POWER_S as POWER,
PWM0_S as PWM0,
PWM1_S as PWM1,
PWM2_S as PWM2,
PWM3_S as PWM3,
QDEC0_S as QDEC0,
QDEC1_S as QDEC1,
QSPI_S as QSPI,
REGULATORS_S as REGULATORS,
RESET_S as RESET,
RTC0_S as RTC0,
RTC1_S as RTC1,
SAADC_S as SAADC,
SPIM0_S as SPIM0,
SPIM1_S as SPIM1,
SPIM2_S as SPIM2,
SPIM3_S as SPIM3,
SPIM4_S as SPIM4,
SPIS0_S as SPIS0,
SPIS1_S as SPIS1,
SPIS2_S as SPIS2,
SPIS3_S as SPIS3,
SPU_S as SPU,
TAD_S as TAD,
TIMER0_S as TIMER0,
TIMER1_S as TIMER1,
TIMER2_S as TIMER2,
TWIM0_S as TWIM0,
TWIM1_S as TWIM1,
TWIM2_S as TWIM2,
TWIM3_S as TWIM3,
TWIS0_S as TWIS0,
TWIS1_S as TWIS1,
TWIS2_S as TWIS2,
TWIS3_S as TWIS3,
UARTE0_S as UARTE0,
UARTE1_S as UARTE1,
UARTE2_S as UARTE2,
UARTE3_S as UARTE3,
UICR_S as UICR,
USBD_S as USBD,
USBREGULATOR_S as USBREGULATOR,
VMC_S as VMC,
WDT0_S as WDT0,
WDT1_S as WDT1,
};
}
/// The maximum buffer size that the EasyDMA can send/recv in one operation.

View File

@ -7,12 +7,9 @@ pub mod pac {
pub use nrf5340_net_pac::NVIC_PRIO_BITS;
#[cfg(feature="rt")]
#[doc(no_inline)]
pub use nrf5340_net_pac::interrupt;
#[doc(no_inline)]
pub use nrf5340_net_pac::{
interrupt,
Interrupt,
Peripherals,

View File

@ -7,12 +7,9 @@ pub mod pac {
pub use nrf9160_pac::NVIC_PRIO_BITS;
#[cfg(feature="rt")]
#[doc(no_inline)]
pub use nrf9160_pac::interrupt;
#[doc(no_inline)]
pub use nrf9160_pac::{
interrupt,
Interrupt,
cc_host_rgf_s as cc_host_rgf,
@ -48,131 +45,122 @@ pub mod pac {
wdt_ns as wdt,
};
/// Non-Secure mode (NS) peripherals
pub mod ns {
#[doc(no_inline)]
pub use nrf9160_pac::{
CLOCK_NS as CLOCK,
DPPIC_NS as DPPIC,
EGU0_NS as EGU0,
EGU1_NS as EGU1,
EGU2_NS as EGU2,
EGU3_NS as EGU3,
EGU4_NS as EGU4,
EGU5_NS as EGU5,
FPU_NS as FPU,
GPIOTE1_NS as GPIOTE1,
I2S_NS as I2S,
IPC_NS as IPC,
KMU_NS as KMU,
NVMC_NS as NVMC,
P0_NS as P0,
PDM_NS as PDM,
POWER_NS as POWER,
PWM0_NS as PWM0,
PWM1_NS as PWM1,
PWM2_NS as PWM2,
PWM3_NS as PWM3,
REGULATORS_NS as REGULATORS,
RTC0_NS as RTC0,
RTC1_NS as RTC1,
SAADC_NS as SAADC,
SPIM0_NS as SPIM0,
SPIM1_NS as SPIM1,
SPIM2_NS as SPIM2,
SPIM3_NS as SPIM3,
SPIS0_NS as SPIS0,
SPIS1_NS as SPIS1,
SPIS2_NS as SPIS2,
SPIS3_NS as SPIS3,
TIMER0_NS as TIMER0,
TIMER1_NS as TIMER1,
TIMER2_NS as TIMER2,
TWIM0_NS as TWIM0,
TWIM1_NS as TWIM1,
TWIM2_NS as TWIM2,
TWIM3_NS as TWIM3,
TWIS0_NS as TWIS0,
TWIS1_NS as TWIS1,
TWIS2_NS as TWIS2,
TWIS3_NS as TWIS3,
UARTE0_NS as UARTE0,
UARTE1_NS as UARTE1,
UARTE2_NS as UARTE2,
UARTE3_NS as UARTE3,
VMC_NS as VMC,
WDT_NS as WDT,
};
}
#[cfg(feature = "nrf9160-ns")]
#[doc(no_inline)]
pub use nrf9160_pac::{
CLOCK_NS as CLOCK,
DPPIC_NS as DPPIC,
EGU0_NS as EGU0,
EGU1_NS as EGU1,
EGU2_NS as EGU2,
EGU3_NS as EGU3,
EGU4_NS as EGU4,
EGU5_NS as EGU5,
FPU_NS as FPU,
GPIOTE1_NS as GPIOTE1,
I2S_NS as I2S,
IPC_NS as IPC,
KMU_NS as KMU,
NVMC_NS as NVMC,
P0_NS as P0,
PDM_NS as PDM,
POWER_NS as POWER,
PWM0_NS as PWM0,
PWM1_NS as PWM1,
PWM2_NS as PWM2,
PWM3_NS as PWM3,
REGULATORS_NS as REGULATORS,
RTC0_NS as RTC0,
RTC1_NS as RTC1,
SAADC_NS as SAADC,
SPIM0_NS as SPIM0,
SPIM1_NS as SPIM1,
SPIM2_NS as SPIM2,
SPIM3_NS as SPIM3,
SPIS0_NS as SPIS0,
SPIS1_NS as SPIS1,
SPIS2_NS as SPIS2,
SPIS3_NS as SPIS3,
TIMER0_NS as TIMER0,
TIMER1_NS as TIMER1,
TIMER2_NS as TIMER2,
TWIM0_NS as TWIM0,
TWIM1_NS as TWIM1,
TWIM2_NS as TWIM2,
TWIM3_NS as TWIM3,
TWIS0_NS as TWIS0,
TWIS1_NS as TWIS1,
TWIS2_NS as TWIS2,
TWIS3_NS as TWIS3,
UARTE0_NS as UARTE0,
UARTE1_NS as UARTE1,
UARTE2_NS as UARTE2,
UARTE3_NS as UARTE3,
VMC_NS as VMC,
WDT_NS as WDT,
};
/// Secure mode (S) peripherals
pub mod s {
#[doc(no_inline)]
pub use nrf9160_pac::{
CC_HOST_RGF_S as CC_HOST_RGF,
CLOCK_S as CLOCK,
CRYPTOCELL_S as CRYPTOCELL,
CTRL_AP_PERI_S as CTRL_AP_PERI,
DPPIC_S as DPPIC,
EGU0_S as EGU0,
EGU1_S as EGU1,
EGU2_S as EGU2,
EGU3_S as EGU3,
EGU4_S as EGU4,
EGU5_S as EGU5,
FICR_S as FICR,
FPU_S as FPU,
GPIOTE0_S as GPIOTE0,
I2S_S as I2S,
IPC_S as IPC,
KMU_S as KMU,
NVMC_S as NVMC,
P0_S as P0,
PDM_S as PDM,
POWER_S as POWER,
PWM0_S as PWM0,
PWM1_S as PWM1,
PWM2_S as PWM2,
PWM3_S as PWM3,
REGULATORS_S as REGULATORS,
RTC0_S as RTC0,
RTC1_S as RTC1,
SAADC_S as SAADC,
SPIM0_S as SPIM0,
SPIM1_S as SPIM1,
SPIM2_S as SPIM2,
SPIM3_S as SPIM3,
SPIS0_S as SPIS0,
SPIS1_S as SPIS1,
SPIS2_S as SPIS2,
SPIS3_S as SPIS3,
SPU_S as SPU,
TAD_S as TAD,
TIMER0_S as TIMER0,
TIMER1_S as TIMER1,
TIMER2_S as TIMER2,
TWIM0_S as TWIM0,
TWIM1_S as TWIM1,
TWIM2_S as TWIM2,
TWIM3_S as TWIM3,
TWIS0_S as TWIS0,
TWIS1_S as TWIS1,
TWIS2_S as TWIS2,
TWIS3_S as TWIS3,
UARTE0_S as UARTE0,
UARTE1_S as UARTE1,
UARTE2_S as UARTE2,
UARTE3_S as UARTE3,
UICR_S as UICR,
VMC_S as VMC,
WDT_S as WDT,
};
}
#[cfg(feature = "_ns")]
pub use ns::*;
#[cfg(feature = "_s")]
pub use s::*;
#[cfg(feature = "nrf9160-s")]
#[doc(no_inline)]
pub use nrf9160_pac::{
CC_HOST_RGF_S as CC_HOST_RGF,
CLOCK_S as CLOCK,
CRYPTOCELL_S as CRYPTOCELL,
CTRL_AP_PERI_S as CTRL_AP_PERI,
DPPIC_S as DPPIC,
EGU0_S as EGU0,
EGU1_S as EGU1,
EGU2_S as EGU2,
EGU3_S as EGU3,
EGU4_S as EGU4,
EGU5_S as EGU5,
FICR_S as FICR,
FPU_S as FPU,
GPIOTE0_S as GPIOTE0,
I2S_S as I2S,
IPC_S as IPC,
KMU_S as KMU,
NVMC_S as NVMC,
P0_S as P0,
PDM_S as PDM,
POWER_S as POWER,
PWM0_S as PWM0,
PWM1_S as PWM1,
PWM2_S as PWM2,
PWM3_S as PWM3,
REGULATORS_S as REGULATORS,
RTC0_S as RTC0,
RTC1_S as RTC1,
SAADC_S as SAADC,
SPIM0_S as SPIM0,
SPIM1_S as SPIM1,
SPIM2_S as SPIM2,
SPIM3_S as SPIM3,
SPIS0_S as SPIS0,
SPIS1_S as SPIS1,
SPIS2_S as SPIS2,
SPIS3_S as SPIS3,
SPU_S as SPU,
TAD_S as TAD,
TIMER0_S as TIMER0,
TIMER1_S as TIMER1,
TIMER2_S as TIMER2,
TWIM0_S as TWIM0,
TWIM1_S as TWIM1,
TWIM2_S as TWIM2,
TWIM3_S as TWIM3,
TWIS0_S as TWIS0,
TWIS1_S as TWIS1,
TWIS2_S as TWIS2,
TWIS3_S as TWIS3,
UARTE0_S as UARTE0,
UARTE1_S as UARTE1,
UARTE2_S as UARTE2,
UARTE3_S as UARTE3,
UICR_S as UICR,
VMC_S as VMC,
WDT_S as WDT,
};
}
/// The maximum buffer size that the EasyDMA can send/recv in one operation.

View File

@ -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.5", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] }
embassy-time = { version = "0.1.3", path = "../embassy-time", features = [ "tick-hz-1_000_000" ] }
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
embassy-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" }

View File

@ -213,7 +213,6 @@ impl<'d> Adc<'d, Async> {
ch: &mut Channel<'_>,
buf: &mut [W],
fcs_err: bool,
div: u16,
dma: impl Peripheral<P = impl dma::Channel>,
) -> Result<(), Error> {
let r = Self::regs();
@ -259,7 +258,6 @@ impl<'d> Adc<'d, Async> {
// start conversions and wait for dma to finish. we can't report errors early
// because there's no interrupt to signal them, and inspecting every element
// of the fifo is too costly to do here.
r.div().write_set(|w| w.set_int(div));
r.cs().write_set(|w| w.set_start_many(true));
dma.await;
mem::drop(auto_reset);
@ -277,10 +275,9 @@ impl<'d> Adc<'d, Async> {
&mut self,
ch: &mut Channel<'_>,
buf: &mut [S],
div: u16,
dma: impl Peripheral<P = impl dma::Channel>,
) -> Result<(), Error> {
self.read_many_inner(ch, buf, false, div, dma).await
self.read_many_inner(ch, buf, false, dma).await
}
#[inline]
@ -288,12 +285,11 @@ impl<'d> Adc<'d, Async> {
&mut self,
ch: &mut Channel<'_>,
buf: &mut [Sample],
div: u16,
dma: impl Peripheral<P = impl dma::Channel>,
) {
// errors are reported in individual samples
let _ = self
.read_many_inner(ch, unsafe { mem::transmute::<_, &mut [u16]>(buf) }, true, div, dma)
.read_many_inner(ch, unsafe { mem::transmute::<_, &mut [u16]>(buf) }, true, dma)
.await;
}
}

View File

@ -10,39 +10,16 @@ use crate::gpio::sealed::Pin as _;
use crate::gpio::{AnyPin, Pin as GpioPin};
use crate::{pac, peripherals, RegExt};
/// The configuration of a PWM slice.
/// Note the period in clock cycles of a slice can be computed as:
/// `(top + 1) * (phase_correct ? 1 : 2) * divider`
#[non_exhaustive]
#[derive(Clone)]
pub struct Config {
/// Inverts the PWM output signal on channel A.
pub invert_a: bool,
/// Inverts the PWM output signal on channel B.
pub invert_b: bool,
/// Enables phase-correct mode for PWM operation.
/// In phase-correct mode, the PWM signal is generated in such a way that
/// the pulse is always centered regardless of the duty cycle.
/// The output frequency is halved when phase-correct mode is enabled.
pub phase_correct: bool,
/// Enables the PWM slice, allowing it to generate an output.
pub enable: bool,
/// A fractional clock divider, represented as a fixed-point number with
/// 8 integer bits and 4 fractional bits. It allows precise control over
/// the PWM output frequency by gating the PWM counter increment.
/// A higher value will result in a slower output frequency.
pub divider: fixed::FixedU16<fixed::types::extra::U4>,
/// The output on channel A goes high when `compare_a` is higher than the
/// counter. A compare of 0 will produce an always low output, while a
/// compare of `top + 1` will produce an always high output.
pub compare_a: u16,
/// The output on channel B goes high when `compare_b` is higher than the
/// counter. A compare of 0 will produce an always low output, while a
/// compare of `top + 1` will produce an always high output.
pub compare_b: u16,
/// The point at which the counter wraps, representing the maximum possible
/// period. The counter will either wrap to 0 or reverse depending on the
/// setting of `phase_correct`.
pub top: u16,
}
@ -196,9 +173,6 @@ impl<'d, T: Channel> Pwm<'d, T> {
});
}
/// Advances a slices output phase by one count while it is running
/// by inserting a pulse into the clock enable. The counter
/// will not count faster than once per cycle.
#[inline]
pub fn phase_advance(&mut self) {
let p = self.inner.regs();
@ -206,9 +180,6 @@ impl<'d, T: Channel> Pwm<'d, T> {
while p.csr().read().ph_adv() {}
}
/// Retards a slices output phase by one count while it is running
/// by deleting a pulse from the clock enable. The counter will not
/// count backward when clock enable is permenantly low.
#[inline]
pub fn phase_retard(&mut self) {
let p = self.inner.regs();

View File

@ -5,7 +5,7 @@ use core::task::Poll;
use atomic_polyfill::{AtomicU8, Ordering};
use embassy_hal_internal::atomic_ring_buffer::RingBuffer;
use embassy_sync::waitqueue::AtomicWaker;
use embassy_time::Timer;
use embassy_time::{Duration, Timer};
use super::*;
use crate::clocks::clk_peri_freq;
@ -435,7 +435,7 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
Self::flush().await.unwrap();
while self.busy() {}
regs.uartlcr_h().write_set(|w| w.set_brk(true));
Timer::after_micros(wait_usecs).await;
Timer::after(Duration::from_micros(wait_usecs)).await;
regs.uartlcr_h().write_clear(|w| w.set_brk(true));
}
}

View File

@ -6,7 +6,7 @@ use atomic_polyfill::{AtomicU16, Ordering};
use embassy_futures::select::{select, Either};
use embassy_hal_internal::{into_ref, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker;
use embassy_time::Timer;
use embassy_time::{Duration, Timer};
use pac::uart::regs::Uartris;
use crate::clocks::clk_peri_freq;
@ -187,7 +187,7 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> {
self.blocking_flush().unwrap();
while self.busy() {}
regs.uartlcr_h().write_set(|w| w.set_brk(true));
Timer::after_micros(wait_usecs).await;
Timer::after(Duration::from_micros(wait_usecs)).await;
regs.uartlcr_h().write_clear(|w| w.set_brk(true));
}
}

View File

@ -13,11 +13,11 @@ 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.5", path = "../embassy-time", optional = true }
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
embassy-hal-internal = { version = "0.1.0", path = "../embassy-hal-internal" }
embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" }
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver", optional=true }
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver", optional=true }
defmt = { version = "0.3", optional = true }
cortex-m = "0.7.6"

View File

@ -3,7 +3,7 @@
use core::task::Context;
use embassy_net_driver::{Capabilities, HardwareAddress, LinkState};
use embassy_net_driver::{Capabilities, HardwareAddress, LinkState, Medium};
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::channel::Channel;
@ -60,15 +60,24 @@ impl<'d> embassy_net_driver::Driver for Driver<'d> {
let mut caps = Capabilities::default();
caps.max_transmission_unit = MTU;
// caps.max_burst_size = Some(self.tx.len());
caps.medium = Medium::Ieee802154;
caps
}
fn link_state(&mut self, _cx: &mut Context) -> LinkState {
// if self.phy.poll_link(&mut self.station_management, cx) {
// LinkState::Up
// } else {
// LinkState::Down
// }
LinkState::Down
}
fn hardware_address(&self) -> HardwareAddress {
// self.mac_addr
HardwareAddress::Ieee802154([0; 8])
}
}

View File

@ -33,11 +33,11 @@ flavors = [
[dependencies]
embassy-sync = { version = "0.3.0", path = "../embassy-sync" }
embassy-time = { version = "0.1.5", path = "../embassy-time", optional = true }
embassy-time = { version = "0.1.3", path = "../embassy-time", optional = true }
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
embassy-hal-internal = {version = "0.1.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-4"] }
embassy-embedded-hal = {version = "0.1.0", path = "../embassy-embedded-hal" }
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver" }
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
embassy-usb-driver = {version = "0.1.0", path = "../embassy-usb-driver", optional = true }
embassy-executor = { version = "0.3.0", path = "../embassy-executor", optional = true }
@ -58,7 +58,7 @@ 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"
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-bcc9b6bf9fa195e91625849efc4ba473d9ace4e9" }
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-6bfa5a0dcec6a9bd42cea94ba11eeae1a17a7f2c" }
vcell = "0.1.3"
bxcan = "0.7.0"
nb = "1.0.0"
@ -76,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-bcc9b6bf9fa195e91625849efc4ba473d9ace4e9", default-features = false, features = ["metadata"]}
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-6bfa5a0dcec6a9bd42cea94ba11eeae1a17a7f2c", default-features = false, features = ["metadata"]}
[features]

View File

@ -1,11 +1,11 @@
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::collections::{HashMap, HashSet};
use std::fmt::Write as _;
use std::path::PathBuf;
use std::{env, fs};
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};
use stm32_metapac::metadata::ir::{BlockItemInner, Enum, FieldSet};
use stm32_metapac::metadata::ir::{BlockItemInner, Enum};
use stm32_metapac::metadata::{MemoryRegionKind, PeripheralRccRegister, METADATA};
fn main() {
@ -352,7 +352,7 @@ fn main() {
// ========
// Generate DMA IRQs.
let mut dma_irqs: BTreeMap<&str, Vec<(&str, &str, &str)>> = BTreeMap::new();
let mut dma_irqs: HashMap<&str, Vec<(&str, &str, &str)>> = HashMap::new();
for p in METADATA.peripherals {
if let Some(r) = &p.registers {
@ -371,59 +371,58 @@ fn main() {
}
}
let dma_irqs: TokenStream = dma_irqs
.iter()
.map(|(irq, channels)| {
let irq = format_ident!("{}", irq);
for (irq, channels) in dma_irqs {
let irq = format_ident!("{}", irq);
let xdma = format_ident!("{}", channels[0].0);
let channels = channels.iter().map(|(_, dma, ch)| format_ident!("{}_{}", dma, ch));
let xdma = format_ident!("{}", channels[0].0);
let channels = channels.iter().map(|(_, dma, ch)| format_ident!("{}_{}", dma, ch));
quote! {
#[cfg(feature = "rt")]
#[crate::interrupt]
unsafe fn #irq () {
#(
<crate::peripherals::#channels as crate::dma::#xdma::sealed::Channel>::on_irq();
)*
}
g.extend(quote! {
#[cfg(feature = "rt")]
#[crate::interrupt]
unsafe fn #irq () {
#(
<crate::peripherals::#channels as crate::dma::#xdma::sealed::Channel>::on_irq();
)*
}
})
.collect();
g.extend(dma_irqs);
// ========
// Extract the rcc registers
let rcc_registers = METADATA
.peripherals
.iter()
.filter_map(|p| p.registers.as_ref())
.find(|r| r.kind == "rcc")
.unwrap();
});
}
// ========
// Generate rcc fieldset and enum maps
let rcc_enum_map: HashMap<&str, HashMap<&str, &Enum>> = {
let rcc_blocks = rcc_registers.ir.blocks.iter().find(|b| b.name == "Rcc").unwrap().items;
let rcc_fieldsets: HashMap<&str, &FieldSet> = rcc_registers.ir.fieldsets.iter().map(|f| (f.name, f)).collect();
let rcc_enums: HashMap<&str, &Enum> = rcc_registers.ir.enums.iter().map(|e| (e.name, e)).collect();
let rcc_registers = METADATA
.peripherals
.iter()
.filter_map(|p| p.registers.as_ref())
.find(|r| r.kind == "rcc")
.unwrap()
.ir;
rcc_blocks
let rcc_blocks = rcc_registers.blocks.iter().find(|b| b.name == "Rcc").unwrap().items;
let rcc_block_item_map: HashMap<&str, &str> = rcc_blocks
.iter()
.filter_map(|b| match &b.inner {
BlockItemInner::Register(register) => register.fieldset.map(|f| (b.name, f)),
BlockItemInner::Register(register) => register.fieldset.map(|f| (f, b.name)),
_ => None,
})
.filter_map(|(b, f)| {
rcc_fieldsets.get(f).map(|f| {
.collect();
let rcc_enum_map: HashMap<&str, &Enum> = rcc_registers.enums.iter().map(|e| (e.name, e)).collect();
rcc_registers
.fieldsets
.iter()
.filter_map(|f| {
rcc_block_item_map.get(f.name).map(|b| {
(
b,
*b,
f.fields
.iter()
.filter_map(|f| {
let enumm = f.enumm?;
let enumm = rcc_enums.get(enumm)?;
let enumm = rcc_enum_map.get(enumm)?;
Some((f.name, *enumm))
})
@ -438,7 +437,7 @@ fn main() {
// Generate RccPeripheral impls
let refcounted_peripherals = HashSet::from(["usart", "adc"]);
let mut refcount_statics = BTreeSet::new();
let mut refcount_statics = HashSet::new();
for p in METADATA.peripherals {
if !singletons.contains(&p.name.to_string()) {
@ -453,8 +452,10 @@ 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! {
crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true));
crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false));
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));
});
}
}
None => TokenStream::new(),
@ -471,9 +472,9 @@ fn main() {
let ptype = if let Some(reg) = &p.registers { reg.kind } else { "" };
let pname = format_ident!("{}", p.name);
let clk = format_ident!("{}", rcc.clock);
let en_reg = format_ident!("{}", en.register);
let set_en_field = format_ident!("set_{}", en.field);
let clk = format_ident!("{}", rcc.clock.to_ascii_lowercase());
let en_reg = format_ident!("{}", en.register.to_ascii_lowercase());
let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase());
let (before_enable, before_disable) = if refcounted_peripherals.contains(ptype) {
let refcount_static =
@ -499,11 +500,9 @@ fn main() {
(TokenStream::new(), TokenStream::new())
};
let mux_supported = HashSet::from(["c0", "h5", "h50", "h7", "h7ab", "h7rm0433", "g4", "l4"])
.contains(rcc_registers.version);
let mux_for = |mux: Option<&'static PeripheralRccRegister>| {
// restrict mux implementation to supported versions
if !mux_supported {
// temporary hack to restrict the scope of the implementation to h5
if !&chip_name.starts_with("stm32h5") {
return None;
}
@ -526,16 +525,12 @@ fn main() {
.filter(|v| v.name != "DISABLE")
.map(|v| {
let variant_name = format_ident!("{}", v.name);
let clock_name = format_ident!("{}", v.name.to_ascii_lowercase());
if v.name.starts_with("HCLK") || v.name.starts_with("PCLK") || v.name == "SYS" {
quote! {
#enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name },
}
} else {
quote! {
#enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name.unwrap() },
}
// temporary hack to restrict the scope of the implementation until clock names can be stabilized
let clock_name = format_ident!("mux_{}", v.name.to_ascii_lowercase());
quote! {
#enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name.unwrap() },
}
})
.collect();
@ -561,19 +556,25 @@ fn main() {
fn frequency() -> crate::time::Hertz {
#clock_frequency
}
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 enable() {
critical_section::with(|_cs| {
#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
})
}
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);
fn disable() {
critical_section::with(|_cs| {
#before_disable
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false));
#[cfg(feature = "low-power")]
crate::rcc::clock_refcount_sub(_cs);
})
}
fn reset() {
#rst
}
}
@ -1019,7 +1020,15 @@ fn main() {
// ========
// Generate Div/Mul impls for RCC prescalers/dividers/multipliers.
for e in rcc_registers.ir.enums {
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,

View File

@ -51,7 +51,8 @@ impl<T: Instance> super::sealed::AdcPin<T> for Temperature {
impl<'d, T: Instance> Adc<'d, T> {
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
into_ref!(adc);
T::enable_and_reset();
T::enable();
T::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)

View File

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

View File

@ -74,9 +74,9 @@ pub(crate) mod sealed {
}
}
#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_g0)))]
#[cfg(not(any(adc_f1, adc_v1, adc_v2, adc_v4, adc_f3)))]
pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> {}
#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v3, adc_v4, adc_f3, adc_g0))]
#[cfg(any(adc_f1, adc_v1, adc_v2, adc_v4, adc_f3))]
pub trait Instance: sealed::Instance + crate::Peripheral<P = Self> + crate::rcc::RccPeripheral {}
pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {}

View File

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

View File

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

View File

@ -9,6 +9,19 @@ pub const VREF_DEFAULT_MV: u32 = 3300;
/// VREF voltage used for factory calibration of VREFINTCAL register.
pub const VREF_CALIB_MV: u32 = 3000;
/// Sadly we cannot use `RccPeripheral::enable` since devices are quite inconsistent ADC clock
/// configuration.
fn enable() {
critical_section::with(|_| {
#[cfg(any(stm32h7, stm32wl))]
crate::pac::RCC.apb2enr().modify(|w| w.set_adcen(true));
#[cfg(stm32g0)]
crate::pac::RCC.apbenr2().modify(|w| w.set_adcen(true));
#[cfg(any(stm32l4, stm32l5, stm32wb))]
crate::pac::RCC.ahb2enr().modify(|w| w.set_adcen(true));
});
}
pub struct VrefInt;
impl<T: Instance> AdcPin<T> for VrefInt {}
impl<T: Instance> super::sealed::AdcPin<T> for VrefInt {
@ -48,7 +61,7 @@ impl<T: Instance> super::sealed::AdcPin<T> for Vbat {
impl<'d, T: Instance> Adc<'d, T> {
pub fn new(adc: impl Peripheral<P = T> + 'd, delay: &mut impl DelayUs<u32>) -> Self {
into_ref!(adc);
T::enable_and_reset();
enable();
T::regs().cr().modify(|reg| {
#[cfg(not(adc_g0))]
reg.set_deeppwd(false);

View File

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

View File

@ -136,7 +136,8 @@ 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_and_reset();
T::enable();
T::reset();
{
use crate::pac::can::vals::{Errie, Fmpie, Tmeie};

View File

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

View File

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

View File

@ -255,7 +255,8 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
) -> Self {
pin.set_as_analog();
into_ref!(peri, dma);
T::enable_and_reset();
T::enable();
T::reset();
let mut dac = Self { _peri: peri, dma };
@ -365,7 +366,8 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
) -> Self {
pin.set_as_analog();
into_ref!(_peri, dma);
T::enable_and_reset();
T::enable();
T::reset();
let mut dac = Self {
phantom: PhantomData,
@ -481,7 +483,8 @@ 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_and_reset();
T::enable();
T::reset();
let mut dac_ch1 = DacCh1 {
_peri: peri,
@ -560,26 +563,35 @@ pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
foreach_peripheral!(
(dac, $inst:ident) => {
// H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented
#[cfg(any(rcc_h7, rcc_h7rm0433))]
impl crate::rcc::sealed::RccPeripheral for peripherals::$inst {
fn frequency() -> crate::time::Hertz {
critical_section::with(|_| unsafe { crate::rcc::get_freqs().pclk1 })
}
// 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 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 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 disable_with_cs(_cs: critical_section::CriticalSection) {
crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false))
}
}
fn enable() {
critical_section::with(|_| {
crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true));
})
}
#[cfg(any(rcc_h7, rcc_h7rm0433))]
impl crate::rcc::RccPeripheral for peripherals::$inst {}
fn disable() {
critical_section::with(|_| {
crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false))
})
}
}
#[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 {

View File

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

View File

@ -77,10 +77,10 @@ impl State {
static STATE: State = State::new();
/// safety: must be called only once
pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: Priority) {
pub(crate) unsafe fn init(irq_priority: Priority) {
foreach_interrupt! {
($peri:ident, bdma, $block:ident, $signal_name:ident, $irq:ident) => {
crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, irq_priority);
crate::interrupt::typelevel::$irq::set_priority(irq_priority);
crate::interrupt::typelevel::$irq::enable();
};
}

View File

@ -154,10 +154,10 @@ impl State {
static STATE: State = State::new();
/// safety: must be called only once
pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: Priority) {
pub(crate) unsafe fn init(irq_priority: Priority) {
foreach_interrupt! {
($peri:ident, dma, $block:ident, $signal_name:ident, $irq:ident) => {
interrupt::typelevel::$irq::set_priority_with_cs(cs, irq_priority);
interrupt::typelevel::$irq::set_priority(irq_priority);
interrupt::typelevel::$irq::enable();
};
}

View File

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

View File

@ -53,10 +53,10 @@ impl State {
static STATE: State = State::new();
/// safety: must be called only once
pub(crate) unsafe fn init(cs: critical_section::CriticalSection, irq_priority: Priority) {
pub(crate) unsafe fn init(irq_priority: Priority) {
foreach_interrupt! {
($peri:ident, gpdma, $block:ident, $signal_name:ident, $irq:ident) => {
crate::interrupt::typelevel::$irq::set_priority_with_cs(cs, irq_priority);
crate::interrupt::typelevel::$irq::set_priority(irq_priority);
crate::interrupt::typelevel::$irq::enable();
};
}

View File

@ -56,17 +56,16 @@ pub(crate) fn slice_ptr_parts_mut<T>(slice: *mut [T]) -> (usize, usize) {
// safety: must be called only once at startup
pub(crate) unsafe fn init(
cs: critical_section::CriticalSection,
#[cfg(bdma)] bdma_priority: Priority,
#[cfg(dma)] dma_priority: Priority,
#[cfg(gpdma)] gpdma_priority: Priority,
) {
#[cfg(bdma)]
bdma::init(cs, bdma_priority);
bdma::init(bdma_priority);
#[cfg(dma)]
dma::init(cs, dma_priority);
dma::init(dma_priority);
#[cfg(gpdma)]
gpdma::init(cs, gpdma_priority);
gpdma::init(gpdma_priority);
#[cfg(dmamux)]
dmamux::init(cs);
dmamux::init();
}

View File

@ -191,7 +191,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
// TODO MTU size setting not found for v1 ethernet, check if correct
// NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called
let hclk = unsafe { crate::rcc::get_freqs() }.hclk1;
let hclk = unsafe { crate::rcc::get_freqs() }.ahb1;
let hclk_mhz = hclk.0 / 1_000_000;
// Set the MDC clock frequency in the range 1MHz - 2.5MHz

View File

@ -164,7 +164,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
});
// NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called
let hclk = unsafe { crate::rcc::get_freqs() }.hclk1;
let hclk = unsafe { crate::rcc::get_freqs() }.ahb1;
let hclk_mhz = hclk.0 / 1_000_000;
// Set the MDC clock frequency in the range 1MHz - 2.5MHz

View File

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

View File

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

View File

@ -1,7 +1,6 @@
#![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};
@ -758,18 +757,11 @@ foreach_pin!(
};
);
pub(crate) unsafe fn init(_cs: CriticalSection) {
pub(crate) unsafe fn init() {
#[cfg(afio)]
<crate::peripherals::AFIO as crate::rcc::sealed::RccPeripheral>::enable_and_reset_with_cs(_cs);
<crate::peripherals::AFIO as crate::rcc::sealed::RccPeripheral>::enable();
crate::_generated::init_gpio();
// Setting this bit is mandatory to use PG[15:2].
#[cfg(stm32u5)]
crate::pac::PWR.svmcr().modify(|w| {
w.set_io2sv(true);
w.set_io2vmen(true);
});
}
mod eh02 {

View File

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

View File

@ -7,6 +7,11 @@ use crate::interrupt;
mod _version;
pub use _version::*;
#[cfg(feature = "time")]
mod timeout;
#[cfg(feature = "time")]
pub use timeout::*;
use crate::peripherals;
#[derive(Debug, PartialEq, Eq)]

View File

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

View File

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

View File

@ -1,21 +1,14 @@
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;
#[cfg(feature = "time")]
use crate::dma::Transfer;
use crate::dma::{NoDma, Transfer};
use crate::gpio::sealed::AFType;
use crate::gpio::Pull;
use crate::i2c::{Error, Instance, SclPin, SdaPin};
@ -50,8 +43,6 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
pub struct Config {
pub sda_pullup: bool,
pub scl_pullup: bool,
#[cfg(feature = "time")]
pub transaction_timeout: Duration,
}
impl Default for Config {
@ -59,8 +50,6 @@ impl Default for Config {
Self {
sda_pullup: false,
scl_pullup: false,
#[cfg(feature = "time")]
transaction_timeout: Duration::from_millis(100),
}
}
}
@ -79,12 +68,9 @@ 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> {
@ -100,7 +86,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
) -> Self {
into_ref!(peri, scl, sda, tx_dma, rx_dma);
T::enable_and_reset();
T::enable();
T::reset();
scl.set_as_af_pull(
scl.af_num(),
@ -145,8 +132,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
_peri: peri,
tx_dma,
rx_dma,
#[cfg(feature = "time")]
timeout: config.transaction_timeout,
}
}
@ -437,7 +422,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
result
}
#[cfg(feature = "time")]
async fn write_dma_internal(
&mut self,
address: u8,
@ -528,7 +512,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
Ok(())
}
#[cfg(feature = "time")]
async fn read_dma_internal(
&mut self,
address: u8,
@ -611,41 +594,42 @@ 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<T>,
{
self.write_timeout(address, write, self.timeout).await
self.write_timeout(address, write, || Ok(())).await
}
#[cfg(feature = "time")]
pub async fn write_timeout(&mut self, address: u8, write: &[u8], timeout: Duration) -> Result<(), Error>
pub async fn write_timeout(
&mut self,
address: u8,
write: &[u8],
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error>
where
TXDMA: crate::i2c::TxDma<T>,
{
if write.is_empty() {
self.write_internal(address, write, true, timeout_fn(timeout))
self.write_internal(address, write, true, check_timeout)
} else {
embassy_time::with_timeout(
timeout,
self.write_dma_internal(address, write, true, true, timeout_fn(timeout)),
)
.await
.unwrap_or(Err(Error::Timeout))
self.write_dma_internal(address, write, true, true, check_timeout).await
}
}
#[cfg(feature = "time")]
pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error>
where
TXDMA: crate::i2c::TxDma<T>,
{
self.write_vectored_timeout(address, write, self.timeout).await
self.write_vectored_timeout(address, write, || Ok(())).await
}
#[cfg(feature = "time")]
pub async fn write_vectored_timeout(&mut self, address: u8, write: &[&[u8]], timeout: Duration) -> Result<(), Error>
pub async fn write_vectored_timeout(
&mut self,
address: u8,
write: &[&[u8]],
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error>
where
TXDMA: crate::i2c::TxDma<T>,
{
@ -660,88 +644,67 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
let next = iter.next();
let is_last = next.is_none();
embassy_time::with_timeout(
timeout,
self.write_dma_internal(address, c, first, is_last, timeout_fn(timeout)),
)
.await
.unwrap_or(Err(Error::Timeout))?;
self.write_dma_internal(address, c, first, is_last, || check_timeout())
.await?;
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<T>,
{
self.read_timeout(address, buffer, self.timeout).await
self.read_timeout(address, buffer, || Ok(())).await
}
#[cfg(feature = "time")]
pub async fn read_timeout(&mut self, address: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error>
pub async fn read_timeout(
&mut self,
address: u8,
buffer: &mut [u8],
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error>
where
RXDMA: crate::i2c::RxDma<T>,
{
if buffer.is_empty() {
self.read_internal(address, buffer, false, timeout_fn(timeout))
self.read_internal(address, buffer, false, check_timeout)
} else {
embassy_time::with_timeout(
timeout,
self.read_dma_internal(address, buffer, false, timeout_fn(timeout)),
)
.await
.unwrap_or(Err(Error::Timeout))
self.read_dma_internal(address, buffer, false, check_timeout).await
}
}
#[cfg(feature = "time")]
pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error>
where
TXDMA: super::TxDma<T>,
RXDMA: super::RxDma<T>,
{
self.write_read_timeout(address, write, read, self.timeout).await
self.write_read_timeout(address, write, read, || Ok(())).await
}
#[cfg(feature = "time")]
pub async fn write_read_timeout(
&mut self,
address: u8,
write: &[u8],
read: &mut [u8],
timeout: Duration,
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error>
where
TXDMA: super::TxDma<T>,
RXDMA: super::RxDma<T>,
{
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 {
embassy_time::with_timeout(
timeout,
self.write_dma_internal(address, write, true, true, &check_timeout),
)
.await
.unwrap_or(Err(Error::Timeout))?;
self.write_dma_internal(address, write, true, true, || check_timeout())
.await?;
}
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 {
embassy_time::with_timeout(
time_left_until_timeout,
self.read_dma_internal(address, read, true, &check_timeout),
)
.await
.unwrap_or(Err(Error::Timeout))?;
self.read_dma_internal(address, read, true, check_timeout).await?;
}
Ok(())
@ -750,73 +713,33 @@ 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,
@ -829,17 +752,11 @@ 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(()))
}
fn blocking_write_vectored_with_timeout(
pub fn blocking_write_vectored_timeout(
&mut self,
address: u8,
write: &[&[u8]],
@ -848,7 +765,6 @@ 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;
@ -917,33 +833,6 @@ 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(()))
}
@ -955,7 +844,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> {
}
}
#[cfg(feature = "time")]
mod eh02 {
use super::*;
@ -1155,7 +1043,7 @@ mod eh1 {
}
}
#[cfg(all(feature = "unstable-traits", feature = "nightly", feature = "time"))]
#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
mod eha {
use super::super::{RxDma, TxDma};
use super::*;
@ -1201,15 +1089,3 @@ 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(())
}
}
}

View File

@ -170,7 +170,7 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
let spi = Spi::new_internal(peri, txdma, rxdma, spi_cfg);
#[cfg(all(rcc_f4, not(stm32f410)))]
let pclk = unsafe { get_freqs() }.plli2s1_q.unwrap();
let pclk = unsafe { get_freqs() }.plli2s.unwrap();
#[cfg(stm32f410)]
let pclk = T::frequency();

View File

@ -5,7 +5,6 @@ use core::task::Poll;
use self::sealed::Instance;
use crate::interrupt;
use crate::interrupt::typelevel::Interrupt;
use crate::pac::rcc::vals::{Lptim1sel, Lptim2sel};
use crate::peripherals::IPCC;
use crate::rcc::sealed::RccPeripheral;
@ -94,7 +93,8 @@ pub struct Ipcc;
impl Ipcc {
pub fn enable(_config: Config) {
IPCC::enable_and_reset();
IPCC::enable();
IPCC::reset();
IPCC::set_cpu2(true);
_configure_pwr();
@ -274,7 +274,7 @@ fn _configure_pwr() {
// set LPTIM1 & LPTIM2 clock source
rcc.ccipr().modify(|w| {
w.set_lptim1sel(Lptim1sel::PCLK1);
w.set_lptim2sel(Lptim2sel::PCLK1);
w.set_lptim1sel(0b00); // PCLK
w.set_lptim2sel(0b00); // PCLK
});
}

View File

@ -155,82 +155,81 @@ impl Default for Config {
/// Initialize embassy.
pub fn init(config: Config) -> Peripherals {
critical_section::with(|cs| {
let p = Peripherals::take_with_cs(cs);
let p = Peripherals::take();
#[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_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);
#[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();
#[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() {
critical_section::with(|cs| {
crate::rcc::clock_refcount_sub(cs);
});
}
}
p
}

View File

@ -101,22 +101,18 @@ pub trait InvertingPin<T: Instance>: sealed::InvertingPin<T> {}
#[cfg(opamp_f3)]
macro_rules! impl_opamp_output {
($inst:ident, $adc:ident, $ch:expr) => {
foreach_adc!(
($adc, $common_inst:ident, $adc_clock:ident) => {
impl<'d, 'p, P: NonInvertingPin<crate::peripherals::$inst>> crate::adc::sealed::AdcPin<crate::peripherals::$adc>
for OpAmpOutput<'d, 'p, crate::peripherals::$inst, P>
{
fn channel(&self) -> u8 {
$ch
}
}
impl<'d, 'p, P: NonInvertingPin<crate::peripherals::$inst>> crate::adc::sealed::AdcPin<crate::peripherals::$adc>
for OpAmpOutput<'d, 'p, crate::peripherals::$inst, P>
{
fn channel(&self) -> u8 {
$ch
}
}
impl<'d, 'p, P: NonInvertingPin<crate::peripherals::$inst>> crate::adc::AdcPin<crate::peripherals::$adc>
for OpAmpOutput<'d, 'p, crate::peripherals::$inst, P>
{
}
};
);
impl<'d, 'p, P: NonInvertingPin<crate::peripherals::$inst>> crate::adc::AdcPin<crate::peripherals::$adc>
for OpAmpOutput<'d, 'p, crate::peripherals::$inst, P>
{
}
};
}

View File

@ -177,7 +177,8 @@ impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
) -> Self {
into_ref!(peri, dma);
T::enable_and_reset();
T::enable();
T::reset();
while T::REGS.sr().read().busy() {}

View File

@ -106,7 +106,7 @@ impl LsConfig {
pub const fn off() -> Self {
Self {
rtc: RtcClockSource::DISABLE,
rtc: RtcClockSource::NOCLOCK,
lsi: false,
lse: None,
}
@ -133,7 +133,7 @@ impl LsConfig {
Some(LSI_FREQ)
}
RtcClockSource::LSE => Some(self.lse.as_ref().unwrap().frequency),
RtcClockSource::DISABLE => None,
RtcClockSource::NOCLOCK => None,
_ => todo!(),
};
@ -180,7 +180,7 @@ impl LsConfig {
ok &= reg.rtcsel() == self.rtc;
#[cfg(not(rcc_wba))]
{
ok &= reg.rtcen() == (self.rtc != RtcClockSource::DISABLE);
ok &= reg.rtcen() == (self.rtc != RtcClockSource::NOCLOCK);
}
ok &= reg.lseon() == lse_en;
ok &= reg.lsebyp() == lse_byp;
@ -225,7 +225,7 @@ impl LsConfig {
while !bdcr().read().lserdy() {}
}
if self.rtc != RtcClockSource::DISABLE {
if self.rtc != RtcClockSource::NOCLOCK {
bdcr().modify(|w| {
#[cfg(any(rtc_v2h7, rtc_v2l4, rtc_v2wb, rtc_v3, rtc_v3u5))]
assert!(!w.lsecsson(), "RTC is not compatible with LSE CSS, yet.");

View File

@ -134,12 +134,10 @@ pub(crate) unsafe fn init(config: Config) {
};
set_freqs(Clocks {
hsi: None,
lse: None,
sys: sys_clk,
hclk1: ahb_freq,
pclk1: apb_freq,
pclk1_tim: apb_tim_freq,
ahb1: ahb_freq,
apb1: apb_freq,
apb1_tim: apb_tim_freq,
rtc,
});
}

View File

@ -127,7 +127,7 @@ pub(crate) unsafe fn init(config: Config) {
}
if config.usb_pll {
RCC.cfgr3().modify(|w| w.set_usbsw(Usbsw::PLL1_P));
RCC.cfgr3().modify(|w| w.set_usbsw(Usbsw::PLLCLK));
}
// TODO: Option to use CRS (Clock Recovery)
@ -140,7 +140,7 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cfgr().modify(|w| {
w.set_ppre(Ppre::from_bits(ppre_bits));
w.set_hpre(Hpre::from_bits(hpre_bits));
w.set_sw(Sw::PLL1_P)
w.set_sw(Sw::PLL)
});
} else {
RCC.cfgr().modify(|w| {
@ -162,11 +162,11 @@ pub(crate) unsafe fn init(config: Config) {
set_freqs(Clocks {
sys: Hertz(real_sysclk),
pclk1: Hertz(pclk),
pclk2: Hertz(pclk),
pclk1_tim: Hertz(pclk * timer_mul),
pclk2_tim: Hertz(pclk * timer_mul),
hclk1: Hertz(hclk),
apb1: Hertz(pclk),
apb2: Hertz(pclk),
apb1_tim: Hertz(pclk * timer_mul),
apb2_tim: Hertz(pclk * timer_mul),
ahb1: Hertz(hclk),
rtc,
});
}

View File

@ -102,6 +102,7 @@ pub(crate) unsafe fn init(config: Config) {
assert!(pclk2 <= 72_000_000);
// Only needed for stm32f103?
FLASH.acr().write(|w| {
w.set_latency(if real_sysclk <= 24_000_000 {
Latency::WS0
@ -110,8 +111,6 @@ pub(crate) unsafe fn init(config: Config) {
} else {
Latency::WS2
});
// the prefetch buffer is enabled by default, let's keep it enabled
w.set_prftbe(true);
});
// the USB clock is only valid if an external crystal is used, the PLL is enabled, and the
@ -169,7 +168,7 @@ pub(crate) unsafe fn init(config: Config) {
#[cfg(not(rcc_f100))]
w.set_usbpre(Usbpre::from_bits(usbpre as u8));
w.set_sw(if pllmul_bits.is_some() {
Sw::PLL1_P
Sw::PLL
} else if config.hse.is_some() {
Sw::HSE
} else {
@ -181,11 +180,11 @@ pub(crate) unsafe fn init(config: Config) {
set_freqs(Clocks {
sys: Hertz(real_sysclk),
pclk1: Hertz(pclk1),
pclk2: Hertz(pclk2),
pclk1_tim: Hertz(pclk1 * timer_mul1),
pclk2_tim: Hertz(pclk2 * timer_mul2),
hclk1: Hertz(hclk),
apb1: Hertz(pclk1),
apb2: Hertz(pclk2),
apb1_tim: Hertz(pclk1 * timer_mul1),
apb2_tim: Hertz(pclk2 * timer_mul2),
ahb1: Hertz(hclk),
adc: Some(Hertz(adcclk)),
rtc,
});

View File

@ -256,7 +256,7 @@ pub(crate) unsafe fn init(config: Config) {
ClockSrc::PLL => {
RCC.cr().modify(|w| w.set_pllon(true));
while !RCC.cr().read().pllrdy() {}
(pll_clocks.main_freq, Sw::PLL1_P)
(pll_clocks.main_freq, Sw::PLL)
}
};
// RM0033 Figure 9. Clock tree suggests max SYSCLK/HCLK is 168 MHz, but datasheet specifies PLL
@ -307,14 +307,14 @@ pub(crate) unsafe fn init(config: Config) {
set_freqs(Clocks {
sys: sys_clk,
hclk1: ahb_freq,
hclk2: ahb_freq,
hclk3: ahb_freq,
pclk1: apb1_freq,
pclk1_tim: apb1_tim_freq,
pclk2: apb2_freq,
pclk2_tim: apb2_tim_freq,
pll1_q: Some(pll_clocks.pll48_freq),
ahb1: ahb_freq,
ahb2: ahb_freq,
ahb3: ahb_freq,
apb1: apb1_freq,
apb1_tim: apb1_tim_freq,
apb2: apb2_freq,
apb2_tim: apb2_tim_freq,
pll48: Some(pll_clocks.pll48_freq),
rtc,
});
}

View File

@ -214,7 +214,7 @@ pub(crate) unsafe fn init(config: Config) {
// CFGR has been written before (PLL, PLL48, clock divider) don't overwrite these settings
RCC.cfgr().modify(|w| {
w.set_sw(match (pll_config, config.hse) {
(Some(_), _) => Sw::PLL1_P,
(Some(_), _) => Sw::PLL,
(None, Some(_)) => Sw::HSE,
(None, None) => Sw::HSI,
})
@ -271,7 +271,7 @@ pub(crate) unsafe fn init(config: Config) {
pll_config.unwrap();
assert!((pclk2 == sysclk) || (pclk2 * 2u32 == sysclk));
RCC.cfgr3().modify(|w| w.set_hrtim1sw(Timsw::PLL1_P));
RCC.cfgr3().modify(|w| w.set_hrtim1sw(Timsw::PLL));
Some(sysclk * 2u32)
}
@ -281,11 +281,11 @@ pub(crate) unsafe fn init(config: Config) {
set_freqs(Clocks {
sys: sysclk,
pclk1: pclk1,
pclk2: pclk2,
pclk1_tim: pclk1 * timer_mul1,
pclk2_tim: pclk2 * timer_mul2,
hclk1: hclk,
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))]

396
embassy-stm32/src/rcc/f4.rs Normal file
View File

@ -0,0 +1,396 @@
use crate::pac::rcc::vals::{Hpre, Pllm, Plln, Pllq, Pllr, Ppre, 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);
/// Clocks configuration
#[non_exhaustive]
#[derive(Default)]
pub struct Config {
pub hse: Option<Hertz>,
pub bypass_hse: bool,
pub hclk: Option<Hertz>,
pub sys_ck: Option<Hertz>,
pub pclk1: Option<Hertz>,
pub pclk2: Option<Hertz>,
#[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))]
pub plli2s: Option<Hertz>,
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
pub pllsai: Option<Hertz>,
pub pll48: bool,
pub ls: super::LsConfig,
}
#[cfg(stm32f410)]
fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> {
None
}
// Not currently implemented, but will be in the future
#[cfg(any(stm32f411, stm32f412, stm32f413, stm32f423, stm32f446))]
fn setup_i2s_pll(_vco_in: u32, _plli2s: Option<u32>) -> Option<u32> {
None
}
#[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423)))]
fn calculate_sai_i2s_pll_values(vco_in: u32, max_div: u32, target: Option<u32>) -> Option<(u32, u32, u32)> {
let min_div = 2;
let target = match target {
Some(target) => target,
None => return None,
};
// We loop through the possible divider values to find the best configuration. Looping
// through all possible "N" values would result in more iterations.
let (n, outdiv, output, _error) = (min_div..=max_div)
.filter_map(|outdiv| {
let target_vco_out = match target.checked_mul(outdiv) {
Some(x) => x,
None => return None,
};
let n = (target_vco_out + (vco_in >> 1)) / vco_in;
let vco_out = vco_in * n;
if !(100_000_000..=432_000_000).contains(&vco_out) {
return None;
}
let output = vco_out / outdiv;
let error = (output as i32 - target as i32).unsigned_abs();
Some((n, outdiv, output, error))
})
.min_by_key(|(_, _, _, error)| *error)?;
Some((n, outdiv, output))
}
#[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))]
fn setup_i2s_pll(vco_in: u32, plli2s: Option<u32>) -> Option<u32> {
let (n, outdiv, output) = calculate_sai_i2s_pll_values(vco_in, 7, plli2s)?;
RCC.plli2scfgr().modify(|w| {
w.set_plli2sn(n as u16);
w.set_plli2sr(outdiv as u8);
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
w.set_plli2sq(outdiv as u8); //set sai divider same as i2s
});
Some(output)
}
#[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479)))]
fn setup_sai_pll(_vco_in: u32, _pllsai: Option<u32>) -> Option<u32> {
None
}
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
fn setup_sai_pll(vco_in: u32, pllsai: Option<u32>) -> Option<u32> {
let (n, outdiv, output) = calculate_sai_i2s_pll_values(vco_in, 15, pllsai)?;
RCC.pllsaicfgr().modify(|w| {
w.set_pllsain(n as u16);
w.set_pllsaiq(outdiv as u8);
});
Some(output)
}
fn setup_pll(
pllsrcclk: u32,
use_hse: bool,
pllsysclk: Option<u32>,
plli2s: Option<u32>,
pllsai: Option<u32>,
pll48clk: bool,
) -> PllResults {
use crate::pac::rcc::vals::{Pllp, Pllsrc};
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)));
return PllResults {
use_pll: false,
pllsysclk: None,
pll48clk: None,
plli2sclk: None,
pllsaiclk: None,
};
}
// Input divisor from PLL source clock, must result to frequency in
// the range from 1 to 2 MHz
let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000;
let pllm_max = pllsrcclk / 1_000_000;
// Sysclk output divisor must be one of 2, 4, 6 or 8
let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1);
let target_freq = if pll48clk { 48_000_000 } else { sysclk * sysclk_div };
// Find the lowest pllm value that minimize the difference between
// target frequency and the real vco_out frequency.
let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| {
let vco_in = pllsrcclk / pllm;
let plln = target_freq / vco_in;
target_freq - vco_in * plln
}));
let vco_in = pllsrcclk / pllm;
assert!((1_000_000..=2_000_000).contains(&vco_in));
// Main scaler, must result in >= 100MHz (>= 192MHz for F401)
// and <= 432MHz, min 50, max 432
let plln = if pll48clk {
// try the different valid pllq according to the valid
// main scaller values, and take the best
let pllq = unwrap!((4..=9).min_by_key(|pllq| {
let plln = 48_000_000 * pllq / vco_in;
let pll48_diff = 48_000_000 - vco_in * plln / pllq;
let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs();
(pll48_diff, sysclk_diff)
}));
48_000_000 * pllq / vco_in
} else {
sysclk * sysclk_div / vco_in
};
let pllp = (sysclk_div / 2) - 1;
let pllq = (vco_in * plln + 47_999_999) / 48_000_000;
let real_pll48clk = vco_in * plln / pllq;
RCC.pllcfgr().modify(|w| {
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::from_bits(pllq as u8));
w.set_pllsrc(Pllsrc::from_bits(use_hse as u8));
w.set_pllr(Pllr::from_bits(0));
});
let real_pllsysclk = vco_in * plln / sysclk_div;
PllResults {
use_pll: true,
pllsysclk: Some(real_pllsysclk),
pll48clk: if pll48clk { Some(real_pll48clk) } else { None },
plli2sclk: setup_i2s_pll(vco_in, plli2s),
pllsaiclk: setup_sai_pll(vco_in, pllsai),
}
}
fn flash_setup(sysclk: u32) {
use crate::pac::flash::vals::Latency;
// Be conservative with voltage ranges
const FLASH_LATENCY_STEP: u32 = 30_000_000;
critical_section::with(|_| {
FLASH
.acr()
.modify(|w| w.set_latency(Latency::from_bits(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
});
}
pub(crate) unsafe fn init(config: Config) {
let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI_FREQ.0);
let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
let sysclk_on_pll = sysclk != pllsrcclk;
let plls = setup_pll(
pllsrcclk,
config.hse.is_some(),
if sysclk_on_pll { Some(sysclk) } else { None },
#[cfg(not(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446)))]
config.plli2s.map(|i2s| i2s.0),
#[cfg(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f446))]
None,
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
config.pllsai.map(|sai| sai.0),
#[cfg(not(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479)))]
None,
config.pll48,
);
if config.pll48 {
let freq = unwrap!(plls.pll48clk);
assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32);
}
let sysclk = if sysclk_on_pll { unwrap!(plls.pllsysclk) } else { sysclk };
// AHB prescaler
let hclk = config.hclk.map(|h| h.0).unwrap_or(sysclk);
let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk {
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),
};
// Calculate real AHB clock
let hclk = sysclk / hpre_div;
let pclk1 = config
.pclk1
.map(|p| p.0)
.unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk));
let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 {
0 => unreachable!(),
1 => (0b000, 1),
2 => (0b100, 2),
3..=5 => (0b101, 4),
6..=11 => (0b110, 8),
_ => (0b111, 16),
};
let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
// Calculate real APB1 clock
let pclk1 = hclk / ppre1;
assert!(pclk1 <= max::PCLK1_MAX);
let pclk2 = config
.pclk2
.map(|p| p.0)
.unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk));
let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 {
0 => unreachable!(),
1 => (0b000, 1),
2 => (0b100, 2),
3..=5 => (0b101, 4),
6..=11 => (0b110, 8),
_ => (0b111, 16),
};
let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
// Calculate real APB2 clock
let pclk2 = hclk / ppre2;
assert!(pclk2 <= max::PCLK2_MAX);
flash_setup(sysclk);
if config.hse.is_some() {
RCC.cr().modify(|w| {
w.set_hsebyp(config.bypass_hse);
w.set_hseon(true);
});
while !RCC.cr().read().hserdy() {}
}
if plls.use_pll {
RCC.cr().modify(|w| w.set_pllon(true));
if hclk > max::HCLK_OVERDRIVE_FREQUENCY {
PWR.cr1().modify(|w| w.set_oden(true));
while !PWR.csr1().read().odrdy() {}
PWR.cr1().modify(|w| w.set_odswen(true));
while !PWR.csr1().read().odswrdy() {}
}
while !RCC.cr().read().pllrdy() {}
}
#[cfg(not(stm32f410))]
if plls.plli2sclk.is_some() {
RCC.cr().modify(|w| w.set_plli2son(true));
while !RCC.cr().read().plli2srdy() {}
}
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
if plls.pllsaiclk.is_some() {
RCC.cr().modify(|w| w.set_pllsaion(true));
while !RCC.cr().read().pllsairdy() {}
}
RCC.cfgr().modify(|w| {
w.set_ppre2(Ppre::from_bits(ppre2_bits));
w.set_ppre1(Ppre::from_bits(ppre1_bits));
w.set_hpre(hpre_bits);
});
// Wait for the new prescalers to kick in
// "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write"
cortex_m::asm::delay(16);
RCC.cfgr().modify(|w| {
w.set_sw(if sysclk_on_pll {
Sw::PLL
} else if config.hse.is_some() {
Sw::HSE
} else {
Sw::HSI
})
});
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),
ahb2: Hertz(hclk),
ahb3: Hertz(hclk),
pll48: plls.pll48clk.map(Hertz),
#[cfg(not(stm32f410))]
plli2s: plls.plli2sclk.map(Hertz),
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
pllsai: plls.pllsaiclk.map(Hertz),
rtc,
});
}
struct PllResults {
use_pll: bool,
pllsysclk: Option<u32>,
pll48clk: Option<u32>,
#[allow(dead_code)]
plli2sclk: Option<u32>,
#[allow(dead_code)]
pllsaiclk: Option<u32>,
}
mod max {
#[cfg(stm32f401)]
pub(crate) const SYSCLK_MAX: u32 = 84_000_000;
#[cfg(any(stm32f405, stm32f407, stm32f415, stm32f417,))]
pub(crate) const SYSCLK_MAX: u32 = 168_000_000;
#[cfg(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
pub(crate) const SYSCLK_MAX: u32 = 100_000_000;
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479,))]
pub(crate) const SYSCLK_MAX: u32 = 180_000_000;
pub(crate) const HCLK_OVERDRIVE_FREQUENCY: u32 = 168_000_000;
pub(crate) const PCLK1_MAX: u32 = PCLK2_MAX / 2;
#[cfg(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX;
#[cfg(not(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,)))]
pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2;
pub(crate) const PLL_48_CLK: u32 = 48_000_000;
pub(crate) const PLL_48_TOLERANCE: u32 = 120_000;
}

View File

@ -1,387 +0,0 @@
pub use crate::pac::rcc::vals::{
Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp, Pllq, Pllr, Pllsrc as PllSource,
Ppre as APBPrescaler, Sw as Sysclk,
};
use crate::pac::{FLASH, RCC};
use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz;
// TODO: on some F4s, PLLM is shared between all PLLs. Enforce that.
// TODO: on some F4s, add support for plli2s_src
//
// plli2s plli2s_m plli2s_src pllsai pllsai_m
// f401 y shared
// f410
// f411 y individual
// f412 y individual y
// f4[12]3 y individual y
// f446 y individual y individual
// f4[67]9 y shared y shared
// f4[23][79] y shared y shared
// f4[01][57] y shared
/// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000);
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum HseMode {
/// crystal/ceramic oscillator (HSEBYP=0)
Oscillator,
/// external analog clock (low swing) (HSEBYP=1)
Bypass,
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Hse {
/// HSE frequency.
pub freq: Hertz,
/// HSE mode.
pub mode: HseMode,
}
#[derive(Clone, Copy)]
pub struct Pll {
/// PLL pre-divider (DIVM).
pub prediv: PllPreDiv,
/// PLL multiplication factor.
pub mul: PllMul,
/// PLL P division factor. If None, PLL P output is disabled.
pub divp: Option<Pllp>,
/// PLL Q division factor. If None, PLL Q output is disabled.
pub divq: Option<Pllq>,
/// PLL R division factor. If None, PLL R output is disabled.
pub divr: Option<Pllr>,
}
/// Configuration of the core clocks
#[non_exhaustive]
pub struct Config {
pub hsi: bool,
pub hse: Option<Hse>,
pub sys: Sysclk,
pub pll_src: PllSource,
pub pll: Option<Pll>,
#[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))]
pub plli2s: Option<Pll>,
#[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
pub pllsai: Option<Pll>,
pub ahb_pre: AHBPrescaler,
pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler,
pub ls: super::LsConfig,
}
impl Default for Config {
fn default() -> Self {
Self {
hsi: true,
hse: None,
sys: Sysclk::HSI,
pll_src: PllSource::HSI,
pll: None,
#[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))]
plli2s: None,
#[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
pllsai: None,
ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1,
ls: Default::default(),
}
}
}
pub(crate) unsafe fn init(config: Config) {
// always enable overdrive for now. Make it configurable in the future.
#[cfg(not(any(
stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f405, stm32f407, stm32f415, stm32f417
)))]
{
use crate::pac::PWR;
PWR.cr1().modify(|w| w.set_oden(true));
while !PWR.csr1().read().odrdy() {}
PWR.cr1().modify(|w| w.set_odswen(true));
while !PWR.csr1().read().odswrdy() {}
}
// Configure HSI
let hsi = match config.hsi {
false => {
RCC.cr().modify(|w| w.set_hsion(false));
None
}
true => {
RCC.cr().modify(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
Some(HSI_FREQ)
}
};
// Configure HSE
let hse = match config.hse {
None => {
RCC.cr().modify(|w| w.set_hseon(false));
None
}
Some(hse) => {
match hse.mode {
HseMode::Bypass => assert!(max::HSE_BYP.contains(&hse.freq)),
HseMode::Oscillator => assert!(max::HSE_OSC.contains(&hse.freq)),
}
RCC.cr().modify(|w| w.set_hsebyp(hse.mode != HseMode::Oscillator));
RCC.cr().modify(|w| w.set_hseon(true));
while !RCC.cr().read().hserdy() {}
Some(hse.freq)
}
};
// Configure PLLs.
let pll_input = PllInput {
hse,
hsi,
source: config.pll_src,
};
let pll = init_pll(PllInstance::Pll, config.pll, &pll_input);
#[cfg(any(all(stm32f4, not(any(stm32f410, stm32f429))), stm32f7))]
let _plli2s = init_pll(PllInstance::Plli2s, config.plli2s, &pll_input);
#[cfg(all(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7), not(stm32f429)))]
let _pllsai = init_pll(PllInstance::Pllsai, config.pllsai, &pll_input);
// Configure sysclk
let sys = match config.sys {
Sysclk::HSI => unwrap!(hsi),
Sysclk::HSE => unwrap!(hse),
Sysclk::PLL1_P => unwrap!(pll.p),
_ => unreachable!(),
};
let hclk = sys / config.ahb_pre;
let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre);
let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre);
assert!(max::SYSCLK.contains(&sys));
assert!(max::HCLK.contains(&hclk));
assert!(max::PCLK1.contains(&pclk1));
assert!(max::PCLK2.contains(&pclk2));
let rtc = config.ls.init();
flash_setup(hclk);
RCC.cfgr().modify(|w| {
w.set_sw(config.sys);
w.set_hpre(config.ahb_pre);
w.set_ppre1(config.apb1_pre);
w.set_ppre2(config.apb2_pre);
});
while RCC.cfgr().read().sws() != config.sys {}
set_freqs(Clocks {
sys,
hclk1: hclk,
hclk2: hclk,
hclk3: hclk,
pclk1,
pclk2,
pclk1_tim,
pclk2_tim,
rtc,
pll1_q: pll.q,
#[cfg(all(rcc_f4, not(any(stm32f410, stm32f429))))]
plli2s1_q: _plli2s.q,
#[cfg(all(rcc_f4, not(any(stm32f410, stm32f429))))]
plli2s1_r: _plli2s.r,
#[cfg(stm32f429)]
plli2s1_q: None,
#[cfg(stm32f429)]
plli2s1_r: None,
#[cfg(any(stm32f427, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
pllsai1_q: _pllsai.q,
#[cfg(any(stm32f427, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
pllsai1_r: _pllsai.r,
#[cfg(stm32f429)]
pllsai1_q: None,
#[cfg(stm32f429)]
pllsai1_r: None,
});
}
struct PllInput {
source: PllSource,
hsi: Option<Hertz>,
hse: Option<Hertz>,
}
#[derive(Default)]
#[allow(unused)]
struct PllOutput {
p: Option<Hertz>,
q: Option<Hertz>,
r: Option<Hertz>,
}
#[allow(dead_code)]
#[derive(PartialEq, Eq, Clone, Copy)]
enum PllInstance {
Pll,
#[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))]
Plli2s,
#[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
Pllsai,
}
fn pll_enable(instance: PllInstance, enabled: bool) {
match instance {
PllInstance::Pll => {
RCC.cr().modify(|w| w.set_pllon(enabled));
while RCC.cr().read().pllrdy() != enabled {}
}
#[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))]
PllInstance::Plli2s => {
RCC.cr().modify(|w| w.set_plli2son(enabled));
while RCC.cr().read().plli2srdy() != enabled {}
}
#[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
PllInstance::Pllsai => {
RCC.cr().modify(|w| w.set_pllsaion(enabled));
while RCC.cr().read().pllsairdy() != enabled {}
}
}
}
fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> PllOutput {
// Disable PLL
pll_enable(instance, false);
let Some(pll) = config else { return PllOutput::default() };
let pll_src = match input.source {
PllSource::HSE => input.hse,
PllSource::HSI => input.hsi,
};
let pll_src = pll_src.unwrap();
let in_freq = pll_src / pll.prediv;
assert!(max::PLL_IN.contains(&in_freq));
let vco_freq = in_freq * pll.mul;
assert!(max::PLL_VCO.contains(&vco_freq));
let p = pll.divp.map(|div| vco_freq / div);
let q = pll.divq.map(|div| vco_freq / div);
let r = pll.divr.map(|div| vco_freq / div);
macro_rules! write_fields {
($w:ident) => {
$w.set_plln(pll.mul);
if let Some(divp) = pll.divp {
$w.set_pllp(divp);
}
if let Some(divq) = pll.divq {
$w.set_pllq(divq);
}
if let Some(divr) = pll.divr {
$w.set_pllr(divr);
}
};
}
match instance {
PllInstance::Pll => RCC.pllcfgr().write(|w| {
w.set_pllm(pll.prediv);
w.set_pllsrc(input.source);
write_fields!(w);
}),
#[cfg(any(all(stm32f4, not(stm32f410)), stm32f7))]
PllInstance::Plli2s => RCC.plli2scfgr().write(|w| {
write_fields!(w);
}),
#[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
PllInstance::Pllsai => RCC.pllsaicfgr().write(|w| {
write_fields!(w);
}),
}
// Enable PLL
pll_enable(instance, true);
PllOutput { p, q, r }
}
fn flash_setup(clk: Hertz) {
use crate::pac::flash::vals::Latency;
// Be conservative with voltage ranges
const FLASH_LATENCY_STEP: u32 = 30_000_000;
let latency = (clk.0 - 1) / FLASH_LATENCY_STEP;
debug!("flash: latency={}", latency);
let latency = Latency::from_bits(latency as u8);
FLASH.acr().write(|w| {
w.set_latency(latency);
});
while FLASH.acr().read().latency() != latency {}
}
#[cfg(stm32f7)]
mod max {
use core::ops::RangeInclusive;
use crate::time::Hertz;
pub(crate) const HSE_OSC: RangeInclusive<Hertz> = Hertz(4_000_000)..=Hertz(26_000_000);
pub(crate) const HSE_BYP: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(50_000_000);
pub(crate) const SYSCLK: RangeInclusive<Hertz> = Hertz(12_500_000)..=Hertz(216_000_000);
pub(crate) const HCLK: RangeInclusive<Hertz> = Hertz(12_500_000)..=Hertz(216_000_000);
pub(crate) const PCLK1: RangeInclusive<Hertz> = Hertz(12_500_000)..=Hertz(216_000_000 / 4);
pub(crate) const PCLK2: RangeInclusive<Hertz> = Hertz(12_500_000)..=Hertz(216_000_000 / 2);
pub(crate) const PLL_IN: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(2_100_000);
pub(crate) const PLL_VCO: RangeInclusive<Hertz> = Hertz(100_000_000)..=Hertz(432_000_000);
}
#[cfg(stm32f4)]
mod max {
use core::ops::RangeInclusive;
use crate::time::Hertz;
pub(crate) const HSE_OSC: RangeInclusive<Hertz> = Hertz(4_000_000)..=Hertz(26_000_000);
pub(crate) const HSE_BYP: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(50_000_000);
#[cfg(stm32f401)]
pub(crate) const SYSCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(84_000_000);
#[cfg(any(stm32f405, stm32f407, stm32f415, stm32f417,))]
pub(crate) const SYSCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(168_000_000);
#[cfg(any(stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
pub(crate) const SYSCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(100_000_000);
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479,))]
pub(crate) const SYSCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(180_000_000);
pub(crate) const HCLK: RangeInclusive<Hertz> = Hertz(0)..=Hertz(SYSCLK.end().0);
pub(crate) const PCLK1: RangeInclusive<Hertz> = Hertz(0)..=Hertz(PCLK2.end().0 / 2);
#[cfg(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,))]
pub(crate) const PCLK2: RangeInclusive<Hertz> = Hertz(0)..=Hertz(HCLK.end().0);
#[cfg(not(any(stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423,)))]
pub(crate) const PCLK2: RangeInclusive<Hertz> = Hertz(0)..=Hertz(HCLK.end().0 / 2);
pub(crate) const PLL_IN: RangeInclusive<Hertz> = Hertz(1_000_000)..=Hertz(2_100_000);
pub(crate) const PLL_VCO: RangeInclusive<Hertz> = Hertz(100_000_000)..=Hertz(432_000_000);
}

305
embassy-stm32/src/rcc/f7.rs Normal file
View File

@ -0,0 +1,305 @@
use crate::pac::pwr::vals::Vos;
use crate::pac::rcc::vals::{Hpre, Pllm, Plln, Pllp, Pllq, Pllsrc, Ppre, 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);
/// Clocks configuration
#[non_exhaustive]
#[derive(Default)]
pub struct Config {
pub hse: Option<Hertz>,
pub bypass_hse: bool,
pub hclk: Option<Hertz>,
pub sys_ck: Option<Hertz>,
pub pclk1: Option<Hertz>,
pub pclk2: Option<Hertz>,
pub pll48: bool,
pub ls: super::LsConfig,
}
fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48clk: bool) -> PllResults {
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)));
return PllResults {
use_pll: false,
pllsysclk: None,
pll48clk: None,
};
}
// Input divisor from PLL source clock, must result to frequency in
// the range from 1 to 2 MHz
let pllm_min = (pllsrcclk + 1_999_999) / 2_000_000;
let pllm_max = pllsrcclk / 1_000_000;
// Sysclk output divisor must be one of 2, 4, 6 or 8
let sysclk_div = core::cmp::min(8, (432_000_000 / sysclk) & !1);
let target_freq = if pll48clk { 48_000_000 } else { sysclk * sysclk_div };
// Find the lowest pllm value that minimize the difference between
// target frequency and the real vco_out frequency.
let pllm = unwrap!((pllm_min..=pllm_max).min_by_key(|pllm| {
let vco_in = pllsrcclk / pllm;
let plln = target_freq / vco_in;
target_freq - vco_in * plln
}));
let vco_in = pllsrcclk / pllm;
assert!((1_000_000..=2_000_000).contains(&vco_in));
// Main scaler, must result in >= 100MHz (>= 192MHz for F401)
// and <= 432MHz, min 50, max 432
let plln = if pll48clk {
// try the different valid pllq according to the valid
// main scaller values, and take the best
let pllq = unwrap!((4..=9).min_by_key(|pllq| {
let plln = 48_000_000 * pllq / vco_in;
let pll48_diff = 48_000_000 - vco_in * plln / pllq;
let sysclk_diff = (sysclk as i32 - (vco_in * plln / sysclk_div) as i32).abs();
(pll48_diff, sysclk_diff)
}));
48_000_000 * pllq / vco_in
} else {
sysclk * sysclk_div / vco_in
};
let pllp = (sysclk_div / 2) - 1;
let pllq = (vco_in * plln + 47_999_999) / 48_000_000;
let real_pll48clk = vco_in * plln / pllq;
RCC.pllcfgr().modify(|w| {
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::from_bits(pllq as u8));
w.set_pllsrc(Pllsrc::from_bits(use_hse as u8));
});
let real_pllsysclk = vco_in * plln / sysclk_div;
PllResults {
use_pll: true,
pllsysclk: Some(real_pllsysclk),
pll48clk: if pll48clk { Some(real_pll48clk) } else { None },
}
}
fn flash_setup(sysclk: u32) {
use crate::pac::flash::vals::Latency;
// Be conservative with voltage ranges
const FLASH_LATENCY_STEP: u32 = 30_000_000;
critical_section::with(|_| {
FLASH
.acr()
.modify(|w| w.set_latency(Latency::from_bits(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
});
}
pub(crate) unsafe fn init(config: Config) {
if let Some(hse) = config.hse {
if config.bypass_hse {
assert!((max::HSE_BYPASS_MIN..=max::HSE_BYPASS_MAX).contains(&hse.0));
} else {
assert!((max::HSE_OSC_MIN..=max::HSE_OSC_MAX).contains(&hse.0));
}
}
let pllsrcclk = config.hse.map(|hse| hse.0).unwrap_or(HSI_FREQ.0);
let sysclk = config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk);
let sysclk_on_pll = sysclk != pllsrcclk;
assert!((max::SYSCLK_MIN..=max::SYSCLK_MAX).contains(&sysclk));
let plls = setup_pll(
pllsrcclk,
config.hse.is_some(),
if sysclk_on_pll { Some(sysclk) } else { None },
config.pll48,
);
if config.pll48 {
let freq = unwrap!(plls.pll48clk);
assert!((max::PLL_48_CLK as i32 - freq as i32).abs() <= max::PLL_48_TOLERANCE as i32);
}
let sysclk = if sysclk_on_pll { unwrap!(plls.pllsysclk) } else { sysclk };
// AHB prescaler
let hclk = config.hclk.map(|h| h.0).unwrap_or(sysclk);
let (hpre_bits, hpre_div) = match (sysclk + hclk - 1) / hclk {
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),
};
// Calculate real AHB clock
let hclk = sysclk / hpre_div;
assert!(hclk <= max::HCLK_MAX);
let pclk1 = config
.pclk1
.map(|p| p.0)
.unwrap_or_else(|| core::cmp::min(max::PCLK1_MAX, hclk));
let (ppre1_bits, ppre1) = match (hclk + pclk1 - 1) / pclk1 {
0 => unreachable!(),
1 => (0b000, 1),
2 => (0b100, 2),
3..=5 => (0b101, 4),
6..=11 => (0b110, 8),
_ => (0b111, 16),
};
let timer_mul1 = if ppre1 == 1 { 1 } else { 2 };
// Calculate real APB1 clock
let pclk1 = hclk / ppre1;
assert!((max::PCLK1_MIN..=max::PCLK1_MAX).contains(&pclk1));
let pclk2 = config
.pclk2
.map(|p| p.0)
.unwrap_or_else(|| core::cmp::min(max::PCLK2_MAX, hclk));
let (ppre2_bits, ppre2) = match (hclk + pclk2 - 1) / pclk2 {
0 => unreachable!(),
1 => (0b000, 1),
2 => (0b100, 2),
3..=5 => (0b101, 4),
6..=11 => (0b110, 8),
_ => (0b111, 16),
};
let timer_mul2 = if ppre2 == 1 { 1 } else { 2 };
// Calculate real APB2 clock
let pclk2 = hclk / ppre2;
assert!((max::PCLK2_MIN..=max::PCLK2_MAX).contains(&pclk2));
flash_setup(sysclk);
if config.hse.is_some() {
RCC.cr().modify(|w| {
w.set_hsebyp(config.bypass_hse);
w.set_hseon(true);
});
while !RCC.cr().read().hserdy() {}
}
if plls.use_pll {
RCC.cr().modify(|w| w.set_pllon(false));
// setup VOSScale
let vos_scale = if sysclk <= 144_000_000 {
3
} else if sysclk <= 168_000_000 {
2
} else {
1
};
PWR.cr1().modify(|w| {
w.set_vos(match vos_scale {
3 => Vos::SCALE3,
2 => Vos::SCALE2,
1 => Vos::SCALE1,
_ => panic!("Invalid VOS Scale."),
})
});
RCC.cr().modify(|w| w.set_pllon(true));
if hclk > max::HCLK_OVERDRIVE_FREQUENCY {
PWR.cr1().modify(|w| w.set_oden(true));
while !PWR.csr1().read().odrdy() {}
PWR.cr1().modify(|w| w.set_odswen(true));
while !PWR.csr1().read().odswrdy() {}
}
while !RCC.cr().read().pllrdy() {}
}
RCC.cfgr().modify(|w| {
w.set_ppre2(Ppre::from_bits(ppre2_bits));
w.set_ppre1(Ppre::from_bits(ppre1_bits));
w.set_hpre(hpre_bits);
});
// Wait for the new prescalers to kick in
// "The clocks are divided with the new prescaler factor from 1 to 16 AHB cycles after write"
cortex_m::asm::delay(16);
RCC.cfgr().modify(|w| {
w.set_sw(if sysclk_on_pll {
Sw::PLL
} else if config.hse.is_some() {
Sw::HSE
} else {
Sw::HSI
})
});
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),
ahb2: Hertz(hclk),
ahb3: Hertz(hclk),
pll48: plls.pll48clk.map(Hertz),
rtc,
});
}
struct PllResults {
use_pll: bool,
pllsysclk: Option<u32>,
pll48clk: Option<u32>,
}
mod max {
pub(crate) const HSE_OSC_MIN: u32 = 4_000_000;
pub(crate) const HSE_OSC_MAX: u32 = 26_000_000;
pub(crate) const HSE_BYPASS_MIN: u32 = 1_000_000;
pub(crate) const HSE_BYPASS_MAX: u32 = 50_000_000;
pub(crate) const HCLK_MAX: u32 = 216_000_000;
pub(crate) const HCLK_OVERDRIVE_FREQUENCY: u32 = 180_000_000;
pub(crate) const SYSCLK_MIN: u32 = 12_500_000;
pub(crate) const SYSCLK_MAX: u32 = 216_000_000;
pub(crate) const PCLK1_MIN: u32 = SYSCLK_MIN;
pub(crate) const PCLK1_MAX: u32 = SYSCLK_MAX / 4;
pub(crate) const PCLK2_MIN: u32 = SYSCLK_MIN;
pub(crate) const PCLK2_MAX: u32 = SYSCLK_MAX / 2;
// USB specification allows +-0.25%
pub(crate) const PLL_48_CLK: u32 = 48_000_000;
pub(crate) const PLL_48_TOLERANCE: u32 = 120_000;
}

View File

@ -1,7 +1,7 @@
use crate::pac::flash::vals::Latency;
use crate::pac::rcc::vals::{self, Sw};
pub use crate::pac::rcc::vals::{
Hpre as AHBPrescaler, Hsidiv as HSIPrescaler, Pllm, Plln, Pllp, Pllq, Pllr, Ppre as APBPrescaler,
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};
@ -14,7 +14,7 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000);
#[derive(Clone, Copy)]
pub enum ClockSrc {
HSE(Hertz),
HSI(HSIPrescaler),
HSI16(HSI16Prescaler),
PLL(PllConfig),
LSI,
}
@ -46,9 +46,9 @@ pub struct PllConfig {
impl Default for PllConfig {
#[inline]
fn default() -> PllConfig {
// HSI / 1 * 8 / 2 = 64 MHz
// HSI16 / 1 * 8 / 2 = 64 MHz
PllConfig {
source: PllSrc::HSI,
source: PllSrc::HSI16,
m: Pllm::DIV1,
n: Plln::MUL8,
r: Pllr::DIV2,
@ -60,7 +60,7 @@ impl Default for PllConfig {
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum PllSrc {
HSI,
HSI16,
HSE(Hertz),
}
@ -77,7 +77,7 @@ impl Default for Config {
#[inline]
fn default() -> Config {
Config {
mux: ClockSrc::HSI(HSIPrescaler::DIV1),
mux: ClockSrc::HSI16(HSI16Prescaler::DIV1),
ahb_pre: AHBPrescaler::DIV1,
apb_pre: APBPrescaler::DIV1,
low_power_run: false,
@ -89,7 +89,7 @@ impl Default for Config {
impl PllConfig {
pub(crate) fn init(self) -> Hertz {
let (src, input_freq) = match self.source {
PllSrc::HSI => (vals::Pllsrc::HSI, HSI_FREQ),
PllSrc::HSI16 => (vals::Pllsrc::HSI16, HSI_FREQ),
PllSrc::HSE(freq) => (vals::Pllsrc::HSE, freq),
};
@ -121,7 +121,7 @@ impl PllConfig {
// > 3. Change the desired parameter.
// Enable whichever clock source we're using, and wait for it to become ready
match self.source {
PllSrc::HSI => {
PllSrc::HSI16 => {
RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
}
@ -167,8 +167,8 @@ impl PllConfig {
pub(crate) unsafe fn init(config: Config) {
let (sys_clk, sw) = match config.mux {
ClockSrc::HSI(div) => {
// Enable HSI
ClockSrc::HSI16(div) => {
// Enable HSI16
RCC.cr().write(|w| {
w.set_hsidiv(div);
w.set_hsion(true)
@ -186,7 +186,7 @@ pub(crate) unsafe fn init(config: Config) {
}
ClockSrc::PLL(pll) => {
let freq = pll.init();
(freq, Sw::PLL1_R)
(freq, Sw::PLLRCLK)
}
ClockSrc::LSI => {
// Enable LSI
@ -275,9 +275,9 @@ pub(crate) unsafe fn init(config: Config) {
set_freqs(Clocks {
sys: sys_clk,
hclk1: ahb_freq,
pclk1: apb_freq,
pclk1_tim: apb_tim_freq,
ahb1: ahb_freq,
apb1: apb_freq,
apb1_tim: apb_tim_freq,
rtc,
});
}

View File

@ -18,14 +18,14 @@ pub const HSI_FREQ: Hertz = Hertz(16_000_000);
#[derive(Clone, Copy)]
pub enum ClockSrc {
HSE(Hertz),
HSI,
HSI16,
PLL,
}
/// PLL clock input source
#[derive(Clone, Copy, Debug)]
pub enum PllSrc {
HSI,
HSI16,
HSE(Hertz),
}
@ -33,7 +33,7 @@ impl Into<Pllsrc> for PllSrc {
fn into(self) -> Pllsrc {
match self {
PllSrc::HSE(..) => Pllsrc::HSE,
PllSrc::HSI => Pllsrc::HSI,
PllSrc::HSI16 => Pllsrc::HSI16,
}
}
}
@ -112,15 +112,15 @@ impl Default for Config {
#[inline]
fn default() -> Config {
Config {
mux: ClockSrc::HSI,
mux: ClockSrc::HSI16,
ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1,
low_power_run: false,
pll: None,
clock_48mhz_src: Some(Clock48MhzSrc::Hsi48(None)),
adc12_clock_source: Adcsel::DISABLE,
adc345_clock_source: Adcsel::DISABLE,
clock_48mhz_src: None,
adc12_clock_source: Adcsel::NOCLK,
adc345_clock_source: Adcsel::NOCLK,
ls: Default::default(),
}
}
@ -135,7 +135,7 @@ pub struct PllFreq {
pub(crate) unsafe fn init(config: Config) {
let pll_freq = config.pll.map(|pll_config| {
let src_freq = match pll_config.source {
PllSrc::HSI => {
PllSrc::HSI16 => {
RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
@ -196,12 +196,12 @@ pub(crate) unsafe fn init(config: Config) {
});
let (sys_clk, sw) = match config.mux {
ClockSrc::HSI => {
// Enable HSI
ClockSrc::HSI16 => {
// Enable HSI16
RCC.cr().write(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
(HSI_FREQ, Sw::HSI)
(HSI_FREQ, Sw::HSI16)
}
ClockSrc::HSE(freq) => {
// Enable HSE
@ -249,7 +249,7 @@ pub(crate) unsafe fn init(config: Config) {
}
}
(Hertz(freq), Sw::PLL1_R)
(Hertz(freq), Sw::PLLRCLK)
}
};
@ -286,7 +286,7 @@ pub(crate) unsafe fn init(config: Config) {
let pllq_freq = pll_freq.as_ref().and_then(|f| f.pll_q);
assert!(pllq_freq.is_some() && pllq_freq.unwrap().0 == 48_000_000);
crate::pac::rcc::vals::Clk48sel::PLL1_Q
crate::pac::rcc::vals::Clk48sel::PLLQCLK
}
Clock48MhzSrc::Hsi48(crs_config) => {
// Enable HSI48
@ -296,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_and_reset();
crate::peripherals::CRS::enable();
let sync_src = match crs_config.sync_src {
CrsSyncSource::Gpio => crate::pac::crs::vals::Syncsrc::GPIO,
@ -326,16 +326,16 @@ pub(crate) unsafe fn init(config: Config) {
RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source));
let adc12_ck = match config.adc12_clock_source {
AdcClockSource::DISABLE => None,
AdcClockSource::PLL1_P => pll_freq.as_ref().unwrap().pll_p,
AdcClockSource::SYS => Some(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::DISABLE => None,
AdcClockSource::PLL1_P => pll_freq.as_ref().unwrap().pll_p,
AdcClockSource::SYS => Some(sys_clk),
AdcClockSource::NOCLK => None,
AdcClockSource::PLLP => pll_freq.as_ref().unwrap().pll_p,
AdcClockSource::SYSCLK => Some(sys_clk),
_ => unreachable!(),
};
@ -348,15 +348,14 @@ pub(crate) unsafe fn init(config: Config) {
set_freqs(Clocks {
sys: sys_clk,
hclk1: ahb_freq,
hclk2: ahb_freq,
pclk1: apb1_freq,
pclk1_tim: apb1_tim_freq,
pclk2: apb2_freq,
pclk2_tim: apb2_tim_freq,
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,
pll1_p: None,
rtc,
});
}

View File

@ -6,11 +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, Hsidiv as HSIPrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul,
Pllsrc as PllSource, Sw as Sysclk,
};
use crate::pac::rcc::vals::{Ckpersel, Pllrge, Pllvcosel, Timpre};
use crate::pac::rcc::vals::{Ckpersel, Hsidiv, Pllrge, Pllsrc, Pllvcosel, Sw, Timpre};
pub use crate::pac::rcc::vals::{Ckpersel as PerClockSource, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul};
use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz;
@ -61,9 +58,50 @@ 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
Mhz64,
/// 32Mhz (divided by 2)
Mhz32,
/// 16Mhz (divided by 4)
Mhz16,
/// 8Mhz (divided by 8)
Mhz8,
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum Sysclk {
/// HSI selected as sysclk
HSI,
/// HSE selected as sysclk
HSE,
/// CSI selected as sysclk
CSI,
/// PLL1_P selected as sysclk
Pll1P,
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum PllSource {
Hsi,
Csi,
Hse,
}
#[derive(Clone, Copy)]
pub struct Pll {
/// Source clock selection.
#[cfg(stm32h5)]
pub source: PllSource,
/// PLL pre-divider (DIVM).
@ -123,12 +161,19 @@ impl From<TimerPrescaler> for Timpre {
/// Configuration of the core clocks
#[non_exhaustive]
pub struct Config {
pub hsi: Option<HSIPrescaler>,
pub hsi: Option<Hsi>,
pub hse: Option<Hse>,
#[cfg(stm32h7)]
pub lse: Option<Lse>,
#[cfg(stm32h7)]
pub lsi: bool,
pub csi: bool,
pub hsi48: bool,
pub sys: Sysclk,
#[cfg(stm32h7)]
pub pll_src: PllSource,
pub pll1: Option<Pll>,
pub pll2: Option<Pll>,
#[cfg(any(rcc_h5, stm32h7))]
@ -152,11 +197,17 @@ pub struct Config {
impl Default for Config {
fn default() -> Self {
Self {
hsi: Some(HSIPrescaler::DIV1),
hsi: Some(Hsi::Mhz64),
hse: None,
#[cfg(stm32h7)]
lse: None,
#[cfg(stm32h7)]
lsi: false,
csi: false,
hsi48: false,
sys: Sysclk::HSI,
#[cfg(stm32h7)]
pll_src: PllSource::Hsi,
pll1: None,
pll2: None,
#[cfg(any(rcc_h5, stm32h7))]
@ -269,13 +320,19 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cr().modify(|w| w.set_hsion(false));
None
}
Some(hsidiv) => {
Some(hsi) => {
let (freq, hsidiv) = match hsi {
Hsi::Mhz64 => (HSI_FREQ / 1u32, Hsidiv::DIV1),
Hsi::Mhz32 => (HSI_FREQ / 2u32, Hsidiv::DIV2),
Hsi::Mhz16 => (HSI_FREQ / 4u32, Hsidiv::DIV4),
Hsi::Mhz8 => (HSI_FREQ / 8u32, Hsidiv::DIV8),
};
RCC.cr().modify(|w| {
w.set_hsidiv(hsidiv);
w.set_hsion(true);
});
while !RCC.cr().read().hsirdy() {}
Some(HSI_FREQ / hsidiv)
Some(freq)
}
};
@ -320,29 +377,25 @@ pub(crate) unsafe fn init(config: Config) {
}
};
// H7 has shared PLLSRC, check it's equal in all PLLs.
#[cfg(stm32h7)]
{
let plls = [&config.pll1, &config.pll2, &config.pll3];
if !super::util::all_equal(plls.into_iter().flatten().map(|p| p.source)) {
panic!("Source must be equal across all enabled PLLs.")
};
}
// Configure PLLs.
let pll_input = PllInput { csi, hse, hsi };
let pll_input = PllInput {
csi,
hse,
hsi,
#[cfg(stm32h7)]
source: config.pll_src,
};
let pll1 = init_pll(0, config.pll1, &pll_input);
let pll2 = init_pll(1, config.pll2, &pll_input);
#[cfg(any(rcc_h5, stm32h7))]
let pll3 = init_pll(2, config.pll3, &pll_input);
// Configure sysclk
let sys = match config.sys {
Sysclk::HSI => unwrap!(hsi),
Sysclk::HSE => unwrap!(hse),
Sysclk::CSI => unwrap!(csi),
Sysclk::PLL1_P => unwrap!(pll1.p),
_ => unreachable!(),
let (sys, sw) = match config.sys {
Sysclk::HSI => (unwrap!(hsi), Sw::HSI),
Sysclk::HSE => (unwrap!(hse), Sw::HSE),
Sysclk::CSI => (unwrap!(csi), Sw::CSI),
Sysclk::Pll1P => (unwrap!(pll1.p), Sw::PLL1),
};
// Check limits.
@ -353,14 +406,7 @@ pub(crate) unsafe fn init(config: Config) {
VoltageScale::Scale2 => (Hertz(150_000_000), Hertz(150_000_000)),
VoltageScale::Scale3 => (Hertz(100_000_000), Hertz(100_000_000)),
};
#[cfg(pwr_h7rm0455)]
let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale {
VoltageScale::Scale0 => (Hertz(280_000_000), Hertz(280_000_000), Hertz(140_000_000)),
VoltageScale::Scale1 => (Hertz(225_000_000), Hertz(225_000_000), Hertz(112_500_000)),
VoltageScale::Scale2 => (Hertz(160_000_000), Hertz(160_000_000), Hertz(80_000_000)),
VoltageScale::Scale3 => (Hertz(88_000_000), Hertz(88_000_000), Hertz(44_000_000)),
};
#[cfg(all(stm32h7, not(pwr_h7rm0455)))]
#[cfg(stm32h7)]
let (d1cpre_clk_max, hclk_max, pclk_max) = match config.voltage_scale {
VoltageScale::Scale0 => (Hertz(480_000_000), Hertz(240_000_000), Hertz(120_000_000)),
VoltageScale::Scale1 => (Hertz(400_000_000), Hertz(200_000_000), Hertz(100_000_000)),
@ -407,12 +453,12 @@ pub(crate) unsafe fn init(config: Config) {
};
#[cfg(stm32h5)]
let adc = match config.adc_clock_source {
AdcClockSource::HCLK1 => Some(hclk),
AdcClockSource::SYS => Some(sys),
AdcClockSource::HCLK => Some(hclk),
AdcClockSource::SYSCLK => Some(sys),
AdcClockSource::PLL2_R => pll2.r,
AdcClockSource::HSE => hse,
AdcClockSource::HSI => hsi,
AdcClockSource::CSI => csi,
AdcClockSource::HSI_KER => hsi,
AdcClockSource::CSI_KER => csi,
_ => unreachable!(),
};
@ -466,8 +512,8 @@ pub(crate) unsafe fn init(config: Config) {
RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into()));
RCC.cfgr().modify(|w| w.set_sw(config.sys));
while RCC.cfgr().read().sws() != config.sys {}
RCC.cfgr().modify(|w| w.set_sw(sw));
while RCC.cfgr().read().sws() != sw {}
// IO compensation cell - Requires CSI clock and SYSCFG
#[cfg(stm32h7)] // TODO h5
@ -486,65 +532,66 @@ pub(crate) unsafe fn init(config: Config) {
set_freqs(Clocks {
sys,
hclk1: hclk,
hclk2: hclk,
hclk3: hclk,
hclk4: hclk,
pclk1: apb1,
pclk2: apb2,
pclk3: apb3,
ahb1: hclk,
ahb2: hclk,
ahb3: hclk,
ahb4: hclk,
apb1,
apb2,
apb3,
#[cfg(stm32h7)]
pclk4: apb4,
#[cfg(stm32h5)]
pclk4: Hertz(1),
pclk1_tim: apb1_tim,
pclk2_tim: apb2_tim,
apb4,
apb1_tim,
apb2_tim,
adc,
rtc,
#[cfg(any(stm32h5, stm32h7))]
hsi: None,
#[cfg(stm32h5)]
hsi48: None,
mux_rcc_pclk1: Some(apb1),
#[cfg(stm32h5)]
lsi: None,
#[cfg(any(stm32h5, stm32h7))]
csi: None,
mux_pll2_q: None,
#[cfg(stm32h5)]
mux_pll3_q: None,
#[cfg(stm32h5)]
mux_hsi_ker: None,
#[cfg(stm32h5)]
mux_csi_ker: None,
#[cfg(stm32h5)]
mux_lse: None,
#[cfg(stm32h5)]
mux_pll1_q: pll1.q,
#[cfg(stm32h5)]
mux_pll2_p: pll2.p,
#[cfg(rcc_h5)]
mux_pll3_p: pll3.p,
#[cfg(stm32h5)]
mux_audioclk: None,
#[cfg(stm32h5)]
mux_per: None,
#[cfg(any(stm32h5, stm32h7))]
lse: None,
#[cfg(any(stm32h5, stm32h7))]
hse: None,
#[cfg(any(stm32h5, stm32h7))]
pll1_q: pll1.q,
#[cfg(any(stm32h5, stm32h7))]
pll2_p: pll2.p,
#[cfg(any(stm32h5, stm32h7))]
pll2_q: pll2.q,
#[cfg(any(stm32h5, stm32h7))]
pll2_r: pll2.r,
#[cfg(any(rcc_h5, stm32h7))]
pll3_p: pll3.p,
#[cfg(any(rcc_h5, stm32h7))]
pll3_q: pll3.q,
#[cfg(any(rcc_h5, stm32h7))]
pll3_r: pll3.r,
#[cfg(rcc_h50)]
pll3_p: None,
#[cfg(rcc_h50)]
pll3_q: None,
#[cfg(rcc_h50)]
pll3_r: None,
#[cfg(rcc_h5)]
mux_pll3_r: pll3.r,
#[cfg(all(not(rcc_h5), stm32h5))]
mux_pll3_r: None,
#[cfg(stm32h5)]
mux_rcc_pclk3: Some(apb3),
#[cfg(stm32h5)]
mux_pll3_1: None,
#[cfg(stm32h5)]
mux_hsi48_ker: None,
#[cfg(stm32h5)]
mux_lsi_ker: None,
#[cfg(stm32h5)]
mux_pll2_r: pll2.r,
#[cfg(stm32h5)]
mux_rcc_pclk2: Some(apb2),
#[cfg(stm32h5)]
mux_rcc_pclk4: None,
#[cfg(stm32h5)]
mux_hse: hse,
#[cfg(stm32h5)]
audioclk: None,
#[cfg(any(stm32h5, stm32h7))]
per: None,
#[cfg(stm32h7)]
rcc_pclk_d3: None,
mux_hsi48: None,
});
}
@ -552,6 +599,8 @@ struct PllInput {
hsi: Option<Hertz>,
hse: Option<Hertz>,
csi: Option<Hertz>,
#[cfg(stm32h7)]
source: PllSource,
}
struct PllOutput {
@ -581,11 +630,15 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
};
};
let in_clk = match config.source {
PllSource::DISABLE => panic!("must not set PllSource::Disable"),
PllSource::HSI => unwrap!(input.hsi),
PllSource::HSE => unwrap!(input.hse),
PllSource::CSI => unwrap!(input.csi),
#[cfg(stm32h5)]
let source = config.source;
#[cfg(stm32h7)]
let source = input.source;
let (in_clk, src) = match source {
PllSource::Hsi => (unwrap!(input.hsi), Pllsrc::HSI),
PllSource::Hse => (unwrap!(input.hse), Pllsrc::HSE),
PllSource::Csi => (unwrap!(input.csi), Pllsrc::CSI),
};
let ref_clk = in_clk / config.prediv as u32;
@ -625,7 +678,7 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
#[cfg(stm32h5)]
RCC.pllcfgr(num).write(|w| {
w.set_pllsrc(config.source);
w.set_pllsrc(src);
w.set_divm(config.prediv);
w.set_pllvcosel(vco_range);
w.set_pllrge(ref_range);
@ -639,7 +692,7 @@ fn init_pll(num: usize, config: Option<Pll>, input: &PllInput) -> PllOutput {
{
RCC.pllckselr().modify(|w| {
w.set_divm(num, config.prediv);
w.set_pllsrc(config.source);
w.set_pllsrc(src);
});
RCC.pllcfgr().modify(|w| {
w.set_pllvcosel(num, vco_range);

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