aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGustav Toft <[email protected]>2024-06-05 08:11:50 +0200
committerGustav Toft <[email protected]>2024-06-05 08:11:50 +0200
commit319e18b3997756942803cb1c10ae43327a4e3056 (patch)
tree428f0d698d58dd569f9b3fb8b1ee47c2ca9a70a1
parentd3c3670a966cd68b8d2d46a732ab971390ec3006 (diff)
parent5f9bc6def7ea8698a6ce45d8e12e1d1bd8cce876 (diff)
Merge branch 'main' of https://github.com/embassy-rs/embassy into fix_main
-rw-r--r--docs/pages/faq.adoc2
-rw-r--r--docs/pages/getting_started.adoc2
-rw-r--r--embassy-boot-nrf/Cargo.toml1
-rw-r--r--embassy-boot-rp/Cargo.toml2
-rw-r--r--embassy-boot-rp/build.rs1
-rw-r--r--embassy-boot-stm32/Cargo.toml2
-rw-r--r--embassy-boot-stm32/build.rs1
-rw-r--r--embassy-boot/README.md2
-rw-r--r--embassy-executor/build.rs31
-rw-r--r--embassy-executor/build_common.rs109
-rw-r--r--embassy-hal-internal/build.rs30
-rw-r--r--embassy-hal-internal/build_common.rs109
-rw-r--r--embassy-net-adin1110/Cargo.toml1
-rw-r--r--embassy-net-adin1110/src/lib.rs2
-rwxr-xr-xembassy-nrf/src/qspi.rs2
-rw-r--r--embassy-stm32-wpan/Cargo.toml2
-rw-r--r--embassy-stm32/Cargo.toml4
-rw-r--r--embassy-stm32/build.rs364
-rw-r--r--embassy-stm32/build_common.rs109
-rw-r--r--embassy-stm32/src/adc/f1.rs6
-rw-r--r--embassy-stm32/src/adc/f3.rs6
-rw-r--r--embassy-stm32/src/adc/f3_v1_1.rs6
-rw-r--r--embassy-stm32/src/adc/g4.rs4
-rw-r--r--embassy-stm32/src/adc/mod.rs6
-rw-r--r--embassy-stm32/src/adc/v1.rs6
-rw-r--r--embassy-stm32/src/adc/v2.rs8
-rw-r--r--embassy-stm32/src/adc/v3.rs4
-rw-r--r--embassy-stm32/src/adc/v4.rs4
-rw-r--r--embassy-stm32/src/can/bxcan/filter.rs70
-rw-r--r--embassy-stm32/src/can/bxcan/mod.rs381
-rw-r--r--embassy-stm32/src/can/bxcan/registers.rs24
-rw-r--r--embassy-stm32/src/can/fd/peripheral.rs58
-rw-r--r--embassy-stm32/src/can/fdcan.rs441
-rw-r--r--embassy-stm32/src/cordic/mod.rs6
-rw-r--r--embassy-stm32/src/crc/v1.rs5
-rw-r--r--embassy-stm32/src/crc/v2v3.rs5
-rw-r--r--embassy-stm32/src/cryp/mod.rs112
-rw-r--r--embassy-stm32/src/dac/mod.rs22
-rw-r--r--embassy-stm32/src/dcmi.rs4
-rw-r--r--embassy-stm32/src/dma/util.rs1
-rw-r--r--embassy-stm32/src/dsihost.rs16
-rw-r--r--embassy-stm32/src/flash/mod.rs4
-rw-r--r--embassy-stm32/src/fmc.rs12
-rw-r--r--embassy-stm32/src/gpio.rs2
-rw-r--r--embassy-stm32/src/hash/mod.rs5
-rw-r--r--embassy-stm32/src/hrtim/mod.rs4
-rw-r--r--embassy-stm32/src/i2c/mod.rs93
-rw-r--r--embassy-stm32/src/i2c/v1.rs6
-rw-r--r--embassy-stm32/src/i2c/v2.rs6
-rw-r--r--embassy-stm32/src/i2s.rs317
-rw-r--r--embassy-stm32/src/ipcc.rs5
-rw-r--r--embassy-stm32/src/lib.rs9
-rw-r--r--embassy-stm32/src/ltdc.rs10
-rw-r--r--embassy-stm32/src/opamp.rs26
-rw-r--r--embassy-stm32/src/ospi/mod.rs6
-rw-r--r--embassy-stm32/src/qspi/mod.rs4
-rw-r--r--embassy-stm32/src/rcc/bd.rs6
-rw-r--r--embassy-stm32/src/rcc/f013.rs10
-rw-r--r--embassy-stm32/src/rcc/hsi48.rs4
-rw-r--r--embassy-stm32/src/rcc/mod.rs252
-rw-r--r--embassy-stm32/src/rng.rs4
-rw-r--r--embassy-stm32/src/rtc/datetime.rs59
-rw-r--r--embassy-stm32/src/rtc/low_power.rs230
-rw-r--r--embassy-stm32/src/rtc/mod.rs206
-rw-r--r--embassy-stm32/src/rtc/v2.rs8
-rw-r--r--embassy-stm32/src/rtc/v3.rs8
-rw-r--r--embassy-stm32/src/sai/mod.rs6
-rw-r--r--embassy-stm32/src/sdmmc/mod.rs4
-rw-r--r--embassy-stm32/src/spi/mod.rs222
-rw-r--r--embassy-stm32/src/time_driver.rs4
-rw-r--r--embassy-stm32/src/timer/input_capture.rs39
-rw-r--r--embassy-stm32/src/timer/low_level.rs33
-rw-r--r--embassy-stm32/src/timer/mod.rs1
-rw-r--r--embassy-stm32/src/timer/pwm_input.rs114
-rw-r--r--embassy-stm32/src/tsc/mod.rs6
-rw-r--r--embassy-stm32/src/ucpd.rs8
-rw-r--r--embassy-stm32/src/usart/buffered.rs155
-rw-r--r--embassy-stm32/src/usart/mod.rs139
-rw-r--r--embassy-stm32/src/usart/ringbuffered.rs10
-rw-r--r--embassy-stm32/src/usb/mod.rs4
-rw-r--r--embassy-stm32/src/usb/otg.rs4
-rw-r--r--embassy-stm32/src/usb/usb.rs4
-rw-r--r--embassy-sync/build.rs32
-rw-r--r--embassy-sync/build_common.rs109
-rw-r--r--embassy-sync/src/lib.rs2
-rw-r--r--embassy-time/Cargo.toml10
-rw-r--r--embassy-time/src/lib.rs17
-rw-r--r--embassy-usb-dfu/Cargo.toml4
-rw-r--r--examples/boot/application/nrf/Cargo.toml7
-rw-r--r--examples/boot/application/stm32f3/Cargo.toml1
-rw-r--r--examples/boot/application/stm32f3/src/bin/a.rs2
-rw-r--r--examples/boot/application/stm32f3/src/bin/b.rs2
-rw-r--r--examples/boot/application/stm32f7/Cargo.toml1
-rw-r--r--examples/boot/application/stm32f7/src/bin/a.rs2
-rw-r--r--examples/boot/application/stm32f7/src/bin/b.rs2
-rw-r--r--examples/boot/application/stm32h7/Cargo.toml1
-rw-r--r--examples/boot/application/stm32h7/src/bin/a.rs2
-rw-r--r--examples/boot/application/stm32h7/src/bin/b.rs2
-rw-r--r--examples/boot/application/stm32l0/Cargo.toml1
-rw-r--r--examples/boot/application/stm32l0/src/bin/a.rs2
-rw-r--r--examples/boot/application/stm32l0/src/bin/b.rs2
-rw-r--r--examples/boot/application/stm32l1/Cargo.toml1
-rw-r--r--examples/boot/application/stm32l1/src/bin/a.rs2
-rw-r--r--examples/boot/application/stm32l1/src/bin/b.rs2
-rw-r--r--examples/boot/application/stm32l4/Cargo.toml1
-rw-r--r--examples/boot/application/stm32l4/src/bin/a.rs2
-rw-r--r--examples/boot/application/stm32l4/src/bin/b.rs2
-rw-r--r--examples/boot/application/stm32wb-dfu/src/main.rs2
-rw-r--r--examples/boot/application/stm32wl/Cargo.toml1
-rw-r--r--examples/boot/application/stm32wl/src/bin/a.rs2
-rw-r--r--examples/boot/application/stm32wl/src/bin/b.rs2
-rw-r--r--examples/boot/bootloader/nrf/Cargo.toml2
-rw-r--r--examples/boot/bootloader/rp/Cargo.toml2
-rw-r--r--examples/boot/bootloader/stm32-dual-bank/Cargo.toml3
-rw-r--r--examples/boot/bootloader/stm32/Cargo.toml2
-rw-r--r--examples/boot/bootloader/stm32wb-dfu/Cargo.toml2
-rw-r--r--examples/rp/src/bin/zerocopy.rs94
-rw-r--r--examples/stm32f1/src/bin/input_capture.rs52
-rw-r--r--examples/stm32f1/src/bin/pwm_input.rs54
-rw-r--r--examples/stm32f4/src/bin/i2s_dma.rs3
-rw-r--r--examples/stm32f4/src/bin/pwm_input.rs54
-rw-r--r--examples/stm32f4/src/bin/usb_ethernet.rs2
-rw-r--r--examples/stm32f4/src/bin/usb_hid_keyboard.rs2
-rw-r--r--examples/stm32f4/src/bin/usb_hid_mouse.rs2
-rw-r--r--examples/stm32f4/src/bin/usb_raw.rs2
-rw-r--r--examples/stm32f4/src/bin/usb_serial.rs2
-rw-r--r--examples/stm32f7/src/bin/can.rs6
-rw-r--r--examples/stm32f7/src/bin/usb_serial.rs2
-rw-r--r--examples/stm32g0/src/bin/spi_neopixel.rs2
-rw-r--r--examples/stm32h7/src/bin/usb_serial.rs2
-rw-r--r--examples/stm32l4/src/bin/usb_serial.rs2
-rw-r--r--rust-toolchain-nightly.toml2
-rw-r--r--tests/stm32/Cargo.toml30
-rw-r--r--tests/stm32/build.rs1
-rw-r--r--tests/stm32/src/bin/can.rs6
-rw-r--r--tests/stm32/src/bin/can_common.rs9
-rw-r--r--tests/stm32/src/bin/fdcan.rs2
-rw-r--r--tests/stm32/src/bin/spi.rs58
-rw-r--r--tests/stm32/src/bin/spi_dma.rs89
139 files changed, 3168 insertions, 1559 deletions
diff --git a/docs/pages/faq.adoc b/docs/pages/faq.adoc
index bb088dfb6..a2f56a539 100644
--- a/docs/pages/faq.adoc
+++ b/docs/pages/faq.adoc
@@ -299,7 +299,7 @@ You can add a section to your `Cargo.toml` file like this, you'll need to patch
299 299
300Using `patch` will replace all direct AND indirect dependencies. 300Using `patch` will replace all direct AND indirect dependencies.
301 301
302See the link:https://embassy.dev/book/dev/new_project.html#_cargo_toml[new project docs] for more details on this approach. 302See the link:https://embassy.dev/book/#_starting_a_new_project[new project docs] for more details on this approach.
303 303
304[source,toml] 304[source,toml]
305---- 305----
diff --git a/docs/pages/getting_started.adoc b/docs/pages/getting_started.adoc
index 465059922..77275a857 100644
--- a/docs/pages/getting_started.adoc
+++ b/docs/pages/getting_started.adoc
@@ -131,7 +131,7 @@ If you’re using a raspberry pi pico-w, make sure you’re running `+cargo run
131 131
132If you’re using an rp2040 debug probe (e.g. the pico probe) and are having issues after running `probe-rs info`, unplug and reconnect the probe, letting it power cycle. Running `probe-rs info` is link:https://github.com/probe-rs/probe-rs/issues/1849[known to put the pico probe into an unusable state]. 132If you’re using an rp2040 debug probe (e.g. the pico probe) and are having issues after running `probe-rs info`, unplug and reconnect the probe, letting it power cycle. Running `probe-rs info` is link:https://github.com/probe-rs/probe-rs/issues/1849[known to put the pico probe into an unusable state].
133 133
134If you’re still having problems, check the link:https://embassy.dev/book/dev/faq.html[FAQ], or ask for help in the link:https://matrix.to/#/#embassy-rs:matrix.org[Embassy Chat Room]. 134If you’re still having problems, check the link:https://embassy.dev/book/#_frequently_asked_questions[FAQ], or ask for help in the link:https://matrix.to/#/#embassy-rs:matrix.org[Embassy Chat Room].
135 135
136== What's next? 136== What's next?
137 137
diff --git a/embassy-boot-nrf/Cargo.toml b/embassy-boot-nrf/Cargo.toml
index e6bb27043..86bfc21f4 100644
--- a/embassy-boot-nrf/Cargo.toml
+++ b/embassy-boot-nrf/Cargo.toml
@@ -22,6 +22,7 @@ target = "thumbv7em-none-eabi"
22 22
23[dependencies] 23[dependencies]
24defmt = { version = "0.3", optional = true } 24defmt = { version = "0.3", optional = true }
25log = { version = "0.4.17", optional = true }
25 26
26embassy-sync = { version = "0.6.0", path = "../embassy-sync" } 27embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
27embassy-nrf = { version = "0.1.0", path = "../embassy-nrf", default-features = false } 28embassy-nrf = { version = "0.1.0", path = "../embassy-nrf", default-features = false }
diff --git a/embassy-boot-rp/Cargo.toml b/embassy-boot-rp/Cargo.toml
index 0bd8abf4c..de2ae3780 100644
--- a/embassy-boot-rp/Cargo.toml
+++ b/embassy-boot-rp/Cargo.toml
@@ -21,7 +21,6 @@ target = "thumbv6m-none-eabi"
21 21
22[dependencies] 22[dependencies]
23defmt = { version = "0.3", optional = true } 23defmt = { version = "0.3", optional = true }
24defmt-rtt = { version = "0.4", optional = true }
25log = { version = "0.4", optional = true } 24log = { version = "0.4", optional = true }
26 25
27embassy-sync = { version = "0.6.0", path = "../embassy-sync" } 26embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
@@ -46,7 +45,6 @@ log = [
46 "embassy-boot/log", 45 "embassy-boot/log",
47 "embassy-rp/log", 46 "embassy-rp/log",
48] 47]
49debug = ["defmt-rtt"]
50 48
51[profile.dev] 49[profile.dev]
52debug = 2 50debug = 2
diff --git a/embassy-boot-rp/build.rs b/embassy-boot-rp/build.rs
index 2cbc7ef5e..bfaee3503 100644
--- a/embassy-boot-rp/build.rs
+++ b/embassy-boot-rp/build.rs
@@ -5,4 +5,5 @@ fn main() {
5 if target.starts_with("thumbv6m-") { 5 if target.starts_with("thumbv6m-") {
6 println!("cargo:rustc-cfg=armv6m"); 6 println!("cargo:rustc-cfg=armv6m");
7 } 7 }
8 println!("cargo:rustc-check-cfg=cfg(armv6m)");
8} 9}
diff --git a/embassy-boot-stm32/Cargo.toml b/embassy-boot-stm32/Cargo.toml
index a3661f6cb..d4525a6de 100644
--- a/embassy-boot-stm32/Cargo.toml
+++ b/embassy-boot-stm32/Cargo.toml
@@ -22,7 +22,6 @@ target = "thumbv7em-none-eabi"
22 22
23[dependencies] 23[dependencies]
24defmt = { version = "0.3", optional = true } 24defmt = { version = "0.3", optional = true }
25defmt-rtt = { version = "0.4", optional = true }
26log = { version = "0.4", optional = true } 25log = { version = "0.4", optional = true }
27 26
28embassy-sync = { version = "0.6.0", path = "../embassy-sync" } 27embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
@@ -37,7 +36,6 @@ cfg-if = "1.0.0"
37[features] 36[features]
38defmt = ["dep:defmt", "embassy-boot/defmt", "embassy-stm32/defmt"] 37defmt = ["dep:defmt", "embassy-boot/defmt", "embassy-stm32/defmt"]
39log = ["dep:log", "embassy-boot/log", "embassy-stm32/log"] 38log = ["dep:log", "embassy-boot/log", "embassy-stm32/log"]
40debug = ["defmt-rtt"]
41 39
42[profile.dev] 40[profile.dev]
43debug = 2 41debug = 2
diff --git a/embassy-boot-stm32/build.rs b/embassy-boot-stm32/build.rs
index 2cbc7ef5e..bfaee3503 100644
--- a/embassy-boot-stm32/build.rs
+++ b/embassy-boot-stm32/build.rs
@@ -5,4 +5,5 @@ fn main() {
5 if target.starts_with("thumbv6m-") { 5 if target.starts_with("thumbv6m-") {
6 println!("cargo:rustc-cfg=armv6m"); 6 println!("cargo:rustc-cfg=armv6m");
7 } 7 }
8 println!("cargo:rustc-check-cfg=cfg(armv6m)");
8} 9}
diff --git a/embassy-boot/README.md b/embassy-boot/README.md
index 812c43524..c893c83e1 100644
--- a/embassy-boot/README.md
+++ b/embassy-boot/README.md
@@ -24,7 +24,7 @@ For any partition, the following preconditions are required:
24 24
25The linker scripts for the application and bootloader look similar, but the FLASH region must point to the BOOTLOADER partition for the bootloader, and the ACTIVE partition for the application. 25The linker scripts for the application and bootloader look similar, but the FLASH region must point to the BOOTLOADER partition for the bootloader, and the ACTIVE partition for the application.
26 26
27For more details on the bootloader, see [the documentation](https://embassy.dev/book/dev/bootloader.html). 27For more details on the bootloader, see [the documentation](https://embassy.dev/book/#_bootloader).
28 28
29## Hardware support 29## Hardware support
30 30
diff --git a/embassy-executor/build.rs b/embassy-executor/build.rs
index 07f31e3fb..8a41d7503 100644
--- a/embassy-executor/build.rs
+++ b/embassy-executor/build.rs
@@ -3,6 +3,9 @@ use std::fmt::Write;
3use std::path::PathBuf; 3use std::path::PathBuf;
4use std::{env, fs}; 4use std::{env, fs};
5 5
6#[path = "./build_common.rs"]
7mod common;
8
6static CONFIGS: &[(&str, usize)] = &[ 9static CONFIGS: &[(&str, usize)] = &[
7 // BEGIN AUTOGENERATED CONFIG FEATURES 10 // BEGIN AUTOGENERATED CONFIG FEATURES
8 // Generated by gen_config.py. DO NOT EDIT. 11 // Generated by gen_config.py. DO NOT EDIT.
@@ -91,30 +94,6 @@ fn main() {
91 let out_file = out_dir.join("config.rs").to_string_lossy().to_string(); 94 let out_file = out_dir.join("config.rs").to_string_lossy().to_string();
92 fs::write(out_file, data).unwrap(); 95 fs::write(out_file, data).unwrap();
93 96
94 // cortex-m targets 97 let mut rustc_cfgs = common::CfgSet::new();
95 let target = env::var("TARGET").unwrap(); 98 common::set_target_cfgs(&mut rustc_cfgs);
96
97 if target.starts_with("thumbv6m-") {
98 println!("cargo:rustc-cfg=cortex_m");
99 println!("cargo:rustc-cfg=armv6m");
100 } else if target.starts_with("thumbv7m-") {
101 println!("cargo:rustc-cfg=cortex_m");
102 println!("cargo:rustc-cfg=armv7m");
103 } else if target.starts_with("thumbv7em-") {
104 println!("cargo:rustc-cfg=cortex_m");
105 println!("cargo:rustc-cfg=armv7m");
106 println!("cargo:rustc-cfg=armv7em"); // (not currently used)
107 } else if target.starts_with("thumbv8m.base") {
108 println!("cargo:rustc-cfg=cortex_m");
109 println!("cargo:rustc-cfg=armv8m");
110 println!("cargo:rustc-cfg=armv8m_base");
111 } else if target.starts_with("thumbv8m.main") {
112 println!("cargo:rustc-cfg=cortex_m");
113 println!("cargo:rustc-cfg=armv8m");
114 println!("cargo:rustc-cfg=armv8m_main");
115 }
116
117 if target.ends_with("-eabihf") {
118 println!("cargo:rustc-cfg=has_fpu");
119 }
120} 99}
diff --git a/embassy-executor/build_common.rs b/embassy-executor/build_common.rs
new file mode 100644
index 000000000..2c65f8529
--- /dev/null
+++ b/embassy-executor/build_common.rs
@@ -0,0 +1,109 @@
1// NOTE: this file is copy-pasted between several Embassy crates, because there is no
2// straightforward way to share this code:
3// - it cannot be placed into the root of the repo and linked from each build.rs using `#[path =
4// "../build_common.rs"]`, because `cargo publish` requires that all files published with a crate
5// reside in the crate's directory,
6// - it cannot be symlinked from `embassy-xxx/build_common.rs` to `../build_common.rs`, because
7// symlinks don't work on Windows.
8
9use std::collections::HashSet;
10use std::env;
11use std::ffi::OsString;
12use std::process::Command;
13
14/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring
15/// them (`cargo:rust-check-cfg=cfg(X)`).
16#[derive(Debug)]
17pub struct CfgSet {
18 enabled: HashSet<String>,
19 declared: HashSet<String>,
20 emit_declared: bool,
21}
22
23impl CfgSet {
24 pub fn new() -> Self {
25 Self {
26 enabled: HashSet::new(),
27 declared: HashSet::new(),
28 emit_declared: is_rustc_nightly(),
29 }
30 }
31
32 /// Enable a config, which can then be used in `#[cfg(...)]` for conditional compilation.
33 ///
34 /// All configs that can potentially be enabled should be unconditionally declared using
35 /// [`Self::declare()`].
36 pub fn enable(&mut self, cfg: impl AsRef<str>) {
37 if self.enabled.insert(cfg.as_ref().to_owned()) {
38 println!("cargo:rustc-cfg={}", cfg.as_ref());
39 }
40 }
41
42 pub fn enable_all(&mut self, cfgs: &[impl AsRef<str>]) {
43 for cfg in cfgs.iter() {
44 self.enable(cfg.as_ref());
45 }
46 }
47
48 /// Declare a valid config for conditional compilation, without enabling it.
49 ///
50 /// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid.
51 pub fn declare(&mut self, cfg: impl AsRef<str>) {
52 if self.declared.insert(cfg.as_ref().to_owned()) && self.emit_declared {
53 println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref());
54 }
55 }
56
57 pub fn declare_all(&mut self, cfgs: &[impl AsRef<str>]) {
58 for cfg in cfgs.iter() {
59 self.declare(cfg.as_ref());
60 }
61 }
62
63 pub fn set(&mut self, cfg: impl Into<String>, enable: bool) {
64 let cfg = cfg.into();
65 if enable {
66 self.enable(cfg.clone());
67 }
68 self.declare(cfg);
69 }
70}
71
72fn is_rustc_nightly() -> bool {
73 let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
74
75 let output = Command::new(rustc)
76 .arg("--version")
77 .output()
78 .expect("failed to run `rustc --version`");
79
80 String::from_utf8_lossy(&output.stdout).contains("nightly")
81}
82
83/// Sets configs that describe the target platform.
84pub fn set_target_cfgs(cfgs: &mut CfgSet) {
85 let target = env::var("TARGET").unwrap();
86
87 if target.starts_with("thumbv6m-") {
88 cfgs.enable_all(&["cortex_m", "armv6m"]);
89 } else if target.starts_with("thumbv7m-") {
90 cfgs.enable_all(&["cortex_m", "armv7m"]);
91 } else if target.starts_with("thumbv7em-") {
92 cfgs.enable_all(&["cortex_m", "armv7m", "armv7em"]);
93 } else if target.starts_with("thumbv8m.base") {
94 cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_base"]);
95 } else if target.starts_with("thumbv8m.main") {
96 cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_main"]);
97 }
98 cfgs.declare_all(&[
99 "cortex_m",
100 "armv6m",
101 "armv7m",
102 "armv7em",
103 "armv8m",
104 "armv8m_base",
105 "armv8m_main",
106 ]);
107
108 cfgs.set("has_fpu", target.ends_with("-eabihf"));
109}
diff --git a/embassy-hal-internal/build.rs b/embassy-hal-internal/build.rs
index 6fe82b44f..ecd2c0c9f 100644
--- a/embassy-hal-internal/build.rs
+++ b/embassy-hal-internal/build.rs
@@ -1,29 +1,7 @@
1use std::env; 1#[path = "./build_common.rs"]
2mod common;
2 3
3fn main() { 4fn main() {
4 let target = env::var("TARGET").unwrap(); 5 let mut cfgs = common::CfgSet::new();
5 6 common::set_target_cfgs(&mut cfgs);
6 if target.starts_with("thumbv6m-") {
7 println!("cargo:rustc-cfg=cortex_m");
8 println!("cargo:rustc-cfg=armv6m");
9 } else if target.starts_with("thumbv7m-") {
10 println!("cargo:rustc-cfg=cortex_m");
11 println!("cargo:rustc-cfg=armv7m");
12 } else if target.starts_with("thumbv7em-") {
13 println!("cargo:rustc-cfg=cortex_m");
14 println!("cargo:rustc-cfg=armv7m");
15 println!("cargo:rustc-cfg=armv7em"); // (not currently used)
16 } else if target.starts_with("thumbv8m.base") {
17 println!("cargo:rustc-cfg=cortex_m");
18 println!("cargo:rustc-cfg=armv8m");
19 println!("cargo:rustc-cfg=armv8m_base");
20 } else if target.starts_with("thumbv8m.main") {
21 println!("cargo:rustc-cfg=cortex_m");
22 println!("cargo:rustc-cfg=armv8m");
23 println!("cargo:rustc-cfg=armv8m_main");
24 }
25
26 if target.ends_with("-eabihf") {
27 println!("cargo:rustc-cfg=has_fpu");
28 }
29} 7}
diff --git a/embassy-hal-internal/build_common.rs b/embassy-hal-internal/build_common.rs
new file mode 100644
index 000000000..2c65f8529
--- /dev/null
+++ b/embassy-hal-internal/build_common.rs
@@ -0,0 +1,109 @@
1// NOTE: this file is copy-pasted between several Embassy crates, because there is no
2// straightforward way to share this code:
3// - it cannot be placed into the root of the repo and linked from each build.rs using `#[path =
4// "../build_common.rs"]`, because `cargo publish` requires that all files published with a crate
5// reside in the crate's directory,
6// - it cannot be symlinked from `embassy-xxx/build_common.rs` to `../build_common.rs`, because
7// symlinks don't work on Windows.
8
9use std::collections::HashSet;
10use std::env;
11use std::ffi::OsString;
12use std::process::Command;
13
14/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring
15/// them (`cargo:rust-check-cfg=cfg(X)`).
16#[derive(Debug)]
17pub struct CfgSet {
18 enabled: HashSet<String>,
19 declared: HashSet<String>,
20 emit_declared: bool,
21}
22
23impl CfgSet {
24 pub fn new() -> Self {
25 Self {
26 enabled: HashSet::new(),
27 declared: HashSet::new(),
28 emit_declared: is_rustc_nightly(),
29 }
30 }
31
32 /// Enable a config, which can then be used in `#[cfg(...)]` for conditional compilation.
33 ///
34 /// All configs that can potentially be enabled should be unconditionally declared using
35 /// [`Self::declare()`].
36 pub fn enable(&mut self, cfg: impl AsRef<str>) {
37 if self.enabled.insert(cfg.as_ref().to_owned()) {
38 println!("cargo:rustc-cfg={}", cfg.as_ref());
39 }
40 }
41
42 pub fn enable_all(&mut self, cfgs: &[impl AsRef<str>]) {
43 for cfg in cfgs.iter() {
44 self.enable(cfg.as_ref());
45 }
46 }
47
48 /// Declare a valid config for conditional compilation, without enabling it.
49 ///
50 /// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid.
51 pub fn declare(&mut self, cfg: impl AsRef<str>) {
52 if self.declared.insert(cfg.as_ref().to_owned()) && self.emit_declared {
53 println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref());
54 }
55 }
56
57 pub fn declare_all(&mut self, cfgs: &[impl AsRef<str>]) {
58 for cfg in cfgs.iter() {
59 self.declare(cfg.as_ref());
60 }
61 }
62
63 pub fn set(&mut self, cfg: impl Into<String>, enable: bool) {
64 let cfg = cfg.into();
65 if enable {
66 self.enable(cfg.clone());
67 }
68 self.declare(cfg);
69 }
70}
71
72fn is_rustc_nightly() -> bool {
73 let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
74
75 let output = Command::new(rustc)
76 .arg("--version")
77 .output()
78 .expect("failed to run `rustc --version`");
79
80 String::from_utf8_lossy(&output.stdout).contains("nightly")
81}
82
83/// Sets configs that describe the target platform.
84pub fn set_target_cfgs(cfgs: &mut CfgSet) {
85 let target = env::var("TARGET").unwrap();
86
87 if target.starts_with("thumbv6m-") {
88 cfgs.enable_all(&["cortex_m", "armv6m"]);
89 } else if target.starts_with("thumbv7m-") {
90 cfgs.enable_all(&["cortex_m", "armv7m"]);
91 } else if target.starts_with("thumbv7em-") {
92 cfgs.enable_all(&["cortex_m", "armv7m", "armv7em"]);
93 } else if target.starts_with("thumbv8m.base") {
94 cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_base"]);
95 } else if target.starts_with("thumbv8m.main") {
96 cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_main"]);
97 }
98 cfgs.declare_all(&[
99 "cortex_m",
100 "armv6m",
101 "armv7m",
102 "armv7em",
103 "armv8m",
104 "armv8m_base",
105 "armv8m_main",
106 ]);
107
108 cfgs.set("has_fpu", target.ends_with("-eabihf"));
109}
diff --git a/embassy-net-adin1110/Cargo.toml b/embassy-net-adin1110/Cargo.toml
index 97579a467..4a856fac3 100644
--- a/embassy-net-adin1110/Cargo.toml
+++ b/embassy-net-adin1110/Cargo.toml
@@ -29,7 +29,6 @@ critical-section = { version = "1.1.2", features = ["std"] }
29futures-test = "0.3.28" 29futures-test = "0.3.28"
30 30
31[features] 31[features]
32default = [ ]
33defmt = [ "dep:defmt", "embedded-hal-1/defmt-03" ] 32defmt = [ "dep:defmt", "embedded-hal-1/defmt-03" ]
34log = ["dep:log"] 33log = ["dep:log"]
35 34
diff --git a/embassy-net-adin1110/src/lib.rs b/embassy-net-adin1110/src/lib.rs
index d98e98422..7f1c772e2 100644
--- a/embassy-net-adin1110/src/lib.rs
+++ b/embassy-net-adin1110/src/lib.rs
@@ -1,6 +1,6 @@
1#![cfg_attr(not(test), no_std)]
1#![deny(clippy::pedantic)] 2#![deny(clippy::pedantic)]
2#![allow(async_fn_in_trait)] 3#![allow(async_fn_in_trait)]
3#![cfg_attr(not(any(test, feature = "std")), no_std)]
4#![allow(clippy::module_name_repetitions)] 4#![allow(clippy::module_name_repetitions)]
5#![allow(clippy::missing_errors_doc)] 5#![allow(clippy::missing_errors_doc)]
6#![allow(clippy::missing_panics_doc)] 6#![allow(clippy::missing_panics_doc)]
diff --git a/embassy-nrf/src/qspi.rs b/embassy-nrf/src/qspi.rs
index 060fe72cd..d40096edc 100755
--- a/embassy-nrf/src/qspi.rs
+++ b/embassy-nrf/src/qspi.rs
@@ -166,7 +166,7 @@ impl<'d, T: Instance> Qspi<'d, T> {
166 $pin.conf().write(|w| { 166 $pin.conf().write(|w| {
167 w.dir().output(); 167 w.dir().output();
168 w.drive().h0h1(); 168 w.drive().h0h1();
169 #[cfg(feature = "_nrf5340-s")] 169 #[cfg(all(feature = "_nrf5340", feature = "_s"))]
170 w.mcusel().peripheral(); 170 w.mcusel().peripheral();
171 w 171 w
172 }); 172 });
diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml
index 11a0adab2..9c81a71f7 100644
--- a/embassy-stm32-wpan/Cargo.toml
+++ b/embassy-stm32-wpan/Cargo.toml
@@ -28,6 +28,8 @@ embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" }
28embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver", optional=true } 28embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver", optional=true }
29 29
30defmt = { version = "0.3", optional = true } 30defmt = { version = "0.3", optional = true }
31log = { version = "0.4.17", optional = true }
32
31cortex-m = "0.7.6" 33cortex-m = "0.7.6"
32heapless = "0.8" 34heapless = "0.8"
33aligned = "0.4.1" 35aligned = "0.4.1"
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index fde5b4786..6a1dfec26 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -72,7 +72,7 @@ rand_core = "0.6.3"
72sdio-host = "0.5.0" 72sdio-host = "0.5.0"
73critical-section = "1.1" 73critical-section = "1.1"
74#stm32-metapac = { version = "15" } 74#stm32-metapac = { version = "15" }
75stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-34c0188a682b32c32ff147d377e0629b1ebe8318" } 75stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-59b1f65bd109c3ef35782e6c44062208d0ef3d0e" }
76 76
77vcell = "0.1.3" 77vcell = "0.1.3"
78nb = "1.0.0" 78nb = "1.0.0"
@@ -97,7 +97,7 @@ proc-macro2 = "1.0.36"
97quote = "1.0.15" 97quote = "1.0.15"
98 98
99#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} 99#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
100stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-34c0188a682b32c32ff147d377e0629b1ebe8318", default-features = false, features = ["metadata"]} 100stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-59b1f65bd109c3ef35782e6c44062208d0ef3d0e", default-features = false, features = ["metadata"] }
101 101
102[features] 102[features]
103default = ["rt"] 103default = ["rt"]
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 7bf6ffba2..6aedcc228 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -9,35 +9,16 @@ use proc_macro2::{Ident, TokenStream};
9use quote::{format_ident, quote}; 9use quote::{format_ident, quote};
10use stm32_metapac::metadata::ir::BitOffset; 10use stm32_metapac::metadata::ir::BitOffset;
11use stm32_metapac::metadata::{ 11use stm32_metapac::metadata::{
12 MemoryRegionKind, PeripheralRccKernelClock, PeripheralRccRegister, PeripheralRegisters, StopMode, METADATA, 12 MemoryRegionKind, PeripheralRccKernelClock, PeripheralRccRegister, PeripheralRegisters, StopMode, ALL_CHIPS,
13 ALL_PERIPHERAL_VERSIONS, METADATA,
13}; 14};
14 15
15fn main() { 16#[path = "./build_common.rs"]
16 let target = env::var("TARGET").unwrap(); 17mod common;
17
18 if target.starts_with("thumbv6m-") {
19 println!("cargo:rustc-cfg=cortex_m");
20 println!("cargo:rustc-cfg=armv6m");
21 } else if target.starts_with("thumbv7m-") {
22 println!("cargo:rustc-cfg=cortex_m");
23 println!("cargo:rustc-cfg=armv7m");
24 } else if target.starts_with("thumbv7em-") {
25 println!("cargo:rustc-cfg=cortex_m");
26 println!("cargo:rustc-cfg=armv7m");
27 println!("cargo:rustc-cfg=armv7em"); // (not currently used)
28 } else if target.starts_with("thumbv8m.base") {
29 println!("cargo:rustc-cfg=cortex_m");
30 println!("cargo:rustc-cfg=armv8m");
31 println!("cargo:rustc-cfg=armv8m_base");
32 } else if target.starts_with("thumbv8m.main") {
33 println!("cargo:rustc-cfg=cortex_m");
34 println!("cargo:rustc-cfg=armv8m");
35 println!("cargo:rustc-cfg=armv8m_main");
36 }
37 18
38 if target.ends_with("-eabihf") { 19fn main() {
39 println!("cargo:rustc-cfg=has_fpu"); 20 let mut cfgs = common::CfgSet::new();
40 } 21 common::set_target_cfgs(&mut cfgs);
41 22
42 let chip_name = match env::vars() 23 let chip_name = match env::vars()
43 .map(|(a, _)| a) 24 .map(|(a, _)| a)
@@ -56,8 +37,15 @@ fn main() {
56 37
57 for p in METADATA.peripherals { 38 for p in METADATA.peripherals {
58 if let Some(r) = &p.registers { 39 if let Some(r) = &p.registers {
59 println!("cargo:rustc-cfg={}", r.kind); 40 cfgs.enable(r.kind);
60 println!("cargo:rustc-cfg={}_{}", r.kind, r.version); 41 cfgs.enable(format!("{}_{}", r.kind, r.version));
42 }
43 }
44
45 for &(kind, versions) in ALL_PERIPHERAL_VERSIONS.iter() {
46 cfgs.declare(kind);
47 for &version in versions.iter() {
48 cfgs.declare(format!("{}_{}", kind, version));
61 } 49 }
62 } 50 }
63 51
@@ -67,7 +55,13 @@ fn main() {
67 let mut singletons: Vec<String> = Vec::new(); 55 let mut singletons: Vec<String> = Vec::new();
68 for p in METADATA.peripherals { 56 for p in METADATA.peripherals {
69 if let Some(r) = &p.registers { 57 if let Some(r) = &p.registers {
70 println!("cargo:rustc-cfg=peri_{}", p.name.to_ascii_lowercase()); 58 if r.kind == "adccommon" || r.kind == "sai" || r.kind == "ucpd" {
59 // TODO: should we emit this for all peripherals? if so, we will need a list of all
60 // possible peripherals across all chips, so that we can declare the configs
61 // (replacing the hard-coded list of `peri_*` cfgs below)
62 cfgs.enable(format!("peri_{}", p.name.to_ascii_lowercase()));
63 }
64
71 match r.kind { 65 match r.kind {
72 // Generate singletons per pin, not per port 66 // Generate singletons per pin, not per port
73 "gpio" => { 67 "gpio" => {
@@ -87,7 +81,7 @@ fn main() {
87 if pin.signal.starts_with("MCO") { 81 if pin.signal.starts_with("MCO") {
88 let name = pin.signal.replace('_', "").to_string(); 82 let name = pin.signal.replace('_', "").to_string();
89 if !singletons.contains(&name) { 83 if !singletons.contains(&name) {
90 println!("cargo:rustc-cfg={}", name.to_ascii_lowercase()); 84 cfgs.enable(name.to_ascii_lowercase());
91 singletons.push(name); 85 singletons.push(name);
92 } 86 }
93 } 87 }
@@ -106,6 +100,20 @@ fn main() {
106 } 100 }
107 } 101 }
108 102
103 cfgs.declare_all(&[
104 "peri_adc1_common",
105 "peri_adc3_common",
106 "peri_adc12_common",
107 "peri_adc34_common",
108 "peri_sai1",
109 "peri_sai2",
110 "peri_sai3",
111 "peri_sai4",
112 "peri_ucpd1",
113 "peri_ucpd2",
114 ]);
115 cfgs.declare_all(&["mco", "mco1", "mco2"]);
116
109 // One singleton per EXTI line 117 // One singleton per EXTI line
110 for pin_num in 0..16 { 118 for pin_num in 0..16 {
111 singletons.push(format!("EXTI{}", pin_num)); 119 singletons.push(format!("EXTI{}", pin_num));
@@ -221,7 +229,13 @@ fn main() {
221 }; 229 };
222 230
223 if !time_driver_singleton.is_empty() { 231 if !time_driver_singleton.is_empty() {
224 println!("cargo:rustc-cfg=time_driver_{}", time_driver_singleton.to_lowercase()); 232 cfgs.enable(format!("time_driver_{}", time_driver_singleton.to_lowercase()));
233 }
234 for tim in [
235 "tim1", "tim2", "tim3", "tim4", "tim5", "tim8", "tim9", "tim12", "tim15", "tim20", "tim21", "tim22", "tim23",
236 "tim24",
237 ] {
238 cfgs.declare(format!("time_driver_{}", tim));
225 } 239 }
226 240
227 // ======== 241 // ========
@@ -367,9 +381,6 @@ fn main() {
367 .filter_map(|p| p.registers.as_ref()) 381 .filter_map(|p| p.registers.as_ref())
368 .find(|r| r.kind == "rcc") 382 .find(|r| r.kind == "rcc")
369 .unwrap(); 383 .unwrap();
370 for b in rcc_registers.ir.blocks {
371 eprintln!("{}", b.name);
372 }
373 let rcc_block = rcc_registers.ir.blocks.iter().find(|b| b.name == "Rcc").unwrap(); 384 let rcc_block = rcc_registers.ir.blocks.iter().find(|b| b.name == "Rcc").unwrap();
374 385
375 // ======== 386 // ========
@@ -388,7 +399,6 @@ fn main() {
388 rcc_registers: &'a PeripheralRegisters, 399 rcc_registers: &'a PeripheralRegisters,
389 chained_muxes: HashMap<&'a str, &'a PeripheralRccRegister>, 400 chained_muxes: HashMap<&'a str, &'a PeripheralRccRegister>,
390 401
391 refcount_statics: BTreeSet<Ident>,
392 clock_names: BTreeSet<String>, 402 clock_names: BTreeSet<String>,
393 muxes: BTreeSet<(Ident, Ident, Ident)>, 403 muxes: BTreeSet<(Ident, Ident, Ident)>,
394 } 404 }
@@ -397,7 +407,6 @@ fn main() {
397 rcc_registers, 407 rcc_registers,
398 chained_muxes: HashMap::new(), 408 chained_muxes: HashMap::new(),
399 409
400 refcount_statics: BTreeSet::new(),
401 clock_names: BTreeSet::new(), 410 clock_names: BTreeSet::new(),
402 muxes: BTreeSet::new(), 411 muxes: BTreeSet::new(),
403 }; 412 };
@@ -516,80 +525,64 @@ fn main() {
516 } 525 }
517 } 526 }
518 527
528 let mut refcount_idxs = HashMap::new();
529
519 for p in METADATA.peripherals { 530 for p in METADATA.peripherals {
520 if !singletons.contains(&p.name.to_string()) { 531 if !singletons.contains(&p.name.to_string()) {
521 continue; 532 continue;
522 } 533 }
523 534
524 if let Some(rcc) = &p.rcc { 535 if let Some(rcc) = &p.rcc {
525 let en = rcc.enable.as_ref().unwrap(); 536 let rst_reg = rcc.reset.as_ref();
526 537 let en_reg = rcc.enable.as_ref().unwrap();
527 let (start_rst, end_rst) = match &rcc.reset {
528 Some(rst) => {
529 let rst_reg = format_ident!("{}", rst.register.to_ascii_lowercase());
530 let set_rst_field = format_ident!("set_{}", rst.field.to_ascii_lowercase());
531 (
532 quote! {
533 crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true));
534 },
535 quote! {
536 crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false));
537 },
538 )
539 }
540 None => (TokenStream::new(), TokenStream::new()),
541 };
542
543 let pname = format_ident!("{}", p.name); 538 let pname = format_ident!("{}", p.name);
544 let en_reg = format_ident!("{}", en.register.to_ascii_lowercase());
545 let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase());
546 let en_reg_offs = rcc_block
547 .items
548 .iter()
549 .find(|i| i.name.eq_ignore_ascii_case(en.register))
550 .unwrap()
551 .byte_offset;
552 let en_reg_offs: u8 = (en_reg_offs / 4).try_into().unwrap();
553
554 let en_bit_offs = &rcc_registers
555 .ir
556 .fieldsets
557 .iter()
558 .find(|i| i.name.eq_ignore_ascii_case(en.register))
559 .unwrap()
560 .fields
561 .iter()
562 .find(|i| i.name.eq_ignore_ascii_case(en.field))
563 .unwrap()
564 .bit_offset;
565 let BitOffset::Regular(en_bit_offs) = en_bit_offs else {
566 panic!("cursed bit offset")
567 };
568 let en_bit_offs: u8 = en_bit_offs.offset.try_into().unwrap();
569 539
570 let refcount = *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1; 540 let get_offset_and_bit = |reg: &PeripheralRccRegister| -> TokenStream {
571 let (before_enable, before_disable) = if refcount { 541 let reg_offset = rcc_block
572 let refcount_static = 542 .items
573 format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase()); 543 .iter()
544 .find(|i| i.name.eq_ignore_ascii_case(reg.register))
545 .unwrap()
546 .byte_offset;
547 let reg_offset: u8 = (reg_offset / 4).try_into().unwrap();
548
549 let bit_offset = &rcc_registers
550 .ir
551 .fieldsets
552 .iter()
553 .find(|i| i.name.eq_ignore_ascii_case(reg.register))
554 .unwrap()
555 .fields
556 .iter()
557 .find(|i| i.name.eq_ignore_ascii_case(reg.field))
558 .unwrap()
559 .bit_offset;
560 let BitOffset::Regular(bit_offset) = bit_offset else {
561 panic!("cursed bit offset")
562 };
563 let bit_offset: u8 = bit_offset.offset.try_into().unwrap();
574 564
575 clock_gen.refcount_statics.insert(refcount_static.clone()); 565 quote! { (#reg_offset, #bit_offset) }
566 };
576 567
577 ( 568 let reset_offset_and_bit = match rst_reg {
578 quote! { 569 Some(rst_reg) => {
579 unsafe { refcount_statics::#refcount_static += 1 }; 570 let reset_offset_and_bit = get_offset_and_bit(rst_reg);
580 if unsafe { refcount_statics::#refcount_static } > 1 { 571 quote! { Some(#reset_offset_and_bit) }
581 return; 572 }
582 } 573 None => quote! { None },
583 }, 574 };
584 quote! { 575 let enable_offset_and_bit = get_offset_and_bit(en_reg);
585 unsafe { refcount_statics::#refcount_static -= 1 }; 576
586 if unsafe { refcount_statics::#refcount_static } > 0 { 577 let needs_refcount = *rcc_field_count.get(&(en_reg.register, en_reg.field)).unwrap() > 1;
587 return; 578 let refcount_idx = if needs_refcount {
588 } 579 let next_refcount_idx = refcount_idxs.len() as u8;
589 }, 580 let refcount_idx = *refcount_idxs
590 ) 581 .entry((en_reg.register, en_reg.field))
582 .or_insert(next_refcount_idx);
583 quote! { Some(#refcount_idx) }
591 } else { 584 } else {
592 (TokenStream::new(), TokenStream::new()) 585 quote! { None }
593 }; 586 };
594 587
595 let clock_frequency = match &rcc.kernel_clock { 588 let clock_frequency = match &rcc.kernel_clock {
@@ -599,24 +592,10 @@ fn main() {
599 592
600 // A refcount leak can result if the same field is shared by peripherals with different stop modes 593 // A refcount leak can result if the same field is shared by peripherals with different stop modes
601 // This condition should be checked in stm32-data 594 // This condition should be checked in stm32-data
602 let stop_refcount = match rcc.stop_mode { 595 let stop_mode = match rcc.stop_mode {
603 StopMode::Standby => None, 596 StopMode::Standby => quote! { crate::rcc::StopMode::Standby },
604 StopMode::Stop2 => Some(quote! { REFCOUNT_STOP2 }), 597 StopMode::Stop2 => quote! { crate::rcc::StopMode::Stop2 },
605 StopMode::Stop1 => Some(quote! { REFCOUNT_STOP1 }), 598 StopMode::Stop1 => quote! { crate::rcc::StopMode::Stop1 },
606 };
607
608 let (incr_stop_refcount, decr_stop_refcount) = match stop_refcount {
609 Some(stop_refcount) => (
610 quote! {
611 #[cfg(feature = "low-power")]
612 unsafe { crate::rcc::#stop_refcount += 1 };
613 },
614 quote! {
615 #[cfg(feature = "low-power")]
616 unsafe { crate::rcc::#stop_refcount -= 1 };
617 },
618 ),
619 None => (TokenStream::new(), TokenStream::new()),
620 }; 599 };
621 600
622 g.extend(quote! { 601 g.extend(quote! {
@@ -624,34 +603,16 @@ fn main() {
624 fn frequency() -> crate::time::Hertz { 603 fn frequency() -> crate::time::Hertz {
625 #clock_frequency 604 #clock_frequency
626 } 605 }
627 fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) {
628 #before_enable
629 #incr_stop_refcount
630
631 #start_rst
632
633 crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true));
634
635 // we must wait two peripheral clock cycles before the clock is active
636 // this seems to work, but might be incorrect
637 // see http://efton.sk/STM32/gotcha/g183.html
638
639 // dummy read (like in the ST HALs)
640 let _ = crate::pac::RCC.#en_reg().read();
641
642 // DSB for good measure
643 cortex_m::asm::dsb();
644
645 #end_rst
646 }
647 fn disable_with_cs(_cs: critical_section::CriticalSection) {
648 #before_disable
649 crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false));
650 #decr_stop_refcount
651 }
652 606
653 const ENABLE_BIT: crate::rcc::ClockEnableBit = 607 const RCC_INFO: crate::rcc::RccInfo = unsafe {
654 unsafe { crate::rcc::ClockEnableBit::new(#en_reg_offs, #en_bit_offs) }; 608 crate::rcc::RccInfo::new(
609 #reset_offset_and_bit,
610 #enable_offset_and_bit,
611 #refcount_idx,
612 #[cfg(feature = "low-power")]
613 #stop_mode,
614 )
615 };
655 } 616 }
656 617
657 impl crate::rcc::RccPeripheral for peripherals::#pname {} 618 impl crate::rcc::RccPeripheral for peripherals::#pname {}
@@ -659,6 +620,14 @@ fn main() {
659 } 620 }
660 } 621 }
661 622
623 g.extend({
624 let refcounts_len = refcount_idxs.len();
625 let refcount_zeros: TokenStream = refcount_idxs.iter().map(|_| quote! { 0u8, }).collect();
626 quote! {
627 pub(crate) static mut REFCOUNTS: [u8; #refcounts_len] = [#refcount_zeros];
628 }
629 });
630
662 let struct_fields: Vec<_> = clock_gen 631 let struct_fields: Vec<_> = clock_gen
663 .muxes 632 .muxes
664 .iter() 633 .iter()
@@ -762,22 +731,6 @@ fn main() {
762 } 731 }
763 ); 732 );
764 733
765 let refcount_mod: TokenStream = clock_gen
766 .refcount_statics
767 .iter()
768 .map(|refcount_static| {
769 quote! {
770 pub(crate) static mut #refcount_static: u8 = 0;
771 }
772 })
773 .collect();
774
775 g.extend(quote! {
776 mod refcount_statics {
777 #refcount_mod
778 }
779 });
780
781 // ======== 734 // ========
782 // Generate fns to enable GPIO, DMA in RCC 735 // Generate fns to enable GPIO, DMA in RCC
783 736
@@ -1654,54 +1607,65 @@ fn main() {
1654 rustfmt(&out_file); 1607 rustfmt(&out_file);
1655 1608
1656 // ======== 1609 // ========
1657 // Multicore 1610 // Configs for multicore and for targeting groups of chips
1658
1659 let mut s = chip_name.split('_');
1660 let mut chip_name: String = s.next().unwrap().to_string();
1661 let core_name = if let Some(c) = s.next() {
1662 if !c.starts_with("CM") {
1663 chip_name.push('_');
1664 chip_name.push_str(c);
1665 None
1666 } else {
1667 Some(c)
1668 }
1669 } else {
1670 None
1671 };
1672 1611
1673 if let Some(core) = core_name { 1612 fn get_chip_cfgs(chip_name: &str) -> Vec<String> {
1674 println!("cargo:rustc-cfg={}_{}", &chip_name[..chip_name.len() - 2], core); 1613 let mut cfgs = Vec::new();
1675 }
1676 1614
1677 // ======= 1615 // Multicore
1678 // Features for targeting groups of chips
1679 1616
1680 if &chip_name[..8] == "stm32wba" { 1617 let mut s = chip_name.split('_');
1681 println!("cargo:rustc-cfg={}", &chip_name[..8]); // stm32wba 1618 let mut chip_name: String = s.next().unwrap().to_string();
1682 println!("cargo:rustc-cfg={}", &chip_name[..10]); // stm32wba52 1619 let core_name = if let Some(c) = s.next() {
1683 println!("cargo:rustc-cfg=package_{}", &chip_name[10..11]); 1620 if !c.starts_with("CM") {
1684 println!("cargo:rustc-cfg=flashsize_{}", &chip_name[11..12]); 1621 chip_name.push('_');
1685 } else { 1622 chip_name.push_str(c);
1686 if &chip_name[..8] == "stm32h7r" || &chip_name[..8] == "stm32h7s" { 1623 None
1687 println!("cargo:rustc-cfg=stm32h7rs"); 1624 } else {
1625 Some(c)
1626 }
1688 } else { 1627 } else {
1689 println!("cargo:rustc-cfg={}", &chip_name[..7]); // stm32f4 1628 None
1629 };
1630
1631 if let Some(core) = core_name {
1632 cfgs.push(format!("{}_{}", &chip_name[..chip_name.len() - 2], core));
1690 } 1633 }
1691 println!("cargo:rustc-cfg={}", &chip_name[..9]); // stm32f429
1692 println!("cargo:rustc-cfg={}x", &chip_name[..8]); // stm32f42x
1693 println!("cargo:rustc-cfg={}x{}", &chip_name[..7], &chip_name[8..9]); // stm32f4x9
1694 println!("cargo:rustc-cfg=package_{}", &chip_name[9..10]);
1695 println!("cargo:rustc-cfg=flashsize_{}", &chip_name[10..11]);
1696 }
1697 1634
1698 // Mark the L4+ chips as they have many differences to regular L4. 1635 // Configs for targeting groups of chips
1699 if &chip_name[..7] == "stm32l4" { 1636 if &chip_name[..8] == "stm32wba" {
1700 if "pqrs".contains(&chip_name[7..8]) { 1637 cfgs.push(chip_name[..8].to_owned()); // stm32wba
1701 println!("cargo:rustc-cfg=stm32l4_plus"); 1638 cfgs.push(chip_name[..10].to_owned()); // stm32wba52
1639 cfgs.push(format!("package_{}", &chip_name[10..11]));
1640 cfgs.push(format!("flashsize_{}", &chip_name[11..12]));
1702 } else { 1641 } else {
1703 println!("cargo:rustc-cfg=stm32l4_nonplus"); 1642 if &chip_name[..8] == "stm32h7r" || &chip_name[..8] == "stm32h7s" {
1643 cfgs.push("stm32h7rs".to_owned());
1644 } else {
1645 cfgs.push(chip_name[..7].to_owned()); // stm32f4
1646 }
1647 cfgs.push(chip_name[..9].to_owned()); // stm32f429
1648 cfgs.push(format!("{}x", &chip_name[..8])); // stm32f42x
1649 cfgs.push(format!("{}x{}", &chip_name[..7], &chip_name[8..9])); // stm32f4x9
1650 cfgs.push(format!("package_{}", &chip_name[9..10]));
1651 cfgs.push(format!("flashsize_{}", &chip_name[10..11]));
1652 }
1653
1654 // Mark the L4+ chips as they have many differences to regular L4.
1655 if &chip_name[..7] == "stm32l4" {
1656 if "pqrs".contains(&chip_name[7..8]) {
1657 cfgs.push("stm32l4_plus".to_owned());
1658 } else {
1659 cfgs.push("stm32l4_nonplus".to_owned());
1660 }
1704 } 1661 }
1662
1663 cfgs
1664 }
1665
1666 cfgs.enable_all(&get_chip_cfgs(&chip_name));
1667 for &chip_name in ALL_CHIPS.iter() {
1668 cfgs.declare_all(&get_chip_cfgs(&chip_name.to_ascii_lowercase()));
1705 } 1669 }
1706 1670
1707 println!("cargo:rerun-if-changed=build.rs"); 1671 println!("cargo:rerun-if-changed=build.rs");
diff --git a/embassy-stm32/build_common.rs b/embassy-stm32/build_common.rs
new file mode 100644
index 000000000..2c65f8529
--- /dev/null
+++ b/embassy-stm32/build_common.rs
@@ -0,0 +1,109 @@
1// NOTE: this file is copy-pasted between several Embassy crates, because there is no
2// straightforward way to share this code:
3// - it cannot be placed into the root of the repo and linked from each build.rs using `#[path =
4// "../build_common.rs"]`, because `cargo publish` requires that all files published with a crate
5// reside in the crate's directory,
6// - it cannot be symlinked from `embassy-xxx/build_common.rs` to `../build_common.rs`, because
7// symlinks don't work on Windows.
8
9use std::collections::HashSet;
10use std::env;
11use std::ffi::OsString;
12use std::process::Command;
13
14/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring
15/// them (`cargo:rust-check-cfg=cfg(X)`).
16#[derive(Debug)]
17pub struct CfgSet {
18 enabled: HashSet<String>,
19 declared: HashSet<String>,
20 emit_declared: bool,
21}
22
23impl CfgSet {
24 pub fn new() -> Self {
25 Self {
26 enabled: HashSet::new(),
27 declared: HashSet::new(),
28 emit_declared: is_rustc_nightly(),
29 }
30 }
31
32 /// Enable a config, which can then be used in `#[cfg(...)]` for conditional compilation.
33 ///
34 /// All configs that can potentially be enabled should be unconditionally declared using
35 /// [`Self::declare()`].
36 pub fn enable(&mut self, cfg: impl AsRef<str>) {
37 if self.enabled.insert(cfg.as_ref().to_owned()) {
38 println!("cargo:rustc-cfg={}", cfg.as_ref());
39 }
40 }
41
42 pub fn enable_all(&mut self, cfgs: &[impl AsRef<str>]) {
43 for cfg in cfgs.iter() {
44 self.enable(cfg.as_ref());
45 }
46 }
47
48 /// Declare a valid config for conditional compilation, without enabling it.
49 ///
50 /// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid.
51 pub fn declare(&mut self, cfg: impl AsRef<str>) {
52 if self.declared.insert(cfg.as_ref().to_owned()) && self.emit_declared {
53 println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref());
54 }
55 }
56
57 pub fn declare_all(&mut self, cfgs: &[impl AsRef<str>]) {
58 for cfg in cfgs.iter() {
59 self.declare(cfg.as_ref());
60 }
61 }
62
63 pub fn set(&mut self, cfg: impl Into<String>, enable: bool) {
64 let cfg = cfg.into();
65 if enable {
66 self.enable(cfg.clone());
67 }
68 self.declare(cfg);
69 }
70}
71
72fn is_rustc_nightly() -> bool {
73 let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
74
75 let output = Command::new(rustc)
76 .arg("--version")
77 .output()
78 .expect("failed to run `rustc --version`");
79
80 String::from_utf8_lossy(&output.stdout).contains("nightly")
81}
82
83/// Sets configs that describe the target platform.
84pub fn set_target_cfgs(cfgs: &mut CfgSet) {
85 let target = env::var("TARGET").unwrap();
86
87 if target.starts_with("thumbv6m-") {
88 cfgs.enable_all(&["cortex_m", "armv6m"]);
89 } else if target.starts_with("thumbv7m-") {
90 cfgs.enable_all(&["cortex_m", "armv7m"]);
91 } else if target.starts_with("thumbv7em-") {
92 cfgs.enable_all(&["cortex_m", "armv7m", "armv7em"]);
93 } else if target.starts_with("thumbv8m.base") {
94 cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_base"]);
95 } else if target.starts_with("thumbv8m.main") {
96 cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_main"]);
97 }
98 cfgs.declare_all(&[
99 "cortex_m",
100 "armv6m",
101 "armv7m",
102 "armv7em",
103 "armv8m",
104 "armv8m_base",
105 "armv8m_main",
106 ]);
107
108 cfgs.set("has_fpu", target.ends_with("-eabihf"));
109}
diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs
index 3822d5032..b37ec260f 100644
--- a/embassy-stm32/src/adc/f1.rs
+++ b/embassy-stm32/src/adc/f1.rs
@@ -7,7 +7,7 @@ use embassy_hal_internal::into_ref;
7use super::blocking_delay_us; 7use super::blocking_delay_us;
8use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; 8use crate::adc::{Adc, AdcChannel, Instance, SampleTime};
9use crate::time::Hertz; 9use crate::time::Hertz;
10use crate::{interrupt, Peripheral}; 10use crate::{interrupt, rcc, Peripheral};
11 11
12pub const VDDA_CALIB_MV: u32 = 3300; 12pub const VDDA_CALIB_MV: u32 = 3300;
13pub const ADC_MAX: u32 = (1 << 12) - 1; 13pub const ADC_MAX: u32 = (1 << 12) - 1;
@@ -50,7 +50,7 @@ impl<T: Instance> super::SealedAdcChannel<T> for Temperature {
50impl<'d, T: Instance> Adc<'d, T> { 50impl<'d, T: Instance> Adc<'d, T> {
51 pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self { 51 pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
52 into_ref!(adc); 52 into_ref!(adc);
53 T::enable_and_reset(); 53 rcc::enable_and_reset::<T>();
54 T::regs().cr2().modify(|reg| reg.set_adon(true)); 54 T::regs().cr2().modify(|reg| reg.set_adon(true));
55 55
56 // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’) 56 // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’)
@@ -169,6 +169,6 @@ impl<'d, T: Instance> Drop for Adc<'d, T> {
169 fn drop(&mut self) { 169 fn drop(&mut self) {
170 T::regs().cr2().modify(|reg| reg.set_adon(false)); 170 T::regs().cr2().modify(|reg| reg.set_adon(false));
171 171
172 T::disable(); 172 rcc::disable::<T>();
173 } 173 }
174} 174}
diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs
index 3f076d64b..ac88c9742 100644
--- a/embassy-stm32/src/adc/f3.rs
+++ b/embassy-stm32/src/adc/f3.rs
@@ -8,7 +8,7 @@ use super::blocking_delay_us;
8use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; 8use crate::adc::{Adc, AdcChannel, Instance, SampleTime};
9use crate::interrupt::typelevel::Interrupt; 9use crate::interrupt::typelevel::Interrupt;
10use crate::time::Hertz; 10use crate::time::Hertz;
11use crate::{interrupt, Peripheral}; 11use crate::{interrupt, rcc, Peripheral};
12 12
13pub const VDDA_CALIB_MV: u32 = 3300; 13pub const VDDA_CALIB_MV: u32 = 3300;
14pub const ADC_MAX: u32 = (1 << 12) - 1; 14pub const ADC_MAX: u32 = (1 << 12) - 1;
@@ -63,7 +63,7 @@ impl<'d, T: Instance> Adc<'d, T> {
63 63
64 into_ref!(adc); 64 into_ref!(adc);
65 65
66 T::enable_and_reset(); 66 rcc::enable_and_reset::<T>();
67 67
68 // Enable the adc regulator 68 // Enable the adc regulator
69 T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE)); 69 T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE));
@@ -188,6 +188,6 @@ impl<'d, T: Instance> Drop for Adc<'d, T> {
188 T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE)); 188 T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE));
189 T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::DISABLED)); 189 T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::DISABLED));
190 190
191 T::disable(); 191 rcc::disable::<T>();
192 } 192 }
193} 193}
diff --git a/embassy-stm32/src/adc/f3_v1_1.rs b/embassy-stm32/src/adc/f3_v1_1.rs
index 106956989..689c2871d 100644
--- a/embassy-stm32/src/adc/f3_v1_1.rs
+++ b/embassy-stm32/src/adc/f3_v1_1.rs
@@ -10,7 +10,7 @@ use super::Resolution;
10use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; 10use crate::adc::{Adc, AdcChannel, Instance, SampleTime};
11use crate::interrupt::typelevel::Interrupt; 11use crate::interrupt::typelevel::Interrupt;
12use crate::time::Hertz; 12use crate::time::Hertz;
13use crate::{interrupt, Peripheral}; 13use crate::{interrupt, rcc, Peripheral};
14 14
15const ADC_FREQ: Hertz = crate::rcc::HSI_FREQ; 15const ADC_FREQ: Hertz = crate::rcc::HSI_FREQ;
16 16
@@ -143,7 +143,7 @@ impl<'d, T: Instance> Adc<'d, T> {
143 ) -> Self { 143 ) -> Self {
144 into_ref!(adc); 144 into_ref!(adc);
145 145
146 T::enable_and_reset(); 146 rcc::enable_and_reset::<T>();
147 147
148 //let r = T::regs(); 148 //let r = T::regs();
149 //r.cr2().write(|w| w.set_align(true)); 149 //r.cr2().write(|w| w.set_align(true));
@@ -403,6 +403,6 @@ impl<'d, T: Instance> Drop for Adc<'d, T> {
403 403
404 T::regs().cr2().modify(|w| w.set_adon(false)); 404 T::regs().cr2().modify(|w| w.set_adon(false));
405 405
406 T::disable(); 406 rcc::disable::<T>();
407 } 407 }
408} 408}
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs
index ce7f5db70..6569361fe 100644
--- a/embassy-stm32/src/adc/g4.rs
+++ b/embassy-stm32/src/adc/g4.rs
@@ -4,7 +4,7 @@ use pac::adccommon::vals::Presc;
4 4
5use super::{blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime}; 5use super::{blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime};
6use crate::time::Hertz; 6use crate::time::Hertz;
7use crate::{pac, Peripheral}; 7use crate::{pac, rcc, Peripheral};
8 8
9/// Default VREF voltage used for sample conversion to millivolts. 9/// Default VREF voltage used for sample conversion to millivolts.
10pub const VREF_DEFAULT_MV: u32 = 3300; 10pub const VREF_DEFAULT_MV: u32 = 3300;
@@ -130,7 +130,7 @@ impl<'d, T: Instance> Adc<'d, T> {
130 /// Create a new ADC driver. 130 /// Create a new ADC driver.
131 pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self { 131 pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
132 embassy_hal_internal::into_ref!(adc); 132 embassy_hal_internal::into_ref!(adc);
133 T::enable_and_reset(); 133 rcc::enable_and_reset::<T>();
134 134
135 let prescaler = Prescaler::from_ker_ck(T::frequency()); 135 let prescaler = Prescaler::from_ker_ck(T::frequency());
136 136
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index 040ee9c53..0c22a7dae 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -71,9 +71,9 @@ pub(crate) trait SealedAdcChannel<T> {
71/// Performs a busy-wait delay for a specified number of microseconds. 71/// Performs a busy-wait delay for a specified number of microseconds.
72#[allow(unused)] 72#[allow(unused)]
73pub(crate) fn blocking_delay_us(us: u32) { 73pub(crate) fn blocking_delay_us(us: u32) {
74 #[cfg(time)] 74 #[cfg(feature = "time")]
75 embassy_time::block_for(embassy_time::Duration::from_micros(us)); 75 embassy_time::block_for(embassy_time::Duration::from_micros(us as u64));
76 #[cfg(not(time))] 76 #[cfg(not(feature = "time"))]
77 { 77 {
78 let freq = unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 as u64; 78 let freq = unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 as u64;
79 let us = us as u64; 79 let us = us as u64;
diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs
index 090790c39..9bec2e13b 100644
--- a/embassy-stm32/src/adc/v1.rs
+++ b/embassy-stm32/src/adc/v1.rs
@@ -10,7 +10,7 @@ use super::blocking_delay_us;
10use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; 10use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime};
11use crate::interrupt::typelevel::Interrupt; 11use crate::interrupt::typelevel::Interrupt;
12use crate::peripherals::ADC1; 12use crate::peripherals::ADC1;
13use crate::{interrupt, Peripheral}; 13use crate::{interrupt, rcc, Peripheral};
14 14
15pub const VDDA_CALIB_MV: u32 = 3300; 15pub const VDDA_CALIB_MV: u32 = 3300;
16pub const VREF_INT: u32 = 1230; 16pub const VREF_INT: u32 = 1230;
@@ -67,7 +67,7 @@ impl<'d, T: Instance> Adc<'d, T> {
67 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 67 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
68 ) -> Self { 68 ) -> Self {
69 into_ref!(adc); 69 into_ref!(adc);
70 T::enable_and_reset(); 70 rcc::enable_and_reset::<T>();
71 71
72 // Delay 1μs when using HSI14 as the ADC clock. 72 // Delay 1μs when using HSI14 as the ADC clock.
73 // 73 //
@@ -199,6 +199,6 @@ impl<'d, T: Instance> Drop for Adc<'d, T> {
199 T::regs().cr().modify(|reg| reg.set_addis(true)); 199 T::regs().cr().modify(|reg| reg.set_addis(true));
200 while T::regs().cr().read().aden() {} 200 while T::regs().cr().read().aden() {}
201 201
202 T::disable(); 202 rcc::disable::<T>();
203 } 203 }
204} 204}
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs
index 033108195..e3175dff5 100644
--- a/embassy-stm32/src/adc/v2.rs
+++ b/embassy-stm32/src/adc/v2.rs
@@ -4,7 +4,7 @@ use super::blocking_delay_us;
4use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; 4use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime};
5use crate::peripherals::ADC1; 5use crate::peripherals::ADC1;
6use crate::time::Hertz; 6use crate::time::Hertz;
7use crate::Peripheral; 7use crate::{rcc, Peripheral};
8 8
9/// Default VREF voltage used for sample conversion to millivolts. 9/// Default VREF voltage used for sample conversion to millivolts.
10pub const VREF_DEFAULT_MV: u32 = 3300; 10pub const VREF_DEFAULT_MV: u32 = 3300;
@@ -31,7 +31,7 @@ impl AdcChannel<ADC1> for Temperature {}
31impl super::SealedAdcChannel<ADC1> for Temperature { 31impl super::SealedAdcChannel<ADC1> for Temperature {
32 fn channel(&self) -> u8 { 32 fn channel(&self) -> u8 {
33 cfg_if::cfg_if! { 33 cfg_if::cfg_if! {
34 if #[cfg(any(stm32f2, stm32f40, stm32f41))] { 34 if #[cfg(any(stm32f2, stm32f40x, stm32f41x))] {
35 16 35 16
36 } else { 36 } else {
37 18 37 18
@@ -96,7 +96,7 @@ where
96{ 96{
97 pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self { 97 pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
98 into_ref!(adc); 98 into_ref!(adc);
99 T::enable_and_reset(); 99 rcc::enable_and_reset::<T>();
100 100
101 let presc = Prescaler::from_pclk2(T::frequency()); 101 let presc = Prescaler::from_pclk2(T::frequency());
102 T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre())); 102 T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre()));
@@ -206,6 +206,6 @@ impl<'d, T: Instance> Drop for Adc<'d, T> {
206 reg.set_adon(false); 206 reg.set_adon(false);
207 }); 207 });
208 208
209 T::disable(); 209 rcc::disable::<T>();
210 } 210 }
211} 211}
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index be857f4dd..398c57a92 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -3,7 +3,7 @@ use embassy_hal_internal::into_ref;
3 3
4use super::blocking_delay_us; 4use super::blocking_delay_us;
5use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; 5use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime};
6use crate::Peripheral; 6use crate::{rcc, Peripheral};
7 7
8/// Default VREF voltage used for sample conversion to millivolts. 8/// Default VREF voltage used for sample conversion to millivolts.
9pub const VREF_DEFAULT_MV: u32 = 3300; 9pub const VREF_DEFAULT_MV: u32 = 3300;
@@ -94,7 +94,7 @@ cfg_if! {
94impl<'d, T: Instance> Adc<'d, T> { 94impl<'d, T: Instance> Adc<'d, T> {
95 pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self { 95 pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
96 into_ref!(adc); 96 into_ref!(adc);
97 T::enable_and_reset(); 97 rcc::enable_and_reset::<T>();
98 T::regs().cr().modify(|reg| { 98 T::regs().cr().modify(|reg| {
99 #[cfg(not(any(adc_g0, adc_u0)))] 99 #[cfg(not(any(adc_g0, adc_u0)))]
100 reg.set_deeppwd(false); 100 reg.set_deeppwd(false);
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs
index f564114c2..50db646fe 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -4,7 +4,7 @@ use pac::adccommon::vals::Presc;
4 4
5use super::{blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime}; 5use super::{blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime};
6use crate::time::Hertz; 6use crate::time::Hertz;
7use crate::{pac, Peripheral}; 7use crate::{pac, rcc, Peripheral};
8 8
9/// Default VREF voltage used for sample conversion to millivolts. 9/// Default VREF voltage used for sample conversion to millivolts.
10pub const VREF_DEFAULT_MV: u32 = 3300; 10pub const VREF_DEFAULT_MV: u32 = 3300;
@@ -130,7 +130,7 @@ impl<'d, T: Instance> Adc<'d, T> {
130 /// Create a new ADC driver. 130 /// Create a new ADC driver.
131 pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self { 131 pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
132 embassy_hal_internal::into_ref!(adc); 132 embassy_hal_internal::into_ref!(adc);
133 T::enable_and_reset(); 133 rcc::enable_and_reset::<T>();
134 134
135 let prescaler = Prescaler::from_ker_ck(T::frequency()); 135 let prescaler = Prescaler::from_ker_ck(T::frequency());
136 136
diff --git a/embassy-stm32/src/can/bxcan/filter.rs b/embassy-stm32/src/can/bxcan/filter.rs
index 9940c7f50..167c6c572 100644
--- a/embassy-stm32/src/can/bxcan/filter.rs
+++ b/embassy-stm32/src/can/bxcan/filter.rs
@@ -2,7 +2,7 @@
2 2
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4 4
5use super::{ExtendedId, Fifo, FilterOwner, Id, Instance, MasterInstance, StandardId}; 5use super::{ExtendedId, Fifo, Id, StandardId};
6 6
7const F32_RTR: u32 = 0b010; // set the RTR bit to match remote frames 7const F32_RTR: u32 = 0b010; // set the RTR bit to match remote frames
8const F32_IDE: u32 = 0b100; // set the IDE bit to match extended identifiers 8const F32_IDE: u32 = 0b100; // set the IDE bit to match extended identifiers
@@ -210,24 +210,24 @@ impl From<Mask32> for BankConfig {
210} 210}
211 211
212/// Interface to the filter banks of a CAN peripheral. 212/// Interface to the filter banks of a CAN peripheral.
213pub struct MasterFilters<'a, I: FilterOwner> { 213pub struct MasterFilters<'a> {
214 /// Number of assigned filter banks. 214 /// Number of assigned filter banks.
215 /// 215 ///
216 /// On chips with splittable filter banks, this value can be dynamic. 216 /// On chips with splittable filter banks, this value can be dynamic.
217 bank_count: u8, 217 bank_count: u8,
218 _can: PhantomData<&'a mut I>, 218 _phantom: PhantomData<&'a ()>,
219 canregs: crate::pac::can::Can, 219 info: &'static crate::can::Info,
220} 220}
221 221
222// NOTE: This type mutably borrows the CAN instance and has unique access to the registers while it 222// NOTE: This type mutably borrows the CAN instance and has unique access to the registers while it
223// exists. 223// exists.
224impl<I: FilterOwner> MasterFilters<'_, I> { 224impl MasterFilters<'_> {
225 pub(crate) unsafe fn new(canregs: crate::pac::can::Can) -> Self { 225 pub(crate) unsafe fn new(info: &'static crate::can::Info) -> Self {
226 // Enable initialization mode. 226 // Enable initialization mode.
227 canregs.fmr().modify(|reg| reg.set_finit(true)); 227 info.regs.0.fmr().modify(|reg| reg.set_finit(true));
228 228
229 // Read the filter split value. 229 // Read the filter split value.
230 let bank_count = canregs.fmr().read().can2sb(); 230 let bank_count = info.regs.0.fmr().read().can2sb();
231 231
232 // (Reset value of CAN2SB is 0x0E, 14, which, in devices with 14 filter banks, assigns all 232 // (Reset value of CAN2SB is 0x0E, 14, which, in devices with 14 filter banks, assigns all
233 // of them to the master peripheral, and in devices with 28, assigns them 50/50 to 233 // of them to the master peripheral, and in devices with 28, assigns them 50/50 to
@@ -235,8 +235,8 @@ impl<I: FilterOwner> MasterFilters<'_, I> {
235 235
236 Self { 236 Self {
237 bank_count, 237 bank_count,
238 _can: PhantomData, 238 _phantom: PhantomData,
239 canregs, 239 info,
240 } 240 }
241 } 241 }
242 242
@@ -244,7 +244,7 @@ impl<I: FilterOwner> MasterFilters<'_, I> {
244 FilterBanks { 244 FilterBanks {
245 start_idx: 0, 245 start_idx: 0,
246 bank_count: self.bank_count, 246 bank_count: self.bank_count,
247 canregs: self.canregs, 247 info: self.info,
248 } 248 }
249 } 249 }
250 250
@@ -291,49 +291,49 @@ impl<I: FilterOwner> MasterFilters<'_, I> {
291 } 291 }
292} 292}
293 293
294impl<I: MasterInstance> MasterFilters<'_, I> { 294impl MasterFilters<'_> {
295 /// Sets the index at which the filter banks owned by the slave peripheral start. 295 /// Sets the index at which the filter banks owned by the slave peripheral start.
296 pub fn set_split(&mut self, split_index: u8) -> &mut Self { 296 pub fn set_split(&mut self, split_index: u8) -> &mut Self {
297 assert!(split_index <= I::NUM_FILTER_BANKS); 297 assert!(split_index <= self.info.num_filter_banks);
298 self.canregs.fmr().modify(|reg| reg.set_can2sb(split_index)); 298 self.info.regs.0.fmr().modify(|reg| reg.set_can2sb(split_index));
299 self.bank_count = split_index; 299 self.bank_count = split_index;
300 self 300 self
301 } 301 }
302 302
303 /// Accesses the filters assigned to the slave peripheral. 303 /// Accesses the filters assigned to the slave peripheral.
304 pub fn slave_filters(&mut self) -> SlaveFilters<'_, I> { 304 pub fn slave_filters(&mut self) -> SlaveFilters<'_> {
305 // NB: This mutably borrows `self`, so it has full access to the filter bank registers. 305 // NB: This mutably borrows `self`, so it has full access to the filter bank registers.
306 SlaveFilters { 306 SlaveFilters {
307 start_idx: self.bank_count, 307 start_idx: self.bank_count,
308 bank_count: I::NUM_FILTER_BANKS - self.bank_count, 308 bank_count: self.info.num_filter_banks - self.bank_count,
309 _can: PhantomData, 309 _phantom: PhantomData,
310 canregs: self.canregs, 310 info: self.info,
311 } 311 }
312 } 312 }
313} 313}
314 314
315impl<I: FilterOwner> Drop for MasterFilters<'_, I> { 315impl Drop for MasterFilters<'_> {
316 #[inline] 316 #[inline]
317 fn drop(&mut self) { 317 fn drop(&mut self) {
318 // Leave initialization mode. 318 // Leave initialization mode.
319 self.canregs.fmr().modify(|regs| regs.set_finit(false)); 319 self.info.regs.0.fmr().modify(|regs| regs.set_finit(false));
320 } 320 }
321} 321}
322 322
323/// Interface to the filter banks assigned to a slave peripheral. 323/// Interface to the filter banks assigned to a slave peripheral.
324pub struct SlaveFilters<'a, I: Instance> { 324pub struct SlaveFilters<'a> {
325 start_idx: u8, 325 start_idx: u8,
326 bank_count: u8, 326 bank_count: u8,
327 _can: PhantomData<&'a mut I>, 327 _phantom: PhantomData<&'a ()>,
328 canregs: crate::pac::can::Can, 328 info: &'static crate::can::Info,
329} 329}
330 330
331impl<I: Instance> SlaveFilters<'_, I> { 331impl SlaveFilters<'_> {
332 fn banks_imm(&self) -> FilterBanks { 332 fn banks_imm(&self) -> FilterBanks {
333 FilterBanks { 333 FilterBanks {
334 start_idx: self.start_idx, 334 start_idx: self.start_idx,
335 bank_count: self.bank_count, 335 bank_count: self.bank_count,
336 canregs: self.canregs, 336 info: self.info,
337 } 337 }
338 } 338 }
339 339
@@ -377,14 +377,14 @@ impl<I: Instance> SlaveFilters<'_, I> {
377struct FilterBanks { 377struct FilterBanks {
378 start_idx: u8, 378 start_idx: u8,
379 bank_count: u8, 379 bank_count: u8,
380 canregs: crate::pac::can::Can, 380 info: &'static crate::can::Info,
381} 381}
382 382
383impl FilterBanks { 383impl FilterBanks {
384 fn clear(&mut self) { 384 fn clear(&mut self) {
385 let mask = filter_bitmask(self.start_idx, self.bank_count); 385 let mask = filter_bitmask(self.start_idx, self.bank_count);
386 386
387 self.canregs.fa1r().modify(|reg| { 387 self.info.regs.0.fa1r().modify(|reg| {
388 for i in 0..28usize { 388 for i in 0..28usize {
389 if (0x01u32 << i) & mask != 0 { 389 if (0x01u32 << i) & mask != 0 {
390 reg.set_fact(i, false); 390 reg.set_fact(i, false);
@@ -399,7 +399,11 @@ impl FilterBanks {
399 399
400 fn disable(&mut self, index: u8) { 400 fn disable(&mut self, index: u8) {
401 self.assert_bank_index(index); 401 self.assert_bank_index(index);
402 self.canregs.fa1r().modify(|reg| reg.set_fact(index as usize, false)) 402 self.info
403 .regs
404 .0
405 .fa1r()
406 .modify(|reg| reg.set_fact(index as usize, false))
403 } 407 }
404 408
405 fn enable(&mut self, index: u8, fifo: Fifo, config: BankConfig) { 409 fn enable(&mut self, index: u8, fifo: Fifo, config: BankConfig) {
@@ -407,11 +411,11 @@ impl FilterBanks {
407 411
408 // Configure mode. 412 // Configure mode.
409 let mode = matches!(config, BankConfig::List16(_) | BankConfig::List32(_)); 413 let mode = matches!(config, BankConfig::List16(_) | BankConfig::List32(_));
410 self.canregs.fm1r().modify(|reg| reg.set_fbm(index as usize, mode)); 414 self.info.regs.0.fm1r().modify(|reg| reg.set_fbm(index as usize, mode));
411 415
412 // Configure scale. 416 // Configure scale.
413 let scale = matches!(config, BankConfig::List32(_) | BankConfig::Mask32(_)); 417 let scale = matches!(config, BankConfig::List32(_) | BankConfig::Mask32(_));
414 self.canregs.fs1r().modify(|reg| reg.set_fsc(index as usize, scale)); 418 self.info.regs.0.fs1r().modify(|reg| reg.set_fsc(index as usize, scale));
415 419
416 // Configure filter register. 420 // Configure filter register.
417 let (fxr1, fxr2); 421 let (fxr1, fxr2);
@@ -433,12 +437,12 @@ impl FilterBanks {
433 fxr2 = a.mask; 437 fxr2 = a.mask;
434 } 438 }
435 }; 439 };
436 let bank = self.canregs.fb(index as usize); 440 let bank = self.info.regs.0.fb(index as usize);
437 bank.fr1().write(|w| w.0 = fxr1); 441 bank.fr1().write(|w| w.0 = fxr1);
438 bank.fr2().write(|w| w.0 = fxr2); 442 bank.fr2().write(|w| w.0 = fxr2);
439 443
440 // Assign to the right FIFO 444 // Assign to the right FIFO
441 self.canregs.ffa1r().modify(|reg| { 445 self.info.regs.0.ffa1r().modify(|reg| {
442 reg.set_ffa( 446 reg.set_ffa(
443 index as usize, 447 index as usize,
444 match fifo { 448 match fifo {
@@ -449,7 +453,7 @@ impl FilterBanks {
449 }); 453 });
450 454
451 // Set active. 455 // Set active.
452 self.canregs.fa1r().modify(|reg| reg.set_fact(index as usize, true)) 456 self.info.regs.0.fa1r().modify(|reg| reg.set_fact(index as usize, true))
453 } 457 }
454} 458}
455 459
diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs
index 0ac4cdab6..53b94b9e2 100644
--- a/embassy-stm32/src/can/bxcan/mod.rs
+++ b/embassy-stm32/src/can/bxcan/mod.rs
@@ -5,7 +5,8 @@ use core::future::poll_fn;
5use core::marker::PhantomData; 5use core::marker::PhantomData;
6use core::task::Poll; 6use core::task::Poll;
7 7
8use embassy_hal_internal::{into_ref, PeripheralRef}; 8use embassy_hal_internal::interrupt::InterruptExt;
9use embassy_hal_internal::into_ref;
9use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 10use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
10use embassy_sync::channel::Channel; 11use embassy_sync::channel::Channel;
11use embassy_sync::waitqueue::AtomicWaker; 12use embassy_sync::waitqueue::AtomicWaker;
@@ -19,7 +20,7 @@ use super::util;
19use crate::can::enums::{BusError, TryReadError}; 20use crate::can::enums::{BusError, TryReadError};
20use crate::gpio::AFType; 21use crate::gpio::AFType;
21use crate::interrupt::typelevel::Interrupt; 22use crate::interrupt::typelevel::Interrupt;
22use crate::rcc::RccPeripheral; 23use crate::rcc::{self, RccPeripheral};
23use crate::{interrupt, peripherals, Peripheral}; 24use crate::{interrupt, peripherals, Peripheral};
24 25
25/// Interrupt handler. 26/// Interrupt handler.
@@ -90,11 +91,13 @@ impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterrup
90} 91}
91 92
92/// Configuration proxy returned by [`Can::modify_config`]. 93/// Configuration proxy returned by [`Can::modify_config`].
93pub struct CanConfig<'a, T: Instance> { 94pub struct CanConfig<'a> {
94 can: PhantomData<&'a mut T>, 95 phantom: PhantomData<&'a ()>,
96 info: &'static Info,
97 periph_clock: crate::time::Hertz,
95} 98}
96 99
97impl<T: Instance> CanConfig<'_, T> { 100impl CanConfig<'_> {
98 /// Configures the bit timings. 101 /// Configures the bit timings.
99 /// 102 ///
100 /// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter 103 /// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter
@@ -108,7 +111,7 @@ impl<T: Instance> CanConfig<'_, T> {
108 /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` 111 /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr`
109 /// parameter to this method. 112 /// parameter to this method.
110 pub fn set_bit_timing(self, bt: crate::can::util::NominalBitTiming) -> Self { 113 pub fn set_bit_timing(self, bt: crate::can::util::NominalBitTiming) -> Self {
111 Registers(T::regs()).set_bit_timing(bt); 114 self.info.regs.set_bit_timing(bt);
112 self 115 self
113 } 116 }
114 117
@@ -116,20 +119,20 @@ impl<T: Instance> CanConfig<'_, T> {
116 /// 119 ///
117 /// This is a helper that internally calls `set_bit_timing()`[Self::set_bit_timing]. 120 /// This is a helper that internally calls `set_bit_timing()`[Self::set_bit_timing].
118 pub fn set_bitrate(self, bitrate: u32) -> Self { 121 pub fn set_bitrate(self, bitrate: u32) -> Self {
119 let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); 122 let bit_timing = util::calc_can_timings(self.periph_clock, bitrate).unwrap();
120 self.set_bit_timing(bit_timing) 123 self.set_bit_timing(bit_timing)
121 } 124 }
122 125
123 /// Enables or disables loopback mode: Internally connects the TX and RX 126 /// Enables or disables loopback mode: Internally connects the TX and RX
124 /// signals together. 127 /// signals together.
125 pub fn set_loopback(self, enabled: bool) -> Self { 128 pub fn set_loopback(self, enabled: bool) -> Self {
126 Registers(T::regs()).set_loopback(enabled); 129 self.info.regs.set_loopback(enabled);
127 self 130 self
128 } 131 }
129 132
130 /// Enables or disables silent mode: Disconnects the TX signal from the pin. 133 /// Enables or disables silent mode: Disconnects the TX signal from the pin.
131 pub fn set_silent(self, enabled: bool) -> Self { 134 pub fn set_silent(self, enabled: bool) -> Self {
132 Registers(T::regs()).set_silent(enabled); 135 self.info.regs.set_silent(enabled);
133 self 136 self
134 } 137 }
135 138
@@ -140,21 +143,24 @@ impl<T: Instance> CanConfig<'_, T> {
140 /// 143 ///
141 /// Automatic retransmission is enabled by default. 144 /// Automatic retransmission is enabled by default.
142 pub fn set_automatic_retransmit(self, enabled: bool) -> Self { 145 pub fn set_automatic_retransmit(self, enabled: bool) -> Self {
143 Registers(T::regs()).set_automatic_retransmit(enabled); 146 self.info.regs.set_automatic_retransmit(enabled);
144 self 147 self
145 } 148 }
146} 149}
147 150
148impl<T: Instance> Drop for CanConfig<'_, T> { 151impl Drop for CanConfig<'_> {
149 #[inline] 152 #[inline]
150 fn drop(&mut self) { 153 fn drop(&mut self) {
151 Registers(T::regs()).leave_init_mode(); 154 self.info.regs.leave_init_mode();
152 } 155 }
153} 156}
154 157
155/// CAN driver 158/// CAN driver
156pub struct Can<'d, T: Instance> { 159pub struct Can<'d> {
157 peri: PeripheralRef<'d, T>, 160 phantom: PhantomData<&'d ()>,
161 info: &'static Info,
162 state: &'static State,
163 periph_clock: crate::time::Hertz,
158} 164}
159 165
160/// Error returned by `try_write` 166/// Error returned by `try_write`
@@ -165,11 +171,11 @@ pub enum TryWriteError {
165 Full, 171 Full,
166} 172}
167 173
168impl<'d, T: Instance> Can<'d, T> { 174impl<'d> Can<'d> {
169 /// Creates a new Bxcan instance, keeping the peripheral in sleep mode. 175 /// Creates a new Bxcan instance, keeping the peripheral in sleep mode.
170 /// You must call [Can::enable_non_blocking] to use the peripheral. 176 /// You must call [Can::enable_non_blocking] to use the peripheral.
171 pub fn new( 177 pub fn new<T: Instance>(
172 peri: impl Peripheral<P = T> + 'd, 178 _peri: impl Peripheral<P = T> + 'd,
173 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 179 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
174 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 180 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
175 _irqs: impl interrupt::typelevel::Binding<T::TXInterrupt, TxInterruptHandler<T>> 181 _irqs: impl interrupt::typelevel::Binding<T::TXInterrupt, TxInterruptHandler<T>>
@@ -178,15 +184,17 @@ impl<'d, T: Instance> Can<'d, T> {
178 + interrupt::typelevel::Binding<T::SCEInterrupt, SceInterruptHandler<T>> 184 + interrupt::typelevel::Binding<T::SCEInterrupt, SceInterruptHandler<T>>
179 + 'd, 185 + 'd,
180 ) -> Self { 186 ) -> Self {
181 into_ref!(peri, rx, tx); 187 into_ref!(_peri, rx, tx);
188 let info = T::info();
189 let regs = &T::info().regs;
182 190
183 rx.set_as_af(rx.af_num(), AFType::Input); 191 rx.set_as_af(rx.af_num(), AFType::Input);
184 tx.set_as_af(tx.af_num(), AFType::OutputPushPull); 192 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
185 193
186 T::enable_and_reset(); 194 rcc::enable_and_reset::<T>();
187 195
188 { 196 {
189 T::regs().ier().write(|w| { 197 regs.0.ier().write(|w| {
190 w.set_errie(true); 198 w.set_errie(true);
191 w.set_fmpie(0, true); 199 w.set_fmpie(0, true);
192 w.set_fmpie(1, true); 200 w.set_fmpie(1, true);
@@ -197,7 +205,7 @@ impl<'d, T: Instance> Can<'d, T> {
197 w.set_lecie(true); 205 w.set_lecie(true);
198 }); 206 });
199 207
200 T::regs().mcr().write(|w| { 208 regs.0.mcr().write(|w| {
201 // Enable timestamps on rx messages 209 // Enable timestamps on rx messages
202 210
203 w.set_ttcm(true); 211 w.set_ttcm(true);
@@ -205,17 +213,14 @@ impl<'d, T: Instance> Can<'d, T> {
205 } 213 }
206 214
207 unsafe { 215 unsafe {
208 T::TXInterrupt::unpend(); 216 info.tx_interrupt.unpend();
209 T::TXInterrupt::enable(); 217 info.tx_interrupt.enable();
210 218 info.rx0_interrupt.unpend();
211 T::RX0Interrupt::unpend(); 219 info.rx0_interrupt.enable();
212 T::RX0Interrupt::enable(); 220 info.rx1_interrupt.unpend();
213 221 info.rx1_interrupt.enable();
214 T::RX1Interrupt::unpend(); 222 info.sce_interrupt.unpend();
215 T::RX1Interrupt::enable(); 223 info.sce_interrupt.enable();
216
217 T::SCEInterrupt::unpend();
218 T::SCEInterrupt::enable();
219 } 224 }
220 225
221 rx.set_as_af(rx.af_num(), AFType::Input); 226 rx.set_as_af(rx.af_num(), AFType::Input);
@@ -223,12 +228,17 @@ impl<'d, T: Instance> Can<'d, T> {
223 228
224 Registers(T::regs()).leave_init_mode(); 229 Registers(T::regs()).leave_init_mode();
225 230
226 Self { peri } 231 Self {
232 phantom: PhantomData,
233 info: T::info(),
234 state: T::state(),
235 periph_clock: T::frequency(),
236 }
227 } 237 }
228 238
229 /// Set CAN bit rate. 239 /// Set CAN bit rate.
230 pub fn set_bitrate(&mut self, bitrate: u32) { 240 pub fn set_bitrate(&mut self, bitrate: u32) {
231 let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); 241 let bit_timing = util::calc_can_timings(self.periph_clock, bitrate).unwrap();
232 self.modify_config().set_bit_timing(bit_timing); 242 self.modify_config().set_bit_timing(bit_timing);
233 } 243 }
234 244
@@ -236,10 +246,14 @@ impl<'d, T: Instance> Can<'d, T> {
236 /// 246 ///
237 /// Calling this method will enter initialization mode. You must enable the peripheral 247 /// Calling this method will enter initialization mode. You must enable the peripheral
238 /// again afterwards with [`enable`](Self::enable). 248 /// again afterwards with [`enable`](Self::enable).
239 pub fn modify_config(&mut self) -> CanConfig<'_, T> { 249 pub fn modify_config(&mut self) -> CanConfig<'_> {
240 Registers(T::regs()).enter_init_mode(); 250 self.info.regs.enter_init_mode();
241 251
242 CanConfig { can: PhantomData } 252 CanConfig {
253 phantom: self.phantom,
254 info: self.info,
255 periph_clock: self.periph_clock,
256 }
243 } 257 }
244 258
245 /// Enables the peripheral and synchronizes with the bus. 259 /// Enables the peripheral and synchronizes with the bus.
@@ -247,7 +261,7 @@ impl<'d, T: Instance> Can<'d, T> {
247 /// This will wait for 11 consecutive recessive bits (bus idle state). 261 /// This will wait for 11 consecutive recessive bits (bus idle state).
248 /// Contrary to enable method from bxcan library, this will not freeze the executor while waiting. 262 /// Contrary to enable method from bxcan library, this will not freeze the executor while waiting.
249 pub async fn enable(&mut self) { 263 pub async fn enable(&mut self) {
250 while Registers(T::regs()).enable_non_blocking().is_err() { 264 while self.info.regs.enable_non_blocking().is_err() {
251 // SCE interrupt is only generated for entering sleep mode, but not leaving. 265 // SCE interrupt is only generated for entering sleep mode, but not leaving.
252 // Yield to allow other tasks to execute while can bus is initializing. 266 // Yield to allow other tasks to execute while can bus is initializing.
253 embassy_futures::yield_now().await; 267 embassy_futures::yield_now().await;
@@ -257,7 +271,7 @@ impl<'d, T: Instance> Can<'d, T> {
257 /// Enables or disables the peripheral from automatically wakeup when a SOF is detected on the bus 271 /// Enables or disables the peripheral from automatically wakeup when a SOF is detected on the bus
258 /// while the peripheral is in sleep mode 272 /// while the peripheral is in sleep mode
259 pub fn set_automatic_wakeup(&mut self, enabled: bool) { 273 pub fn set_automatic_wakeup(&mut self, enabled: bool) {
260 Registers(T::regs()).set_automatic_wakeup(enabled); 274 self.info.regs.set_automatic_wakeup(enabled);
261 } 275 }
262 276
263 /// Manually wake the peripheral from sleep mode. 277 /// Manually wake the peripheral from sleep mode.
@@ -265,12 +279,12 @@ impl<'d, T: Instance> Can<'d, T> {
265 /// Waking the peripheral manually does not trigger a wake-up interrupt. 279 /// Waking the peripheral manually does not trigger a wake-up interrupt.
266 /// This will wait until the peripheral has acknowledged it has awoken from sleep mode 280 /// This will wait until the peripheral has acknowledged it has awoken from sleep mode
267 pub fn wakeup(&mut self) { 281 pub fn wakeup(&mut self) {
268 Registers(T::regs()).wakeup() 282 self.info.regs.wakeup()
269 } 283 }
270 284
271 /// Check if the peripheral is currently in sleep mode 285 /// Check if the peripheral is currently in sleep mode
272 pub fn is_sleeping(&self) -> bool { 286 pub fn is_sleeping(&self) -> bool {
273 T::regs().msr().read().slak() 287 self.info.regs.0.msr().read().slak()
274 } 288 }
275 289
276 /// Put the peripheral in sleep mode 290 /// Put the peripheral in sleep mode
@@ -282,11 +296,11 @@ impl<'d, T: Instance> Can<'d, T> {
282 /// If the peripheral has automatic wakeup enabled, when a Start-of-Frame is detected 296 /// If the peripheral has automatic wakeup enabled, when a Start-of-Frame is detected
283 /// the peripheral will automatically wake and receive the incoming message. 297 /// the peripheral will automatically wake and receive the incoming message.
284 pub async fn sleep(&mut self) { 298 pub async fn sleep(&mut self) {
285 T::regs().ier().modify(|i| i.set_slkie(true)); 299 self.info.regs.0.ier().modify(|i| i.set_slkie(true));
286 T::regs().mcr().modify(|m| m.set_sleep(true)); 300 self.info.regs.0.mcr().modify(|m| m.set_sleep(true));
287 301
288 poll_fn(|cx| { 302 poll_fn(|cx| {
289 T::state().err_waker.register(cx.waker()); 303 self.state.err_waker.register(cx.waker());
290 if self.is_sleeping() { 304 if self.is_sleeping() {
291 Poll::Ready(()) 305 Poll::Ready(())
292 } else { 306 } else {
@@ -295,7 +309,7 @@ impl<'d, T: Instance> Can<'d, T> {
295 }) 309 })
296 .await; 310 .await;
297 311
298 T::regs().ier().modify(|i| i.set_slkie(false)); 312 self.info.regs.0.ier().modify(|i| i.set_slkie(false));
299 } 313 }
300 314
301 /// Enable FIFO scheduling of outgoing frames. 315 /// Enable FIFO scheduling of outgoing frames.
@@ -307,12 +321,12 @@ impl<'d, T: Instance> Can<'d, T> {
307 /// 321 ///
308 /// FIFO scheduling is disabled by default. 322 /// FIFO scheduling is disabled by default.
309 pub fn set_tx_fifo_scheduling(&mut self, enabled: bool) { 323 pub fn set_tx_fifo_scheduling(&mut self, enabled: bool) {
310 Registers(T::regs()).set_tx_fifo_scheduling(enabled) 324 self.info.regs.set_tx_fifo_scheduling(enabled)
311 } 325 }
312 326
313 /// Checks if FIFO scheduling of outgoing frames is enabled. 327 /// Checks if FIFO scheduling of outgoing frames is enabled.
314 pub fn tx_fifo_scheduling_enabled(&self) -> bool { 328 pub fn tx_fifo_scheduling_enabled(&self) -> bool {
315 Registers(T::regs()).tx_fifo_scheduling_enabled() 329 self.info.regs.tx_fifo_scheduling_enabled()
316 } 330 }
317 331
318 /// Queues the message to be sent. 332 /// Queues the message to be sent.
@@ -337,7 +351,13 @@ impl<'d, T: Instance> Can<'d, T> {
337 351
338 /// Waits for a specific transmit mailbox to become empty 352 /// Waits for a specific transmit mailbox to become empty
339 pub async fn flush(&self, mb: Mailbox) { 353 pub async fn flush(&self, mb: Mailbox) {
340 CanTx::<T>::flush_inner(mb).await 354 CanTx {
355 _phantom: PhantomData,
356 info: self.info,
357 state: self.state,
358 }
359 .flush_inner(mb)
360 .await;
341 } 361 }
342 362
343 /// Waits until any of the transmit mailboxes become empty 363 /// Waits until any of the transmit mailboxes become empty
@@ -347,12 +367,24 @@ impl<'d, T: Instance> Can<'d, T> {
347 /// This will happen if FIFO scheduling of outgoing frames is not enabled, 367 /// This will happen if FIFO scheduling of outgoing frames is not enabled,
348 /// and a frame with equal priority is already queued for transmission. 368 /// and a frame with equal priority is already queued for transmission.
349 pub async fn flush_any(&self) { 369 pub async fn flush_any(&self) {
350 CanTx::<T>::flush_any_inner().await 370 CanTx {
371 _phantom: PhantomData,
372 info: self.info,
373 state: self.state,
374 }
375 .flush_any_inner()
376 .await
351 } 377 }
352 378
353 /// Waits until all of the transmit mailboxes become empty 379 /// Waits until all of the transmit mailboxes become empty
354 pub async fn flush_all(&self) { 380 pub async fn flush_all(&self) {
355 CanTx::<T>::flush_all_inner().await 381 CanTx {
382 _phantom: PhantomData,
383 info: self.info,
384 state: self.state,
385 }
386 .flush_all_inner()
387 .await
356 } 388 }
357 389
358 /// Attempts to abort the sending of a frame that is pending in a mailbox. 390 /// Attempts to abort the sending of a frame that is pending in a mailbox.
@@ -363,12 +395,12 @@ impl<'d, T: Instance> Can<'d, T> {
363 /// If there is a frame in the provided mailbox, and it is canceled successfully, this function 395 /// If there is a frame in the provided mailbox, and it is canceled successfully, this function
364 /// returns `true`. 396 /// returns `true`.
365 pub fn abort(&mut self, mailbox: Mailbox) -> bool { 397 pub fn abort(&mut self, mailbox: Mailbox) -> bool {
366 Registers(T::regs()).abort(mailbox) 398 self.info.regs.abort(mailbox)
367 } 399 }
368 400
369 /// Returns `true` if no frame is pending for transmission. 401 /// Returns `true` if no frame is pending for transmission.
370 pub fn is_transmitter_idle(&self) -> bool { 402 pub fn is_transmitter_idle(&self) -> bool {
371 Registers(T::regs()).is_idle() 403 self.info.regs.is_idle()
372 } 404 }
373 405
374 /// Read a CAN frame. 406 /// Read a CAN frame.
@@ -377,31 +409,35 @@ impl<'d, T: Instance> Can<'d, T> {
377 /// 409 ///
378 /// Returns a tuple of the time the message was received and the message frame 410 /// Returns a tuple of the time the message was received and the message frame
379 pub async fn read(&mut self) -> Result<Envelope, BusError> { 411 pub async fn read(&mut self) -> Result<Envelope, BusError> {
380 T::state().rx_mode.read::<T>().await 412 self.state.rx_mode.read(self.info, self.state).await
381 } 413 }
382 414
383 /// Attempts to read a CAN frame without blocking. 415 /// Attempts to read a CAN frame without blocking.
384 /// 416 ///
385 /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. 417 /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
386 pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { 418 pub fn try_read(&mut self) -> Result<Envelope, TryReadError> {
387 T::state().rx_mode.try_read::<T>() 419 self.state.rx_mode.try_read(self.info)
388 } 420 }
389 421
390 /// Waits while receive queue is empty. 422 /// Waits while receive queue is empty.
391 pub async fn wait_not_empty(&mut self) { 423 pub async fn wait_not_empty(&mut self) {
392 T::state().rx_mode.wait_not_empty::<T>().await 424 self.state.rx_mode.wait_not_empty(self.info, self.state).await
393 } 425 }
394 426
395 /// Split the CAN driver into transmit and receive halves. 427 /// Split the CAN driver into transmit and receive halves.
396 /// 428 ///
397 /// Useful for doing separate transmit/receive tasks. 429 /// Useful for doing separate transmit/receive tasks.
398 pub fn split<'c>(&'c mut self) -> (CanTx<'d, T>, CanRx<'d, T>) { 430 pub fn split<'c>(&'c mut self) -> (CanTx<'d>, CanRx<'d>) {
399 ( 431 (
400 CanTx { 432 CanTx {
401 _peri: unsafe { self.peri.clone_unchecked() }, 433 _phantom: PhantomData,
434 info: self.info,
435 state: self.state,
402 }, 436 },
403 CanRx { 437 CanRx {
404 peri: unsafe { self.peri.clone_unchecked() }, 438 _phantom: PhantomData,
439 info: self.info,
440 state: self.state,
405 }, 441 },
406 ) 442 )
407 } 443 }
@@ -411,7 +447,7 @@ impl<'d, T: Instance> Can<'d, T> {
411 &'c mut self, 447 &'c mut self,
412 txb: &'static mut TxBuf<TX_BUF_SIZE>, 448 txb: &'static mut TxBuf<TX_BUF_SIZE>,
413 rxb: &'static mut RxBuf<RX_BUF_SIZE>, 449 rxb: &'static mut RxBuf<RX_BUF_SIZE>,
414 ) -> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { 450 ) -> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
415 let (tx, rx) = self.split(); 451 let (tx, rx) = self.split();
416 BufferedCan { 452 BufferedCan {
417 tx: tx.buffered(txb), 453 tx: tx.buffered(txb),
@@ -420,23 +456,23 @@ impl<'d, T: Instance> Can<'d, T> {
420 } 456 }
421} 457}
422 458
423impl<'d, T: FilterOwner> Can<'d, T> { 459impl<'d> Can<'d> {
424 /// Accesses the filter banks owned by this CAN peripheral. 460 /// Accesses the filter banks owned by this CAN peripheral.
425 /// 461 ///
426 /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master 462 /// To modify filters of a slave peripheral, `modify_filters` has to be called on the master
427 /// peripheral instead. 463 /// peripheral instead.
428 pub fn modify_filters(&mut self) -> MasterFilters<'_, T> { 464 pub fn modify_filters(&mut self) -> MasterFilters<'_> {
429 unsafe { MasterFilters::new(T::regs()) } 465 unsafe { MasterFilters::new(self.info) }
430 } 466 }
431} 467}
432 468
433/// Buffered CAN driver. 469/// Buffered CAN driver.
434pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { 470pub struct BufferedCan<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
435 tx: BufferedCanTx<'d, T, TX_BUF_SIZE>, 471 tx: BufferedCanTx<'d, TX_BUF_SIZE>,
436 rx: BufferedCanRx<'d, T, RX_BUF_SIZE>, 472 rx: BufferedCanRx<'d, RX_BUF_SIZE>,
437} 473}
438 474
439impl<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { 475impl<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
440 /// Async write frame to TX buffer. 476 /// Async write frame to TX buffer.
441 pub async fn write(&mut self, frame: &Frame) { 477 pub async fn write(&mut self, frame: &Frame) {
442 self.tx.write(frame).await 478 self.tx.write(frame).await
@@ -471,18 +507,20 @@ impl<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Buffer
471} 507}
472 508
473/// CAN driver, transmit half. 509/// CAN driver, transmit half.
474pub struct CanTx<'d, T: Instance> { 510pub struct CanTx<'d> {
475 _peri: PeripheralRef<'d, T>, 511 _phantom: PhantomData<&'d ()>,
512 info: &'static Info,
513 state: &'static State,
476} 514}
477 515
478impl<'d, T: Instance> CanTx<'d, T> { 516impl<'d> CanTx<'d> {
479 /// Queues the message to be sent. 517 /// Queues the message to be sent.
480 /// 518 ///
481 /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. 519 /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure.
482 pub async fn write(&mut self, frame: &Frame) -> TransmitStatus { 520 pub async fn write(&mut self, frame: &Frame) -> TransmitStatus {
483 poll_fn(|cx| { 521 poll_fn(|cx| {
484 T::state().tx_mode.register(cx.waker()); 522 self.state.tx_mode.register(cx.waker());
485 if let Ok(status) = Registers(T::regs()).transmit(frame) { 523 if let Ok(status) = self.info.regs.transmit(frame) {
486 return Poll::Ready(status); 524 return Poll::Ready(status);
487 } 525 }
488 526
@@ -501,13 +539,13 @@ impl<'d, T: Instance> CanTx<'d, T> {
501 /// This is done to work around a hardware limitation that could lead to out-of-order delivery 539 /// This is done to work around a hardware limitation that could lead to out-of-order delivery
502 /// of frames with the same priority. 540 /// of frames with the same priority.
503 pub fn try_write(&mut self, frame: &Frame) -> Result<TransmitStatus, TryWriteError> { 541 pub fn try_write(&mut self, frame: &Frame) -> Result<TransmitStatus, TryWriteError> {
504 Registers(T::regs()).transmit(frame).map_err(|_| TryWriteError::Full) 542 self.info.regs.transmit(frame).map_err(|_| TryWriteError::Full)
505 } 543 }
506 544
507 async fn flush_inner(mb: Mailbox) { 545 async fn flush_inner(&self, mb: Mailbox) {
508 poll_fn(|cx| { 546 poll_fn(|cx| {
509 T::state().tx_mode.register(cx.waker()); 547 self.state.tx_mode.register(cx.waker());
510 if T::regs().tsr().read().tme(mb.index()) { 548 if self.info.regs.0.tsr().read().tme(mb.index()) {
511 return Poll::Ready(()); 549 return Poll::Ready(());
512 } 550 }
513 551
@@ -518,14 +556,14 @@ impl<'d, T: Instance> CanTx<'d, T> {
518 556
519 /// Waits for a specific transmit mailbox to become empty 557 /// Waits for a specific transmit mailbox to become empty
520 pub async fn flush(&self, mb: Mailbox) { 558 pub async fn flush(&self, mb: Mailbox) {
521 Self::flush_inner(mb).await 559 self.flush_inner(mb).await
522 } 560 }
523 561
524 async fn flush_any_inner() { 562 async fn flush_any_inner(&self) {
525 poll_fn(|cx| { 563 poll_fn(|cx| {
526 T::state().tx_mode.register(cx.waker()); 564 self.state.tx_mode.register(cx.waker());
527 565
528 let tsr = T::regs().tsr().read(); 566 let tsr = self.info.regs.0.tsr().read();
529 if tsr.tme(Mailbox::Mailbox0.index()) 567 if tsr.tme(Mailbox::Mailbox0.index())
530 || tsr.tme(Mailbox::Mailbox1.index()) 568 || tsr.tme(Mailbox::Mailbox1.index())
531 || tsr.tme(Mailbox::Mailbox2.index()) 569 || tsr.tme(Mailbox::Mailbox2.index())
@@ -545,14 +583,14 @@ impl<'d, T: Instance> CanTx<'d, T> {
545 /// This will happen if FIFO scheduling of outgoing frames is not enabled, 583 /// This will happen if FIFO scheduling of outgoing frames is not enabled,
546 /// and a frame with equal priority is already queued for transmission. 584 /// and a frame with equal priority is already queued for transmission.
547 pub async fn flush_any(&self) { 585 pub async fn flush_any(&self) {
548 Self::flush_any_inner().await 586 self.flush_any_inner().await
549 } 587 }
550 588
551 async fn flush_all_inner() { 589 async fn flush_all_inner(&self) {
552 poll_fn(|cx| { 590 poll_fn(|cx| {
553 T::state().tx_mode.register(cx.waker()); 591 self.state.tx_mode.register(cx.waker());
554 592
555 let tsr = T::regs().tsr().read(); 593 let tsr = self.info.regs.0.tsr().read();
556 if tsr.tme(Mailbox::Mailbox0.index()) 594 if tsr.tme(Mailbox::Mailbox0.index())
557 && tsr.tme(Mailbox::Mailbox1.index()) 595 && tsr.tme(Mailbox::Mailbox1.index())
558 && tsr.tme(Mailbox::Mailbox2.index()) 596 && tsr.tme(Mailbox::Mailbox2.index())
@@ -567,7 +605,7 @@ impl<'d, T: Instance> CanTx<'d, T> {
567 605
568 /// Waits until all of the transmit mailboxes become empty 606 /// Waits until all of the transmit mailboxes become empty
569 pub async fn flush_all(&self) { 607 pub async fn flush_all(&self) {
570 Self::flush_all_inner().await 608 self.flush_all_inner().await
571 } 609 }
572 610
573 /// Attempts to abort the sending of a frame that is pending in a mailbox. 611 /// Attempts to abort the sending of a frame that is pending in a mailbox.
@@ -578,20 +616,20 @@ impl<'d, T: Instance> CanTx<'d, T> {
578 /// If there is a frame in the provided mailbox, and it is canceled successfully, this function 616 /// If there is a frame in the provided mailbox, and it is canceled successfully, this function
579 /// returns `true`. 617 /// returns `true`.
580 pub fn abort(&mut self, mailbox: Mailbox) -> bool { 618 pub fn abort(&mut self, mailbox: Mailbox) -> bool {
581 Registers(T::regs()).abort(mailbox) 619 self.info.regs.abort(mailbox)
582 } 620 }
583 621
584 /// Returns `true` if no frame is pending for transmission. 622 /// Returns `true` if no frame is pending for transmission.
585 pub fn is_idle(&self) -> bool { 623 pub fn is_idle(&self) -> bool {
586 Registers(T::regs()).is_idle() 624 self.info.regs.is_idle()
587 } 625 }
588 626
589 /// Return a buffered instance of driver. User must supply Buffers 627 /// Return a buffered instance of driver. User must supply Buffers
590 pub fn buffered<const TX_BUF_SIZE: usize>( 628 pub fn buffered<const TX_BUF_SIZE: usize>(
591 self, 629 self,
592 txb: &'static mut TxBuf<TX_BUF_SIZE>, 630 txb: &'static mut TxBuf<TX_BUF_SIZE>,
593 ) -> BufferedCanTx<'d, T, TX_BUF_SIZE> { 631 ) -> BufferedCanTx<'d, TX_BUF_SIZE> {
594 BufferedCanTx::new(self, txb) 632 BufferedCanTx::new(self.info, self.state, self, txb)
595 } 633 }
596} 634}
597 635
@@ -599,23 +637,35 @@ impl<'d, T: Instance> CanTx<'d, T> {
599pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>; 637pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>;
600 638
601/// Buffered CAN driver, transmit half. 639/// Buffered CAN driver, transmit half.
602pub struct BufferedCanTx<'d, T: Instance, const TX_BUF_SIZE: usize> { 640pub struct BufferedCanTx<'d, const TX_BUF_SIZE: usize> {
603 _tx: CanTx<'d, T>, 641 info: &'static Info,
642 state: &'static State,
643 _tx: CanTx<'d>,
604 tx_buf: &'static TxBuf<TX_BUF_SIZE>, 644 tx_buf: &'static TxBuf<TX_BUF_SIZE>,
605} 645}
606 646
607impl<'d, T: Instance, const TX_BUF_SIZE: usize> BufferedCanTx<'d, T, TX_BUF_SIZE> { 647impl<'d, const TX_BUF_SIZE: usize> BufferedCanTx<'d, TX_BUF_SIZE> {
608 fn new(_tx: CanTx<'d, T>, tx_buf: &'static TxBuf<TX_BUF_SIZE>) -> Self { 648 fn new(info: &'static Info, state: &'static State, _tx: CanTx<'d>, tx_buf: &'static TxBuf<TX_BUF_SIZE>) -> Self {
609 Self { _tx, tx_buf }.setup() 649 Self {
650 info,
651 state,
652 _tx,
653 tx_buf,
654 }
655 .setup()
610 } 656 }
611 657
612 fn setup(self) -> Self { 658 fn setup(self) -> Self {
613 // We don't want interrupts being processed while we change modes. 659 // We don't want interrupts being processed while we change modes.
614 critical_section::with(|_| unsafe { 660 critical_section::with(|_| {
615 let tx_inner = super::common::ClassicBufferedTxInner { 661 let tx_inner = super::common::ClassicBufferedTxInner {
616 tx_receiver: self.tx_buf.receiver().into(), 662 tx_receiver: self.tx_buf.receiver().into(),
617 }; 663 };
618 T::mut_state().tx_mode = TxMode::Buffered(tx_inner); 664 let state = self.state as *const State;
665 unsafe {
666 let mut_state = state as *mut State;
667 (*mut_state).tx_mode = TxMode::Buffered(tx_inner);
668 }
619 }); 669 });
620 self 670 self
621 } 671 }
@@ -623,60 +673,67 @@ impl<'d, T: Instance, const TX_BUF_SIZE: usize> BufferedCanTx<'d, T, TX_BUF_SIZE
623 /// Async write frame to TX buffer. 673 /// Async write frame to TX buffer.
624 pub async fn write(&mut self, frame: &Frame) { 674 pub async fn write(&mut self, frame: &Frame) {
625 self.tx_buf.send(*frame).await; 675 self.tx_buf.send(*frame).await;
626 T::TXInterrupt::pend(); // Wake for Tx 676 let waker = self.info.tx_waker;
677 waker(); // Wake for Tx
627 } 678 }
628 679
629 /// Returns a sender that can be used for sending CAN frames. 680 /// Returns a sender that can be used for sending CAN frames.
630 pub fn writer(&self) -> BufferedCanSender { 681 pub fn writer(&self) -> BufferedCanSender {
631 BufferedCanSender { 682 BufferedCanSender {
632 tx_buf: self.tx_buf.sender().into(), 683 tx_buf: self.tx_buf.sender().into(),
633 waker: T::TXInterrupt::pend, 684 waker: self.info.tx_waker,
634 } 685 }
635 } 686 }
636} 687}
637 688
638impl<'d, T: Instance, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, T, TX_BUF_SIZE> { 689impl<'d, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, TX_BUF_SIZE> {
639 fn drop(&mut self) { 690 fn drop(&mut self) {
640 critical_section::with(|_| unsafe { 691 critical_section::with(|_| {
641 T::mut_state().tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); 692 let state = self.state as *const State;
693 unsafe {
694 let mut_state = state as *mut State;
695 (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
696 }
642 }); 697 });
643 } 698 }
644} 699}
645 700
646/// CAN driver, receive half. 701/// CAN driver, receive half.
647#[allow(dead_code)] 702#[allow(dead_code)]
648pub struct CanRx<'d, T: Instance> { 703pub struct CanRx<'d> {
649 peri: PeripheralRef<'d, T>, 704 _phantom: PhantomData<&'d ()>,
705 info: &'static Info,
706 state: &'static State,
650} 707}
651 708
652impl<'d, T: Instance> CanRx<'d, T> { 709impl<'d> CanRx<'d> {
653 /// Read a CAN frame. 710 /// Read a CAN frame.
654 /// 711 ///
655 /// If no CAN frame is in the RX buffer, this will wait until there is one. 712 /// If no CAN frame is in the RX buffer, this will wait until there is one.
656 /// 713 ///
657 /// Returns a tuple of the time the message was received and the message frame 714 /// Returns a tuple of the time the message was received and the message frame
658 pub async fn read(&mut self) -> Result<Envelope, BusError> { 715 pub async fn read(&mut self) -> Result<Envelope, BusError> {
659 T::state().rx_mode.read::<T>().await 716 self.state.rx_mode.read(self.info, self.state).await
660 } 717 }
661 718
662 /// Attempts to read a CAN frame without blocking. 719 /// Attempts to read a CAN frame without blocking.
663 /// 720 ///
664 /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. 721 /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
665 pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { 722 pub fn try_read(&mut self) -> Result<Envelope, TryReadError> {
666 T::state().rx_mode.try_read::<T>() 723 self.state.rx_mode.try_read(self.info)
667 } 724 }
668 725
669 /// Waits while receive queue is empty. 726 /// Waits while receive queue is empty.
670 pub async fn wait_not_empty(&mut self) { 727 pub async fn wait_not_empty(&mut self) {
671 T::state().rx_mode.wait_not_empty::<T>().await 728 self.state.rx_mode.wait_not_empty(self.info, self.state).await
672 } 729 }
673 730
674 /// Return a buffered instance of driver. User must supply Buffers 731 /// Return a buffered instance of driver. User must supply Buffers
675 pub fn buffered<const RX_BUF_SIZE: usize>( 732 pub fn buffered<const RX_BUF_SIZE: usize>(
676 self, 733 self,
677 rxb: &'static mut RxBuf<RX_BUF_SIZE>, 734 rxb: &'static mut RxBuf<RX_BUF_SIZE>,
678 ) -> BufferedCanRx<'d, T, RX_BUF_SIZE> { 735 ) -> BufferedCanRx<'d, RX_BUF_SIZE> {
679 BufferedCanRx::new(self, rxb) 736 BufferedCanRx::new(self.info, self.state, self, rxb)
680 } 737 }
681} 738}
682 739
@@ -684,23 +741,35 @@ impl<'d, T: Instance> CanRx<'d, T> {
684pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<Envelope, BusError>, BUF_SIZE>; 741pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<Envelope, BusError>, BUF_SIZE>;
685 742
686/// CAN driver, receive half in Buffered mode. 743/// CAN driver, receive half in Buffered mode.
687pub struct BufferedCanRx<'d, T: Instance, const RX_BUF_SIZE: usize> { 744pub struct BufferedCanRx<'d, const RX_BUF_SIZE: usize> {
688 _rx: CanRx<'d, T>, 745 info: &'static Info,
746 state: &'static State,
747 _rx: CanRx<'d>,
689 rx_buf: &'static RxBuf<RX_BUF_SIZE>, 748 rx_buf: &'static RxBuf<RX_BUF_SIZE>,
690} 749}
691 750
692impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE> { 751impl<'d, const RX_BUF_SIZE: usize> BufferedCanRx<'d, RX_BUF_SIZE> {
693 fn new(_rx: CanRx<'d, T>, rx_buf: &'static RxBuf<RX_BUF_SIZE>) -> Self { 752 fn new(info: &'static Info, state: &'static State, _rx: CanRx<'d>, rx_buf: &'static RxBuf<RX_BUF_SIZE>) -> Self {
694 BufferedCanRx { _rx, rx_buf }.setup() 753 BufferedCanRx {
754 info,
755 state,
756 _rx,
757 rx_buf,
758 }
759 .setup()
695 } 760 }
696 761
697 fn setup(self) -> Self { 762 fn setup(self) -> Self {
698 // We don't want interrupts being processed while we change modes. 763 // We don't want interrupts being processed while we change modes.
699 critical_section::with(|_| unsafe { 764 critical_section::with(|_| {
700 let rx_inner = super::common::ClassicBufferedRxInner { 765 let rx_inner = super::common::ClassicBufferedRxInner {
701 rx_sender: self.rx_buf.sender().into(), 766 rx_sender: self.rx_buf.sender().into(),
702 }; 767 };
703 T::mut_state().rx_mode = RxMode::Buffered(rx_inner); 768 let state = self.state as *const State;
769 unsafe {
770 let mut_state = state as *mut State;
771 (*mut_state).rx_mode = RxMode::Buffered(rx_inner);
772 }
704 }); 773 });
705 self 774 self
706 } 775 }
@@ -714,7 +783,7 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE
714 /// 783 ///
715 /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. 784 /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
716 pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { 785 pub fn try_read(&mut self) -> Result<Envelope, TryReadError> {
717 match &T::state().rx_mode { 786 match &self.state.rx_mode {
718 RxMode::Buffered(_) => { 787 RxMode::Buffered(_) => {
719 if let Ok(result) = self.rx_buf.try_receive() { 788 if let Ok(result) = self.rx_buf.try_receive() {
720 match result { 789 match result {
@@ -722,7 +791,7 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE
722 Err(e) => Err(TryReadError::BusError(e)), 791 Err(e) => Err(TryReadError::BusError(e)),
723 } 792 }
724 } else { 793 } else {
725 if let Some(err) = Registers(T::regs()).curr_error() { 794 if let Some(err) = self.info.regs.curr_error() {
726 return Err(TryReadError::BusError(err)); 795 return Err(TryReadError::BusError(err));
727 } else { 796 } else {
728 Err(TryReadError::Empty) 797 Err(TryReadError::Empty)
@@ -746,20 +815,26 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE
746 } 815 }
747} 816}
748 817
749impl<'d, T: Instance, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, T, RX_BUF_SIZE> { 818impl<'d, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, RX_BUF_SIZE> {
750 fn drop(&mut self) { 819 fn drop(&mut self) {
751 critical_section::with(|_| unsafe { 820 critical_section::with(|_| {
752 T::mut_state().rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); 821 let state = self.state as *const State;
822 unsafe {
823 let mut_state = state as *mut State;
824 (*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
825 }
753 }); 826 });
754 } 827 }
755} 828}
756 829
757impl<'d, T: Instance> Drop for Can<'d, T> { 830impl Drop for Can<'_> {
758 fn drop(&mut self) { 831 fn drop(&mut self) {
759 // Cannot call `free()` because it moves the instance. 832 // Cannot call `free()` because it moves the instance.
760 // Manually reset the peripheral. 833 // Manually reset the peripheral.
761 T::regs().mcr().write(|w| w.set_reset(true)); 834 self.info.regs.0.mcr().write(|w| w.set_reset(true));
762 T::disable(); 835 self.info.regs.enter_init_mode();
836 self.info.regs.leave_init_mode();
837 //rcc::disable::<T>();
763 } 838 }
764} 839}
765 840
@@ -839,13 +914,13 @@ impl RxMode {
839 } 914 }
840 } 915 }
841 916
842 pub async fn read<T: Instance>(&self) -> Result<Envelope, BusError> { 917 pub(crate) async fn read(&self, info: &Info, state: &State) -> Result<Envelope, BusError> {
843 match self { 918 match self {
844 Self::NonBuffered(waker) => { 919 Self::NonBuffered(waker) => {
845 poll_fn(|cx| { 920 poll_fn(|cx| {
846 T::state().err_waker.register(cx.waker()); 921 state.err_waker.register(cx.waker());
847 waker.register(cx.waker()); 922 waker.register(cx.waker());
848 match self.try_read::<T>() { 923 match self.try_read(info) {
849 Ok(result) => Poll::Ready(Ok(result)), 924 Ok(result) => Poll::Ready(Ok(result)),
850 Err(TryReadError::Empty) => Poll::Pending, 925 Err(TryReadError::Empty) => Poll::Pending,
851 Err(TryReadError::BusError(be)) => Poll::Ready(Err(be)), 926 Err(TryReadError::BusError(be)) => Poll::Ready(Err(be)),
@@ -858,17 +933,17 @@ impl RxMode {
858 } 933 }
859 } 934 }
860 } 935 }
861 pub fn try_read<T: Instance>(&self) -> Result<Envelope, TryReadError> { 936 pub(crate) fn try_read(&self, info: &Info) -> Result<Envelope, TryReadError> {
862 match self { 937 match self {
863 Self::NonBuffered(_) => { 938 Self::NonBuffered(_) => {
864 let registers = Registers(T::regs()); 939 let registers = &info.regs;
865 if let Some(msg) = registers.receive_fifo(RxFifo::Fifo0) { 940 if let Some(msg) = registers.receive_fifo(RxFifo::Fifo0) {
866 T::regs().ier().write(|w| { 941 registers.0.ier().write(|w| {
867 w.set_fmpie(0, true); 942 w.set_fmpie(0, true);
868 }); 943 });
869 Ok(msg) 944 Ok(msg)
870 } else if let Some(msg) = registers.receive_fifo(RxFifo::Fifo1) { 945 } else if let Some(msg) = registers.receive_fifo(RxFifo::Fifo1) {
871 T::regs().ier().write(|w| { 946 registers.0.ier().write(|w| {
872 w.set_fmpie(1, true); 947 w.set_fmpie(1, true);
873 }); 948 });
874 Ok(msg) 949 Ok(msg)
@@ -883,12 +958,12 @@ impl RxMode {
883 } 958 }
884 } 959 }
885 } 960 }
886 pub async fn wait_not_empty<T: Instance>(&self) { 961 pub(crate) async fn wait_not_empty(&self, info: &Info, state: &State) {
887 match &T::state().rx_mode { 962 match &state.rx_mode {
888 Self::NonBuffered(waker) => { 963 Self::NonBuffered(waker) => {
889 poll_fn(|cx| { 964 poll_fn(|cx| {
890 waker.register(cx.waker()); 965 waker.register(cx.waker());
891 if Registers(T::regs()).receive_frame_available() { 966 if info.regs.receive_frame_available() {
892 Poll::Ready(()) 967 Poll::Ready(())
893 } else { 968 } else {
894 Poll::Pending 969 Poll::Pending
@@ -903,7 +978,7 @@ impl RxMode {
903 } 978 }
904} 979}
905 980
906enum TxMode { 981pub(crate) enum TxMode {
907 NonBuffered(AtomicWaker), 982 NonBuffered(AtomicWaker),
908 Buffered(super::common::ClassicBufferedTxInner), 983 Buffered(super::common::ClassicBufferedTxInner),
909} 984}
@@ -943,7 +1018,7 @@ impl TxMode {
943 } 1018 }
944} 1019}
945 1020
946struct State { 1021pub(crate) struct State {
947 pub(crate) rx_mode: RxMode, 1022 pub(crate) rx_mode: RxMode,
948 pub(crate) tx_mode: TxMode, 1023 pub(crate) tx_mode: TxMode,
949 pub err_waker: AtomicWaker, 1024 pub err_waker: AtomicWaker,
@@ -959,7 +1034,22 @@ impl State {
959 } 1034 }
960} 1035}
961 1036
1037pub(crate) struct Info {
1038 regs: Registers,
1039 tx_interrupt: crate::interrupt::Interrupt,
1040 rx0_interrupt: crate::interrupt::Interrupt,
1041 rx1_interrupt: crate::interrupt::Interrupt,
1042 sce_interrupt: crate::interrupt::Interrupt,
1043 tx_waker: fn(),
1044
1045 /// The total number of filter banks available to the instance.
1046 ///
1047 /// This is usually either 14 or 28, and should be specified in the chip's reference manual or datasheet.
1048 num_filter_banks: u8,
1049}
1050
962trait SealedInstance { 1051trait SealedInstance {
1052 fn info() -> &'static Info;
963 fn regs() -> crate::pac::can::Can; 1053 fn regs() -> crate::pac::can::Can;
964 fn state() -> &'static State; 1054 fn state() -> &'static State;
965 unsafe fn mut_state() -> &'static mut State; 1055 unsafe fn mut_state() -> &'static mut State;
@@ -1012,6 +1102,18 @@ foreach_peripheral!(
1012 (can, $inst:ident) => { 1102 (can, $inst:ident) => {
1013 impl SealedInstance for peripherals::$inst { 1103 impl SealedInstance for peripherals::$inst {
1014 1104
1105 fn info() -> &'static Info {
1106 static INFO: Info = Info {
1107 regs: Registers(crate::pac::$inst),
1108 tx_interrupt: crate::_generated::peripheral_interrupts::$inst::TX::IRQ,
1109 rx0_interrupt: crate::_generated::peripheral_interrupts::$inst::RX0::IRQ,
1110 rx1_interrupt: crate::_generated::peripheral_interrupts::$inst::RX1::IRQ,
1111 sce_interrupt: crate::_generated::peripheral_interrupts::$inst::SCE::IRQ,
1112 tx_waker: crate::_generated::peripheral_interrupts::$inst::TX::pend,
1113 num_filter_banks: peripherals::$inst::NUM_FILTER_BANKS,
1114 };
1115 &INFO
1116 }
1015 fn regs() -> crate::pac::can::Can { 1117 fn regs() -> crate::pac::can::Can {
1016 crate::pac::$inst 1118 crate::pac::$inst
1017 } 1119 }
@@ -1046,8 +1148,8 @@ foreach_peripheral!(
1046 (can, CAN1) => { 1148 (can, CAN1) => {
1047 cfg_if::cfg_if! { 1149 cfg_if::cfg_if! {
1048 if #[cfg(all( 1150 if #[cfg(all(
1049 any(stm32l4, stm32f72, stm32f73), 1151 any(stm32l4, stm32f72x, stm32f73x),
1050 not(any(stm32l49, stm32l4a)) 1152 not(any(stm32l49x, stm32l4ax))
1051 ))] { 1153 ))] {
1052 // Most L4 devices and some F7 devices use the name "CAN1" 1154 // Most L4 devices and some F7 devices use the name "CAN1"
1053 // even if there is no "CAN2" peripheral. 1155 // even if there is no "CAN2" peripheral.
@@ -1062,6 +1164,11 @@ foreach_peripheral!(
1062 } 1164 }
1063 } 1165 }
1064 }; 1166 };
1167 (can, CAN2) => {
1168 unsafe impl FilterOwner for peripherals::CAN2 {
1169 const NUM_FILTER_BANKS: u8 = 0;
1170 }
1171 };
1065 (can, CAN3) => { 1172 (can, CAN3) => {
1066 unsafe impl FilterOwner for peripherals::CAN3 { 1173 unsafe impl FilterOwner for peripherals::CAN3 {
1067 const NUM_FILTER_BANKS: u8 = 14; 1174 const NUM_FILTER_BANKS: u8 = 14;
diff --git a/embassy-stm32/src/can/bxcan/registers.rs b/embassy-stm32/src/can/bxcan/registers.rs
index ad27e0744..5f3d70e25 100644
--- a/embassy-stm32/src/can/bxcan/registers.rs
+++ b/embassy-stm32/src/can/bxcan/registers.rs
@@ -11,7 +11,7 @@ use crate::can::frame::{Envelope, Frame, Header};
11pub(crate) struct Registers(pub crate::pac::can::Can); 11pub(crate) struct Registers(pub crate::pac::can::Can);
12 12
13impl Registers { 13impl Registers {
14 pub fn enter_init_mode(&mut self) { 14 pub fn enter_init_mode(&self) {
15 self.0.mcr().modify(|reg| { 15 self.0.mcr().modify(|reg| {
16 reg.set_sleep(false); 16 reg.set_sleep(false);
17 reg.set_inrq(true); 17 reg.set_inrq(true);
@@ -25,7 +25,7 @@ impl Registers {
25 } 25 }
26 26
27 // Leaves initialization mode, enters sleep mode. 27 // Leaves initialization mode, enters sleep mode.
28 pub fn leave_init_mode(&mut self) { 28 pub fn leave_init_mode(&self) {
29 self.0.mcr().modify(|reg| { 29 self.0.mcr().modify(|reg| {
30 reg.set_sleep(true); 30 reg.set_sleep(true);
31 reg.set_inrq(false); 31 reg.set_inrq(false);
@@ -38,7 +38,7 @@ impl Registers {
38 } 38 }
39 } 39 }
40 40
41 pub fn set_bit_timing(&mut self, bt: crate::can::util::NominalBitTiming) { 41 pub fn set_bit_timing(&self, bt: crate::can::util::NominalBitTiming) {
42 let prescaler = u16::from(bt.prescaler) & 0x1FF; 42 let prescaler = u16::from(bt.prescaler) & 0x1FF;
43 let seg1 = u8::from(bt.seg1); 43 let seg1 = u8::from(bt.seg1);
44 let seg2 = u8::from(bt.seg2) & 0x7F; 44 let seg2 = u8::from(bt.seg2) & 0x7F;
@@ -84,7 +84,7 @@ impl Registers {
84 /// receive the frame. If enabled, [`Interrupt::Wakeup`] will also be triggered by the incoming 84 /// receive the frame. If enabled, [`Interrupt::Wakeup`] will also be triggered by the incoming
85 /// frame. 85 /// frame.
86 #[allow(dead_code)] 86 #[allow(dead_code)]
87 pub fn set_automatic_wakeup(&mut self, enabled: bool) { 87 pub fn set_automatic_wakeup(&self, enabled: bool) {
88 self.0.mcr().modify(|reg| reg.set_awum(enabled)); 88 self.0.mcr().modify(|reg| reg.set_awum(enabled));
89 } 89 }
90 90
@@ -96,7 +96,7 @@ impl Registers {
96 /// If this returns [`WouldBlock`][nb::Error::WouldBlock], the peripheral will enable itself 96 /// If this returns [`WouldBlock`][nb::Error::WouldBlock], the peripheral will enable itself
97 /// in the background. The peripheral is enabled and ready to use when this method returns 97 /// in the background. The peripheral is enabled and ready to use when this method returns
98 /// successfully. 98 /// successfully.
99 pub fn enable_non_blocking(&mut self) -> nb::Result<(), Infallible> { 99 pub fn enable_non_blocking(&self) -> nb::Result<(), Infallible> {
100 let msr = self.0.msr().read(); 100 let msr = self.0.msr().read();
101 if msr.slak() { 101 if msr.slak() {
102 self.0.mcr().modify(|reg| { 102 self.0.mcr().modify(|reg| {
@@ -131,7 +131,7 @@ impl Registers {
131 /// Note that this will not trigger [`Interrupt::Wakeup`], only reception of an incoming CAN 131 /// Note that this will not trigger [`Interrupt::Wakeup`], only reception of an incoming CAN
132 /// frame will cause that interrupt. 132 /// frame will cause that interrupt.
133 #[allow(dead_code)] 133 #[allow(dead_code)]
134 pub fn wakeup(&mut self) { 134 pub fn wakeup(&self) {
135 self.0.mcr().modify(|reg| { 135 self.0.mcr().modify(|reg| {
136 reg.set_sleep(false); 136 reg.set_sleep(false);
137 reg.set_inrq(false); 137 reg.set_inrq(false);
@@ -186,7 +186,7 @@ impl Registers {
186 /// If this is enabled, mailboxes are scheduled based on the time when the transmit request bit of the mailbox was set. 186 /// If this is enabled, mailboxes are scheduled based on the time when the transmit request bit of the mailbox was set.
187 /// 187 ///
188 /// If this is disabled, mailboxes are scheduled based on the priority of the frame in the mailbox. 188 /// If this is disabled, mailboxes are scheduled based on the priority of the frame in the mailbox.
189 pub fn set_tx_fifo_scheduling(&mut self, enabled: bool) { 189 pub fn set_tx_fifo_scheduling(&self, enabled: bool) {
190 self.0.mcr().modify(|w| w.set_txfp(enabled)) 190 self.0.mcr().modify(|w| w.set_txfp(enabled))
191 } 191 }
192 192
@@ -216,7 +216,7 @@ impl Registers {
216 /// If FIFO scheduling is enabled, frames are transmitted in the order that they are passed to this function. 216 /// If FIFO scheduling is enabled, frames are transmitted in the order that they are passed to this function.
217 /// 217 ///
218 /// If all transmit mailboxes are full, this function returns [`nb::Error::WouldBlock`]. 218 /// If all transmit mailboxes are full, this function returns [`nb::Error::WouldBlock`].
219 pub fn transmit(&mut self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> { 219 pub fn transmit(&self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> {
220 // Check if FIFO scheduling is enabled. 220 // Check if FIFO scheduling is enabled.
221 let fifo_scheduling = self.0.mcr().read().txfp(); 221 let fifo_scheduling = self.0.mcr().read().txfp();
222 222
@@ -292,7 +292,7 @@ impl Registers {
292 Ok(()) 292 Ok(())
293 } 293 }
294 294
295 fn write_mailbox(&mut self, idx: usize, frame: &Frame) { 295 fn write_mailbox(&self, idx: usize, frame: &Frame) {
296 debug_assert!(idx < 3); 296 debug_assert!(idx < 3);
297 297
298 let mb = self.0.tx(idx); 298 let mb = self.0.tx(idx);
@@ -309,7 +309,7 @@ impl Registers {
309 }); 309 });
310 } 310 }
311 311
312 fn read_pending_mailbox(&mut self, idx: usize) -> Option<Frame> { 312 fn read_pending_mailbox(&self, idx: usize) -> Option<Frame> {
313 if self.abort_by_index(idx) { 313 if self.abort_by_index(idx) {
314 debug_assert!(idx < 3); 314 debug_assert!(idx < 3);
315 315
@@ -332,7 +332,7 @@ impl Registers {
332 } 332 }
333 333
334 /// Tries to abort a pending frame. Returns `true` when aborted. 334 /// Tries to abort a pending frame. Returns `true` when aborted.
335 fn abort_by_index(&mut self, idx: usize) -> bool { 335 fn abort_by_index(&self, idx: usize) -> bool {
336 self.0.tsr().write(|reg| reg.set_abrq(idx, true)); 336 self.0.tsr().write(|reg| reg.set_abrq(idx, true));
337 337
338 // Wait for the abort request to be finished. 338 // Wait for the abort request to be finished.
@@ -351,7 +351,7 @@ impl Registers {
351 /// 351 ///
352 /// If there is a frame in the provided mailbox, and it is canceled successfully, this function 352 /// If there is a frame in the provided mailbox, and it is canceled successfully, this function
353 /// returns `true`. 353 /// returns `true`.
354 pub fn abort(&mut self, mailbox: Mailbox) -> bool { 354 pub fn abort(&self, mailbox: Mailbox) -> bool {
355 // If the mailbox is empty, the value of TXOKx depends on what happened with the previous 355 // If the mailbox is empty, the value of TXOKx depends on what happened with the previous
356 // frame in that mailbox. Only call abort_by_index() if the mailbox is not empty. 356 // frame in that mailbox. Only call abort_by_index() if the mailbox is not empty.
357 let tsr = self.0.tsr().read(); 357 let tsr = self.0.tsr().read();
diff --git a/embassy-stm32/src/can/fd/peripheral.rs b/embassy-stm32/src/can/fd/peripheral.rs
index 9cd5f0785..07e3dddad 100644
--- a/embassy-stm32/src/can/fd/peripheral.rs
+++ b/embassy-stm32/src/can/fd/peripheral.rs
@@ -20,8 +20,9 @@ enum LoopbackMode {
20} 20}
21 21
22pub struct Registers { 22pub struct Registers {
23 pub regs: &'static crate::pac::can::Fdcan, 23 pub regs: crate::pac::can::Fdcan,
24 pub msgram: &'static crate::pac::fdcanram::Fdcanram, 24 pub msgram: crate::pac::fdcanram::Fdcanram,
25 #[allow(dead_code)]
25 pub msg_ram_offset: usize, 26 pub msg_ram_offset: usize,
26} 27}
27 28
@@ -72,7 +73,6 @@ impl Registers {
72 73
73 pub fn put_tx_frame(&self, bufidx: usize, header: &Header, buffer: &[u8]) { 74 pub fn put_tx_frame(&self, bufidx: usize, header: &Header, buffer: &[u8]) {
74 let mailbox = self.tx_buffer_element(bufidx); 75 let mailbox = self.tx_buffer_element(bufidx);
75
76 mailbox.reset(); 76 mailbox.reset();
77 put_tx_header(mailbox, header); 77 put_tx_header(mailbox, header);
78 put_tx_data(mailbox, &buffer[..header.len() as usize]); 78 put_tx_data(mailbox, &buffer[..header.len() as usize]);
@@ -244,12 +244,12 @@ impl Registers {
244 } 244 }
245 245
246 #[inline] 246 #[inline]
247 fn reset_msg_ram(&mut self) { 247 fn reset_msg_ram(&self) {
248 self.msg_ram_mut().reset(); 248 self.msg_ram_mut().reset();
249 } 249 }
250 250
251 #[inline] 251 #[inline]
252 fn enter_init_mode(&mut self) { 252 fn enter_init_mode(&self) {
253 self.regs.cccr().modify(|w| w.set_init(true)); 253 self.regs.cccr().modify(|w| w.set_init(true));
254 while false == self.regs.cccr().read().init() {} 254 while false == self.regs.cccr().read().init() {}
255 self.regs.cccr().modify(|w| w.set_cce(true)); 255 self.regs.cccr().modify(|w| w.set_cce(true));
@@ -258,7 +258,7 @@ impl Registers {
258 /// Enables or disables loopback mode: Internally connects the TX and RX 258 /// Enables or disables loopback mode: Internally connects the TX and RX
259 /// signals together. 259 /// signals together.
260 #[inline] 260 #[inline]
261 fn set_loopback_mode(&mut self, mode: LoopbackMode) { 261 fn set_loopback_mode(&self, mode: LoopbackMode) {
262 let (test, mon, lbck) = match mode { 262 let (test, mon, lbck) = match mode {
263 LoopbackMode::None => (false, false, false), 263 LoopbackMode::None => (false, false, false),
264 LoopbackMode::Internal => (true, true, true), 264 LoopbackMode::Internal => (true, true, true),
@@ -273,34 +273,34 @@ impl Registers {
273 273
274 /// Enables or disables silent mode: Disconnects the TX signal from the pin. 274 /// Enables or disables silent mode: Disconnects the TX signal from the pin.
275 #[inline] 275 #[inline]
276 fn set_bus_monitoring_mode(&mut self, enabled: bool) { 276 fn set_bus_monitoring_mode(&self, enabled: bool) {
277 self.regs.cccr().modify(|w| w.set_mon(enabled)); 277 self.regs.cccr().modify(|w| w.set_mon(enabled));
278 } 278 }
279 279
280 #[inline] 280 #[inline]
281 fn set_restricted_operations(&mut self, enabled: bool) { 281 fn set_restricted_operations(&self, enabled: bool) {
282 self.regs.cccr().modify(|w| w.set_asm(enabled)); 282 self.regs.cccr().modify(|w| w.set_asm(enabled));
283 } 283 }
284 284
285 #[inline] 285 #[inline]
286 fn set_normal_operations(&mut self, _enabled: bool) { 286 fn set_normal_operations(&self, _enabled: bool) {
287 self.set_loopback_mode(LoopbackMode::None); 287 self.set_loopback_mode(LoopbackMode::None);
288 } 288 }
289 289
290 #[inline] 290 #[inline]
291 fn set_test_mode(&mut self, enabled: bool) { 291 fn set_test_mode(&self, enabled: bool) {
292 self.regs.cccr().modify(|w| w.set_test(enabled)); 292 self.regs.cccr().modify(|w| w.set_test(enabled));
293 } 293 }
294 294
295 #[inline] 295 #[inline]
296 fn set_power_down_mode(&mut self, enabled: bool) { 296 fn set_power_down_mode(&self, enabled: bool) {
297 self.regs.cccr().modify(|w| w.set_csr(enabled)); 297 self.regs.cccr().modify(|w| w.set_csr(enabled));
298 while self.regs.cccr().read().csa() != enabled {} 298 while self.regs.cccr().read().csa() != enabled {}
299 } 299 }
300 300
301 /// Moves out of PoweredDownMode and into ConfigMode 301 /// Moves out of PoweredDownMode and into ConfigMode
302 #[inline] 302 #[inline]
303 pub fn into_config_mode(mut self, _config: FdCanConfig) { 303 pub fn into_config_mode(self, _config: FdCanConfig) {
304 self.set_power_down_mode(false); 304 self.set_power_down_mode(false);
305 self.enter_init_mode(); 305 self.enter_init_mode();
306 self.reset_msg_ram(); 306 self.reset_msg_ram();
@@ -327,7 +327,7 @@ impl Registers {
327 327
328 /// Applies the settings of a new FdCanConfig See [`FdCanConfig`] 328 /// Applies the settings of a new FdCanConfig See [`FdCanConfig`]
329 #[inline] 329 #[inline]
330 pub fn apply_config(&mut self, config: FdCanConfig) { 330 pub fn apply_config(&self, config: FdCanConfig) {
331 self.set_tx_buffer_mode(config.tx_buffer_mode); 331 self.set_tx_buffer_mode(config.tx_buffer_mode);
332 332
333 // set standard filters list size to 28 333 // set standard filters list size to 28
@@ -388,7 +388,7 @@ impl Registers {
388 } 388 }
389 389
390 #[inline] 390 #[inline]
391 fn leave_init_mode(&mut self, config: FdCanConfig) { 391 fn leave_init_mode(&self, config: FdCanConfig) {
392 self.apply_config(config); 392 self.apply_config(config);
393 393
394 self.regs.cccr().modify(|w| w.set_cce(false)); 394 self.regs.cccr().modify(|w| w.set_cce(false));
@@ -398,7 +398,7 @@ impl Registers {
398 398
399 /// Moves out of ConfigMode and into specified mode 399 /// Moves out of ConfigMode and into specified mode
400 #[inline] 400 #[inline]
401 pub fn into_mode(mut self, config: FdCanConfig, mode: crate::can::_version::OperatingMode) { 401 pub fn into_mode(&self, config: FdCanConfig, mode: crate::can::_version::OperatingMode) {
402 match mode { 402 match mode {
403 crate::can::OperatingMode::InternalLoopbackMode => self.set_loopback_mode(LoopbackMode::Internal), 403 crate::can::OperatingMode::InternalLoopbackMode => self.set_loopback_mode(LoopbackMode::Internal),
404 crate::can::OperatingMode::ExternalLoopbackMode => self.set_loopback_mode(LoopbackMode::External), 404 crate::can::OperatingMode::ExternalLoopbackMode => self.set_loopback_mode(LoopbackMode::External),
@@ -422,7 +422,7 @@ impl Registers {
422 /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` 422 /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr`
423 /// parameter to this method. 423 /// parameter to this method.
424 #[inline] 424 #[inline]
425 pub fn set_nominal_bit_timing(&mut self, btr: NominalBitTiming) { 425 pub fn set_nominal_bit_timing(&self, btr: NominalBitTiming) {
426 self.regs.nbtp().write(|w| { 426 self.regs.nbtp().write(|w| {
427 w.set_nbrp(btr.nbrp() - 1); 427 w.set_nbrp(btr.nbrp() - 1);
428 w.set_ntseg1(btr.ntseg1() - 1); 428 w.set_ntseg1(btr.ntseg1() - 1);
@@ -434,7 +434,7 @@ impl Registers {
434 /// Configures the data bit timings for the FdCan Variable Bitrates. 434 /// Configures the data bit timings for the FdCan Variable Bitrates.
435 /// This is not used when frame_transmit is set to anything other than AllowFdCanAndBRS. 435 /// This is not used when frame_transmit is set to anything other than AllowFdCanAndBRS.
436 #[inline] 436 #[inline]
437 pub fn set_data_bit_timing(&mut self, btr: DataBitTiming) { 437 pub fn set_data_bit_timing(&self, btr: DataBitTiming) {
438 self.regs.dbtp().write(|w| { 438 self.regs.dbtp().write(|w| {
439 w.set_dbrp(btr.dbrp() - 1); 439 w.set_dbrp(btr.dbrp() - 1);
440 w.set_dtseg1(btr.dtseg1() - 1); 440 w.set_dtseg1(btr.dtseg1() - 1);
@@ -450,39 +450,39 @@ impl Registers {
450 /// 450 ///
451 /// Automatic retransmission is enabled by default. 451 /// Automatic retransmission is enabled by default.
452 #[inline] 452 #[inline]
453 pub fn set_automatic_retransmit(&mut self, enabled: bool) { 453 pub fn set_automatic_retransmit(&self, enabled: bool) {
454 self.regs.cccr().modify(|w| w.set_dar(!enabled)); 454 self.regs.cccr().modify(|w| w.set_dar(!enabled));
455 } 455 }
456 456
457 /// Configures the transmit pause feature. See 457 /// Configures the transmit pause feature. See
458 /// [`FdCanConfig::set_transmit_pause`] 458 /// [`FdCanConfig::set_transmit_pause`]
459 #[inline] 459 #[inline]
460 pub fn set_transmit_pause(&mut self, enabled: bool) { 460 pub fn set_transmit_pause(&self, enabled: bool) {
461 self.regs.cccr().modify(|w| w.set_txp(!enabled)); 461 self.regs.cccr().modify(|w| w.set_txp(!enabled));
462 } 462 }
463 463
464 /// Configures non-iso mode. See [`FdCanConfig::set_non_iso_mode`] 464 /// Configures non-iso mode. See [`FdCanConfig::set_non_iso_mode`]
465 #[inline] 465 #[inline]
466 pub fn set_non_iso_mode(&mut self, enabled: bool) { 466 pub fn set_non_iso_mode(&self, enabled: bool) {
467 self.regs.cccr().modify(|w| w.set_niso(enabled)); 467 self.regs.cccr().modify(|w| w.set_niso(enabled));
468 } 468 }
469 469
470 /// Configures edge filtering. See [`FdCanConfig::set_edge_filtering`] 470 /// Configures edge filtering. See [`FdCanConfig::set_edge_filtering`]
471 #[inline] 471 #[inline]
472 pub fn set_edge_filtering(&mut self, enabled: bool) { 472 pub fn set_edge_filtering(&self, enabled: bool) {
473 self.regs.cccr().modify(|w| w.set_efbi(enabled)); 473 self.regs.cccr().modify(|w| w.set_efbi(enabled));
474 } 474 }
475 475
476 /// Configures TX Buffer Mode 476 /// Configures TX Buffer Mode
477 #[inline] 477 #[inline]
478 pub fn set_tx_buffer_mode(&mut self, tbm: TxBufferMode) { 478 pub fn set_tx_buffer_mode(&self, tbm: TxBufferMode) {
479 self.regs.txbc().write(|w| w.set_tfqm(tbm.into())); 479 self.regs.txbc().write(|w| w.set_tfqm(tbm.into()));
480 } 480 }
481 481
482 /// Configures frame transmission mode. See 482 /// Configures frame transmission mode. See
483 /// [`FdCanConfig::set_frame_transmit`] 483 /// [`FdCanConfig::set_frame_transmit`]
484 #[inline] 484 #[inline]
485 pub fn set_frame_transmit(&mut self, fts: FrameTransmissionConfig) { 485 pub fn set_frame_transmit(&self, fts: FrameTransmissionConfig) {
486 let (fdoe, brse) = match fts { 486 let (fdoe, brse) = match fts {
487 FrameTransmissionConfig::ClassicCanOnly => (false, false), 487 FrameTransmissionConfig::ClassicCanOnly => (false, false),
488 FrameTransmissionConfig::AllowFdCan => (true, false), 488 FrameTransmissionConfig::AllowFdCan => (true, false),
@@ -500,14 +500,14 @@ impl Registers {
500 500
501 /// Sets the protocol exception handling on/off 501 /// Sets the protocol exception handling on/off
502 #[inline] 502 #[inline]
503 pub fn set_protocol_exception_handling(&mut self, enabled: bool) { 503 pub fn set_protocol_exception_handling(&self, enabled: bool) {
504 self.regs.cccr().modify(|w| w.set_pxhd(!enabled)); 504 self.regs.cccr().modify(|w| w.set_pxhd(!enabled));
505 } 505 }
506 506
507 /// Configures and resets the timestamp counter 507 /// Configures and resets the timestamp counter
508 #[inline] 508 #[inline]
509 #[allow(unused)] 509 #[allow(unused)]
510 pub fn set_timestamp_counter_source(&mut self, select: TimestampSource) { 510 pub fn set_timestamp_counter_source(&self, select: TimestampSource) {
511 #[cfg(can_fdcan_h7)] 511 #[cfg(can_fdcan_h7)]
512 let (tcp, tss) = match select { 512 let (tcp, tss) = match select {
513 TimestampSource::None => (0, 0), 513 TimestampSource::None => (0, 0),
@@ -531,7 +531,7 @@ impl Registers {
531 #[cfg(not(can_fdcan_h7))] 531 #[cfg(not(can_fdcan_h7))]
532 /// Configures the global filter settings 532 /// Configures the global filter settings
533 #[inline] 533 #[inline]
534 pub fn set_global_filter(&mut self, filter: GlobalFilter) { 534 pub fn set_global_filter(&self, filter: GlobalFilter) {
535 let anfs = match filter.handle_standard_frames { 535 let anfs = match filter.handle_standard_frames {
536 crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => stm32_metapac::can::vals::Anfs::ACCEPT_FIFO_0, 536 crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => stm32_metapac::can::vals::Anfs::ACCEPT_FIFO_0,
537 crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => stm32_metapac::can::vals::Anfs::ACCEPT_FIFO_1, 537 crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => stm32_metapac::can::vals::Anfs::ACCEPT_FIFO_1,
@@ -554,7 +554,7 @@ impl Registers {
554 #[cfg(can_fdcan_h7)] 554 #[cfg(can_fdcan_h7)]
555 /// Configures the global filter settings 555 /// Configures the global filter settings
556 #[inline] 556 #[inline]
557 pub fn set_global_filter(&mut self, filter: GlobalFilter) { 557 pub fn set_global_filter(&self, filter: GlobalFilter) {
558 let anfs = match filter.handle_standard_frames { 558 let anfs = match filter.handle_standard_frames {
559 crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => 0, 559 crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => 0,
560 crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => 1, 560 crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => 1,
@@ -576,10 +576,10 @@ impl Registers {
576 } 576 }
577 577
578 #[cfg(not(can_fdcan_h7))] 578 #[cfg(not(can_fdcan_h7))]
579 fn configure_msg_ram(&mut self) {} 579 fn configure_msg_ram(&self) {}
580 580
581 #[cfg(can_fdcan_h7)] 581 #[cfg(can_fdcan_h7)]
582 fn configure_msg_ram(&mut self) { 582 fn configure_msg_ram(&self) {
583 let r = self.regs; 583 let r = self.regs;
584 584
585 use crate::can::fd::message_ram::*; 585 use crate::can::fd::message_ram::*;
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index 81ceb06aa..f3ad718ae 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -3,6 +3,7 @@ use core::future::poll_fn;
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4use core::task::Poll; 4use core::task::Poll;
5 5
6use embassy_hal_internal::interrupt::InterruptExt;
6use embassy_hal_internal::{into_ref, PeripheralRef}; 7use embassy_hal_internal::{into_ref, PeripheralRef};
7use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 8use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
8use embassy_sync::channel::{Channel, DynamicReceiver, DynamicSender}; 9use embassy_sync::channel::{Channel, DynamicReceiver, DynamicSender};
@@ -11,7 +12,7 @@ use embassy_sync::waitqueue::AtomicWaker;
11use crate::can::fd::peripheral::Registers; 12use crate::can::fd::peripheral::Registers;
12use crate::gpio::AFType; 13use crate::gpio::AFType;
13use crate::interrupt::typelevel::Interrupt; 14use crate::interrupt::typelevel::Interrupt;
14use crate::rcc::RccPeripheral; 15use crate::rcc::{self, RccPeripheral};
15use crate::{interrupt, peripherals, Peripheral}; 16use crate::{interrupt, peripherals, Peripheral};
16 17
17pub(crate) mod fd; 18pub(crate) mod fd;
@@ -40,7 +41,7 @@ pub struct IT0InterruptHandler<T: Instance> {
40// We use IT0 for everything currently 41// We use IT0 for everything currently
41impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0InterruptHandler<T> { 42impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0InterruptHandler<T> {
42 unsafe fn on_interrupt() { 43 unsafe fn on_interrupt() {
43 let regs = T::regs(); 44 let regs = T::registers().regs;
44 45
45 let ir = regs.ir().read(); 46 let ir = regs.ir().read();
46 47
@@ -140,22 +141,16 @@ pub enum OperatingMode {
140 //TestMode, 141 //TestMode,
141} 142}
142 143
143/// FDCAN Configuration instance instance 144fn calc_ns_per_timer_tick(
144/// Create instance of this first 145 info: &'static Info,
145pub struct CanConfigurator<'d, T: Instance> { 146 freq: crate::time::Hertz,
146 config: crate::can::fd::config::FdCanConfig, 147 mode: crate::can::fd::config::FrameTransmissionConfig,
147 /// Reference to internals. 148) -> u64 {
148 instance: FdcanInstance<'d, T>,
149 properties: Properties<T>,
150}
151
152fn calc_ns_per_timer_tick<T: Instance>(mode: crate::can::fd::config::FrameTransmissionConfig) -> u64 {
153 match mode { 149 match mode {
154 // Use timestamp from Rx FIFO to adjust timestamp reported to user 150 // Use timestamp from Rx FIFO to adjust timestamp reported to user
155 crate::can::fd::config::FrameTransmissionConfig::ClassicCanOnly => { 151 crate::can::fd::config::FrameTransmissionConfig::ClassicCanOnly => {
156 let freq = T::frequency(); 152 let prescale: u64 = ({ info.regs.regs.nbtp().read().nbrp() } + 1) as u64
157 let prescale: u64 = 153 * ({ info.regs.regs.tscc().read().tcp() } + 1) as u64;
158 ({ T::regs().nbtp().read().nbrp() } + 1) as u64 * ({ T::regs().tscc().read().tcp() } + 1) as u64;
159 1_000_000_000 as u64 / (freq.0 as u64 * prescale) 154 1_000_000_000 as u64 / (freq.0 as u64 * prescale)
160 } 155 }
161 // For VBR this is too hard because the FDCAN timer switches clock rate you need to configure to use 156 // For VBR this is too hard because the FDCAN timer switches clock rate you need to configure to use
@@ -164,23 +159,35 @@ fn calc_ns_per_timer_tick<T: Instance>(mode: crate::can::fd::config::FrameTransm
164 } 159 }
165} 160}
166 161
167impl<'d, T: Instance> CanConfigurator<'d, T> { 162/// FDCAN Configuration instance instance
163/// Create instance of this first
164pub struct CanConfigurator<'d> {
165 _phantom: PhantomData<&'d ()>,
166 config: crate::can::fd::config::FdCanConfig,
167 info: &'static Info,
168 state: &'static State,
169 /// Reference to internals.
170 properties: Properties,
171 periph_clock: crate::time::Hertz,
172}
173
174impl<'d> CanConfigurator<'d> {
168 /// Creates a new Fdcan instance, keeping the peripheral in sleep mode. 175 /// Creates a new Fdcan instance, keeping the peripheral in sleep mode.
169 /// You must call [Fdcan::enable_non_blocking] to use the peripheral. 176 /// You must call [Fdcan::enable_non_blocking] to use the peripheral.
170 pub fn new( 177 pub fn new<T: Instance>(
171 peri: impl Peripheral<P = T> + 'd, 178 _peri: impl Peripheral<P = T> + 'd,
172 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 179 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
173 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 180 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
174 _irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>> 181 _irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>>
175 + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>> 182 + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>>
176 + 'd, 183 + 'd,
177 ) -> CanConfigurator<'d, T> { 184 ) -> CanConfigurator<'d> {
178 into_ref!(peri, rx, tx); 185 into_ref!(_peri, rx, tx);
179 186
180 rx.set_as_af(rx.af_num(), AFType::Input); 187 rx.set_as_af(rx.af_num(), AFType::Input);
181 tx.set_as_af(tx.af_num(), AFType::OutputPushPull); 188 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
182 189
183 T::enable_and_reset(); 190 rcc::enable_and_reset::<T>();
184 191
185 let mut config = crate::can::fd::config::FdCanConfig::default(); 192 let mut config = crate::can::fd::config::FdCanConfig::default();
186 config.timestamp_source = TimestampSource::Prescaler(TimestampPrescaler::_1); 193 config.timestamp_source = TimestampSource::Prescaler(TimestampPrescaler::_1);
@@ -196,16 +203,18 @@ impl<'d, T: Instance> CanConfigurator<'d, T> {
196 T::IT1Interrupt::unpend(); // Not unsafe 203 T::IT1Interrupt::unpend(); // Not unsafe
197 T::IT1Interrupt::enable(); 204 T::IT1Interrupt::enable();
198 } 205 }
199
200 Self { 206 Self {
207 _phantom: PhantomData,
201 config, 208 config,
202 instance: FdcanInstance(peri), 209 info: T::info(),
203 properties: Properties::new(), 210 state: T::state(),
211 properties: Properties::new(T::info()),
212 periph_clock: T::frequency(),
204 } 213 }
205 } 214 }
206 215
207 /// Get driver properties 216 /// Get driver properties
208 pub fn properties(&self) -> &Properties<T> { 217 pub fn properties(&self) -> &Properties {
209 &self.properties 218 &self.properties
210 } 219 }
211 220
@@ -221,7 +230,7 @@ impl<'d, T: Instance> CanConfigurator<'d, T> {
221 230
222 /// Configures the bit timings calculated from supplied bitrate. 231 /// Configures the bit timings calculated from supplied bitrate.
223 pub fn set_bitrate(&mut self, bitrate: u32) { 232 pub fn set_bitrate(&mut self, bitrate: u32) {
224 let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); 233 let bit_timing = util::calc_can_timings(self.periph_clock, bitrate).unwrap();
225 234
226 let nbtr = crate::can::fd::config::NominalBitTiming { 235 let nbtr = crate::can::fd::config::NominalBitTiming {
227 sync_jump_width: bit_timing.sync_jump_width, 236 sync_jump_width: bit_timing.sync_jump_width,
@@ -234,7 +243,7 @@ impl<'d, T: Instance> CanConfigurator<'d, T> {
234 243
235 /// Configures the bit timings for VBR data calculated from supplied bitrate. This also sets confit to allow can FD and VBR 244 /// Configures the bit timings for VBR data calculated from supplied bitrate. This also sets confit to allow can FD and VBR
236 pub fn set_fd_data_bitrate(&mut self, bitrate: u32, transceiver_delay_compensation: bool) { 245 pub fn set_fd_data_bitrate(&mut self, bitrate: u32, transceiver_delay_compensation: bool) {
237 let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap(); 246 let bit_timing = util::calc_can_timings(self.periph_clock, bitrate).unwrap();
238 // Note, used existing calcluation for normal(non-VBR) bitrate, appears to work for 250k/1M 247 // Note, used existing calcluation for normal(non-VBR) bitrate, appears to work for 250k/1M
239 let nbtr = crate::can::fd::config::DataBitTiming { 248 let nbtr = crate::can::fd::config::DataBitTiming {
240 transceiver_delay_compensation, 249 transceiver_delay_compensation,
@@ -248,62 +257,68 @@ impl<'d, T: Instance> CanConfigurator<'d, T> {
248 } 257 }
249 258
250 /// Start in mode. 259 /// Start in mode.
251 pub fn start(self, mode: OperatingMode) -> Can<'d, T> { 260 pub fn start(self, mode: OperatingMode) -> Can<'d> {
252 let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.config.frame_transmit); 261 let ns_per_timer_tick = calc_ns_per_timer_tick(self.info, self.periph_clock, self.config.frame_transmit);
253 critical_section::with(|_| unsafe { 262 critical_section::with(|_| {
254 T::mut_state().ns_per_timer_tick = ns_per_timer_tick; 263 let state = self.state as *const State;
264 unsafe {
265 let mut_state = state as *mut State;
266 (*mut_state).ns_per_timer_tick = ns_per_timer_tick;
267 }
255 }); 268 });
256 T::registers().into_mode(self.config, mode); 269 self.info.regs.into_mode(self.config, mode);
257 let ret = Can { 270 Can {
271 _phantom: PhantomData,
258 config: self.config, 272 config: self.config,
259 instance: self.instance, 273 info: self.info,
274 state: self.state,
260 _mode: mode, 275 _mode: mode,
261 properties: self.properties, 276 properties: Properties::new(self.info),
262 }; 277 }
263 ret
264 } 278 }
265 279
266 /// Start, entering mode. Does same as start(mode) 280 /// Start, entering mode. Does same as start(mode)
267 pub fn into_normal_mode(self) -> Can<'d, T> { 281 pub fn into_normal_mode(self) -> Can<'d> {
268 self.start(OperatingMode::NormalOperationMode) 282 self.start(OperatingMode::NormalOperationMode)
269 } 283 }
270 284
271 /// Start, entering mode. Does same as start(mode) 285 /// Start, entering mode. Does same as start(mode)
272 pub fn into_internal_loopback_mode(self) -> Can<'d, T> { 286 pub fn into_internal_loopback_mode(self) -> Can<'d> {
273 self.start(OperatingMode::InternalLoopbackMode) 287 self.start(OperatingMode::InternalLoopbackMode)
274 } 288 }
275 289
276 /// Start, entering mode. Does same as start(mode) 290 /// Start, entering mode. Does same as start(mode)
277 pub fn into_external_loopback_mode(self) -> Can<'d, T> { 291 pub fn into_external_loopback_mode(self) -> Can<'d> {
278 self.start(OperatingMode::ExternalLoopbackMode) 292 self.start(OperatingMode::ExternalLoopbackMode)
279 } 293 }
280} 294}
281 295
282/// FDCAN Instance 296/// FDCAN Instance
283pub struct Can<'d, T: Instance> { 297pub struct Can<'d> {
298 _phantom: PhantomData<&'d ()>,
284 config: crate::can::fd::config::FdCanConfig, 299 config: crate::can::fd::config::FdCanConfig,
285 /// Reference to internals. 300 info: &'static Info,
286 instance: FdcanInstance<'d, T>, 301 state: &'static State,
287 _mode: OperatingMode, 302 _mode: OperatingMode,
288 properties: Properties<T>, 303 properties: Properties,
289} 304}
290 305
291impl<'d, T: Instance> Can<'d, T> { 306impl<'d> Can<'d> {
292 /// Get driver properties 307 /// Get driver properties
293 pub fn properties(&self) -> &Properties<T> { 308 pub fn properties(&self) -> &Properties {
294 &self.properties 309 &self.properties
295 } 310 }
296 311
297 /// Flush one of the TX mailboxes. 312 /// Flush one of the TX mailboxes.
298 pub async fn flush(&self, idx: usize) { 313 pub async fn flush(&self, idx: usize) {
299 poll_fn(|cx| { 314 poll_fn(|cx| {
300 T::state().tx_mode.register(cx.waker()); 315 self.state.tx_mode.register(cx.waker());
301 316
302 if idx > 3 { 317 if idx > 3 {
303 panic!("Bad mailbox"); 318 panic!("Bad mailbox");
304 } 319 }
305 let idx = 1 << idx; 320 let idx = 1 << idx;
306 if !T::regs().txbrp().read().trp(idx) { 321 if !self.info.regs.regs.txbrp().read().trp(idx) {
307 return Poll::Ready(()); 322 return Poll::Ready(());
308 } 323 }
309 324
@@ -317,12 +332,12 @@ impl<'d, T: Instance> Can<'d, T> {
317 /// can be replaced, this call asynchronously waits for a frame to be successfully 332 /// can be replaced, this call asynchronously waits for a frame to be successfully
318 /// transmitted, then tries again. 333 /// transmitted, then tries again.
319 pub async fn write(&mut self, frame: &Frame) -> Option<Frame> { 334 pub async fn write(&mut self, frame: &Frame) -> Option<Frame> {
320 T::state().tx_mode.write::<T>(frame).await 335 self.state.tx_mode.write(self.info, frame).await
321 } 336 }
322 337
323 /// Returns the next received message frame 338 /// Returns the next received message frame
324 pub async fn read(&mut self) -> Result<Envelope, BusError> { 339 pub async fn read(&mut self) -> Result<Envelope, BusError> {
325 T::state().rx_mode.read_classic::<T>().await 340 self.state.rx_mode.read_classic(self.info, self.state).await
326 } 341 }
327 342
328 /// Queues the message to be sent but exerts backpressure. If a lower-priority 343 /// Queues the message to be sent but exerts backpressure. If a lower-priority
@@ -330,58 +345,61 @@ impl<'d, T: Instance> Can<'d, T> {
330 /// can be replaced, this call asynchronously waits for a frame to be successfully 345 /// can be replaced, this call asynchronously waits for a frame to be successfully
331 /// transmitted, then tries again. 346 /// transmitted, then tries again.
332 pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> { 347 pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> {
333 T::state().tx_mode.write_fd::<T>(frame).await 348 self.state.tx_mode.write_fd(self.info, frame).await
334 } 349 }
335 350
336 /// Returns the next received message frame 351 /// Returns the next received message frame
337 pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> { 352 pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> {
338 T::state().rx_mode.read_fd::<T>().await 353 self.state.rx_mode.read_fd(self.info, self.state).await
339 } 354 }
340 355
341 /// Split instance into separate portions: Tx(write), Rx(read), common properties 356 /// Split instance into separate portions: Tx(write), Rx(read), common properties
342 pub fn split(self) -> (CanTx<'d, T>, CanRx<'d, T>, Properties<T>) { 357 pub fn split(self) -> (CanTx<'d>, CanRx<'d>, Properties) {
343 ( 358 (
344 CanTx { 359 CanTx {
360 _phantom: PhantomData,
361 info: self.info,
362 state: self.state,
345 config: self.config, 363 config: self.config,
346 _instance: self.instance,
347 _mode: self._mode, 364 _mode: self._mode,
348 }, 365 },
349 CanRx { 366 CanRx {
350 _instance1: PhantomData::<T>, 367 _phantom: PhantomData,
351 _instance2: T::regs(), 368 info: self.info,
369 state: self.state,
352 _mode: self._mode, 370 _mode: self._mode,
353 }, 371 },
354 self.properties, 372 self.properties,
355 ) 373 )
356 } 374 }
357
358 /// Join split rx and tx portions back together 375 /// Join split rx and tx portions back together
359 pub fn join(tx: CanTx<'d, T>, rx: CanRx<'d, T>) -> Self { 376 pub fn join(tx: CanTx<'d>, rx: CanRx<'d>) -> Self {
360 Can { 377 Can {
378 _phantom: PhantomData,
361 config: tx.config, 379 config: tx.config,
362 //_instance2: T::regs(), 380 info: tx.info,
363 instance: tx._instance, 381 state: tx.state,
364 _mode: rx._mode, 382 _mode: rx._mode,
365 properties: Properties::new(), 383 properties: Properties::new(tx.info),
366 } 384 }
367 } 385 }
368 386
369 /// Return a buffered instance of driver without CAN FD support. User must supply Buffers 387 /// Return a buffered instance of driver without CAN FD support. User must supply Buffers
370 pub fn buffered<const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>( 388 pub fn buffered<const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>(
371 &self, 389 self,
372 tx_buf: &'static mut TxBuf<TX_BUF_SIZE>, 390 tx_buf: &'static mut TxBuf<TX_BUF_SIZE>,
373 rxb: &'static mut RxBuf<RX_BUF_SIZE>, 391 rxb: &'static mut RxBuf<RX_BUF_SIZE>,
374 ) -> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { 392 ) -> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
375 BufferedCan::new(PhantomData::<T>, T::regs(), self._mode, tx_buf, rxb) 393 BufferedCan::new(self.info, self.state, self._mode, tx_buf, rxb)
376 } 394 }
377 395
378 /// Return a buffered instance of driver with CAN FD support. User must supply Buffers 396 /// Return a buffered instance of driver with CAN FD support. User must supply Buffers
379 pub fn buffered_fd<const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>( 397 pub fn buffered_fd<const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>(
380 &self, 398 self,
381 tx_buf: &'static mut TxFdBuf<TX_BUF_SIZE>, 399 tx_buf: &'static mut TxFdBuf<TX_BUF_SIZE>,
382 rxb: &'static mut RxFdBuf<RX_BUF_SIZE>, 400 rxb: &'static mut RxFdBuf<RX_BUF_SIZE>,
383 ) -> BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { 401 ) -> BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
384 BufferedCanFd::new(PhantomData::<T>, T::regs(), self._mode, tx_buf, rxb) 402 BufferedCanFd::new(self.info, self.state, self._mode, tx_buf, rxb)
385 } 403 }
386} 404}
387 405
@@ -392,52 +410,56 @@ pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<
392pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>; 410pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>;
393 411
394/// Buffered FDCAN Instance 412/// Buffered FDCAN Instance
395pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { 413pub struct BufferedCan<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
396 _instance1: PhantomData<T>, 414 _phantom: PhantomData<&'d ()>,
397 _instance2: &'d crate::pac::can::Fdcan, 415 info: &'static Info,
416 state: &'static State,
398 _mode: OperatingMode, 417 _mode: OperatingMode,
399 tx_buf: &'static TxBuf<TX_BUF_SIZE>, 418 tx_buf: &'static TxBuf<TX_BUF_SIZE>,
400 rx_buf: &'static RxBuf<RX_BUF_SIZE>, 419 rx_buf: &'static RxBuf<RX_BUF_SIZE>,
401 properties: Properties<T>, 420 properties: Properties,
402} 421}
403 422
404impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> 423impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
405 BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE>
406{
407 fn new( 424 fn new(
408 _instance1: PhantomData<T>, 425 info: &'static Info,
409 _instance2: &'d crate::pac::can::Fdcan, 426 state: &'static State,
410 _mode: OperatingMode, 427 _mode: OperatingMode,
411 tx_buf: &'static TxBuf<TX_BUF_SIZE>, 428 tx_buf: &'static TxBuf<TX_BUF_SIZE>,
412 rx_buf: &'static RxBuf<RX_BUF_SIZE>, 429 rx_buf: &'static RxBuf<RX_BUF_SIZE>,
413 ) -> Self { 430 ) -> Self {
414 BufferedCan { 431 BufferedCan {
415 _instance1, 432 _phantom: PhantomData,
416 _instance2, 433 info,
434 state,
417 _mode, 435 _mode,
418 tx_buf, 436 tx_buf,
419 rx_buf, 437 rx_buf,
420 properties: Properties::new(), 438 properties: Properties::new(info),
421 } 439 }
422 .setup() 440 .setup()
423 } 441 }
424 442
425 /// Get driver properties 443 /// Get driver properties
426 pub fn properties(&self) -> &Properties<T> { 444 pub fn properties(&self) -> &Properties {
427 &self.properties 445 &self.properties
428 } 446 }
429 447
430 fn setup(self) -> Self { 448 fn setup(self) -> Self {
431 // We don't want interrupts being processed while we change modes. 449 // We don't want interrupts being processed while we change modes.
432 critical_section::with(|_| unsafe { 450 critical_section::with(|_| {
433 let rx_inner = super::common::ClassicBufferedRxInner { 451 let rx_inner = super::common::ClassicBufferedRxInner {
434 rx_sender: self.rx_buf.sender().into(), 452 rx_sender: self.rx_buf.sender().into(),
435 }; 453 };
436 let tx_inner = super::common::ClassicBufferedTxInner { 454 let tx_inner = super::common::ClassicBufferedTxInner {
437 tx_receiver: self.tx_buf.receiver().into(), 455 tx_receiver: self.tx_buf.receiver().into(),
438 }; 456 };
439 T::mut_state().rx_mode = RxMode::ClassicBuffered(rx_inner); 457 let state = self.state as *const State;
440 T::mut_state().tx_mode = TxMode::ClassicBuffered(tx_inner); 458 unsafe {
459 let mut_state = state as *mut State;
460 (*mut_state).rx_mode = RxMode::ClassicBuffered(rx_inner);
461 (*mut_state).tx_mode = TxMode::ClassicBuffered(tx_inner);
462 }
441 }); 463 });
442 self 464 self
443 } 465 }
@@ -445,7 +467,8 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
445 /// Async write frame to TX buffer. 467 /// Async write frame to TX buffer.
446 pub async fn write(&mut self, frame: Frame) { 468 pub async fn write(&mut self, frame: Frame) {
447 self.tx_buf.send(frame).await; 469 self.tx_buf.send(frame).await;
448 T::IT0Interrupt::pend(); // Wake for Tx 470 self.info.interrupt0.pend(); // Wake for Tx
471 //T::IT0Interrupt::pend(); // Wake for Tx
449 } 472 }
450 473
451 /// Async read frame from RX buffer. 474 /// Async read frame from RX buffer.
@@ -457,7 +480,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
457 pub fn writer(&self) -> BufferedCanSender { 480 pub fn writer(&self) -> BufferedCanSender {
458 BufferedCanSender { 481 BufferedCanSender {
459 tx_buf: self.tx_buf.sender().into(), 482 tx_buf: self.tx_buf.sender().into(),
460 waker: T::IT0Interrupt::pend, 483 waker: self.info.tx_waker,
461 } 484 }
462 } 485 }
463 486
@@ -467,13 +490,15 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
467 } 490 }
468} 491}
469 492
470impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop 493impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop for BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
471 for BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE>
472{
473 fn drop(&mut self) { 494 fn drop(&mut self) {
474 critical_section::with(|_| unsafe { 495 critical_section::with(|_| {
475 T::mut_state().rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); 496 let state = self.state as *const State;
476 T::mut_state().tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); 497 unsafe {
498 let mut_state = state as *mut State;
499 (*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
500 (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
501 }
477 }); 502 });
478 } 503 }
479} 504}
@@ -484,16 +509,6 @@ pub type RxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Resul
484/// User supplied buffer for TX buffering 509/// User supplied buffer for TX buffering
485pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFrame, BUF_SIZE>; 510pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFrame, BUF_SIZE>;
486 511
487/// Buffered FDCAN Instance
488pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
489 _instance1: PhantomData<T>,
490 _instance2: &'d crate::pac::can::Fdcan,
491 _mode: OperatingMode,
492 tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
493 rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
494 properties: Properties<T>,
495}
496
497/// Sender that can be used for sending CAN frames. 512/// Sender that can be used for sending CAN frames.
498#[derive(Copy, Clone)] 513#[derive(Copy, Clone)]
499pub struct BufferedFdCanSender { 514pub struct BufferedFdCanSender {
@@ -524,43 +539,57 @@ impl BufferedFdCanSender {
524/// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver. 539/// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
525pub type BufferedFdCanReceiver = DynamicReceiver<'static, Result<FdEnvelope, BusError>>; 540pub type BufferedFdCanReceiver = DynamicReceiver<'static, Result<FdEnvelope, BusError>>;
526 541
527impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> 542/// Buffered FDCAN Instance
528 BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> 543pub struct BufferedCanFd<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
529{ 544 _phantom: PhantomData<&'d ()>,
545 info: &'static Info,
546 state: &'static State,
547 _mode: OperatingMode,
548 tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
549 rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
550 properties: Properties,
551}
552
553impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
530 fn new( 554 fn new(
531 _instance1: PhantomData<T>, 555 info: &'static Info,
532 _instance2: &'d crate::pac::can::Fdcan, 556 state: &'static State,
533 _mode: OperatingMode, 557 _mode: OperatingMode,
534 tx_buf: &'static TxFdBuf<TX_BUF_SIZE>, 558 tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
535 rx_buf: &'static RxFdBuf<RX_BUF_SIZE>, 559 rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
536 ) -> Self { 560 ) -> Self {
537 BufferedCanFd { 561 BufferedCanFd {
538 _instance1, 562 _phantom: PhantomData,
539 _instance2, 563 info,
564 state,
540 _mode, 565 _mode,
541 tx_buf, 566 tx_buf,
542 rx_buf, 567 rx_buf,
543 properties: Properties::new(), 568 properties: Properties::new(info),
544 } 569 }
545 .setup() 570 .setup()
546 } 571 }
547 572
548 /// Get driver properties 573 /// Get driver properties
549 pub fn properties(&self) -> &Properties<T> { 574 pub fn properties(&self) -> &Properties {
550 &self.properties 575 &self.properties
551 } 576 }
552 577
553 fn setup(self) -> Self { 578 fn setup(self) -> Self {
554 // We don't want interrupts being processed while we change modes. 579 // We don't want interrupts being processed while we change modes.
555 critical_section::with(|_| unsafe { 580 critical_section::with(|_| {
556 let rx_inner = super::common::FdBufferedRxInner { 581 let rx_inner = super::common::FdBufferedRxInner {
557 rx_sender: self.rx_buf.sender().into(), 582 rx_sender: self.rx_buf.sender().into(),
558 }; 583 };
559 let tx_inner = super::common::FdBufferedTxInner { 584 let tx_inner = super::common::FdBufferedTxInner {
560 tx_receiver: self.tx_buf.receiver().into(), 585 tx_receiver: self.tx_buf.receiver().into(),
561 }; 586 };
562 T::mut_state().rx_mode = RxMode::FdBuffered(rx_inner); 587 let state = self.state as *const State;
563 T::mut_state().tx_mode = TxMode::FdBuffered(tx_inner); 588 unsafe {
589 let mut_state = state as *mut State;
590 (*mut_state).rx_mode = RxMode::FdBuffered(rx_inner);
591 (*mut_state).tx_mode = TxMode::FdBuffered(tx_inner);
592 }
564 }); 593 });
565 self 594 self
566 } 595 }
@@ -568,7 +597,8 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
568 /// Async write frame to TX buffer. 597 /// Async write frame to TX buffer.
569 pub async fn write(&mut self, frame: FdFrame) { 598 pub async fn write(&mut self, frame: FdFrame) {
570 self.tx_buf.send(frame).await; 599 self.tx_buf.send(frame).await;
571 T::IT0Interrupt::pend(); // Wake for Tx 600 self.info.interrupt0.pend(); // Wake for Tx
601 //T::IT0Interrupt::pend(); // Wake for Tx
572 } 602 }
573 603
574 /// Async read frame from RX buffer. 604 /// Async read frame from RX buffer.
@@ -580,7 +610,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
580 pub fn writer(&self) -> BufferedFdCanSender { 610 pub fn writer(&self) -> BufferedFdCanSender {
581 BufferedFdCanSender { 611 BufferedFdCanSender {
582 tx_buf: self.tx_buf.sender().into(), 612 tx_buf: self.tx_buf.sender().into(),
583 waker: T::IT0Interrupt::pend, 613 waker: self.info.tx_waker,
584 } 614 }
585 } 615 }
586 616
@@ -590,38 +620,55 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
590 } 620 }
591} 621}
592 622
593impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop 623impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop for BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
594 for BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE>
595{
596 fn drop(&mut self) { 624 fn drop(&mut self) {
597 critical_section::with(|_| unsafe { 625 critical_section::with(|_| {
598 T::mut_state().rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); 626 let state = self.state as *const State;
599 T::mut_state().tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new()); 627 unsafe {
628 let mut_state = state as *mut State;
629 (*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
630 (*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
631 }
600 }); 632 });
601 } 633 }
602} 634}
603 635
604/// FDCAN Rx only Instance 636/// FDCAN Rx only Instance
605pub struct CanRx<'d, T: Instance> { 637pub struct CanRx<'d> {
606 _instance1: PhantomData<T>, 638 _phantom: PhantomData<&'d ()>,
607 _instance2: &'d crate::pac::can::Fdcan, 639 info: &'static Info,
640 state: &'static State,
608 _mode: OperatingMode, 641 _mode: OperatingMode,
609} 642}
610 643
644impl<'d> CanRx<'d> {
645 /// Returns the next received message frame
646 pub async fn read(&mut self) -> Result<Envelope, BusError> {
647 self.state.rx_mode.read_classic(&self.info, &self.state).await
648 }
649
650 /// Returns the next received message frame
651 pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> {
652 self.state.rx_mode.read_fd(&self.info, &self.state).await
653 }
654}
655
611/// FDCAN Tx only Instance 656/// FDCAN Tx only Instance
612pub struct CanTx<'d, T: Instance> { 657pub struct CanTx<'d> {
658 _phantom: PhantomData<&'d ()>,
659 info: &'static Info,
660 state: &'static State,
613 config: crate::can::fd::config::FdCanConfig, 661 config: crate::can::fd::config::FdCanConfig,
614 _instance: FdcanInstance<'d, T>, //(PeripheralRef<'a, T>);
615 _mode: OperatingMode, 662 _mode: OperatingMode,
616} 663}
617 664
618impl<'c, 'd, T: Instance> CanTx<'d, T> { 665impl<'c, 'd> CanTx<'d> {
619 /// Queues the message to be sent but exerts backpressure. If a lower-priority 666 /// Queues the message to be sent but exerts backpressure. If a lower-priority
620 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames 667 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames
621 /// can be replaced, this call asynchronously waits for a frame to be successfully 668 /// can be replaced, this call asynchronously waits for a frame to be successfully
622 /// transmitted, then tries again. 669 /// transmitted, then tries again.
623 pub async fn write(&mut self, frame: &Frame) -> Option<Frame> { 670 pub async fn write(&mut self, frame: &Frame) -> Option<Frame> {
624 T::state().tx_mode.write::<T>(frame).await 671 self.state.tx_mode.write(self.info, frame).await
625 } 672 }
626 673
627 /// Queues the message to be sent but exerts backpressure. If a lower-priority 674 /// Queues the message to be sent but exerts backpressure. If a lower-priority
@@ -629,19 +676,7 @@ impl<'c, 'd, T: Instance> CanTx<'d, T> {
629 /// can be replaced, this call asynchronously waits for a frame to be successfully 676 /// can be replaced, this call asynchronously waits for a frame to be successfully
630 /// transmitted, then tries again. 677 /// transmitted, then tries again.
631 pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> { 678 pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> {
632 T::state().tx_mode.write_fd::<T>(frame).await 679 self.state.tx_mode.write_fd(self.info, frame).await
633 }
634}
635
636impl<'c, 'd, T: Instance> CanRx<'d, T> {
637 /// Returns the next received message frame
638 pub async fn read(&mut self) -> Result<Envelope, BusError> {
639 T::state().rx_mode.read_classic::<T>().await
640 }
641
642 /// Returns the next received message frame
643 pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> {
644 T::state().rx_mode.read_fd::<T>().await
645 } 680 }
646} 681}
647 682
@@ -662,7 +697,7 @@ impl RxMode {
662 } 697 }
663 698
664 fn on_interrupt<T: Instance>(&self, fifonr: usize) { 699 fn on_interrupt<T: Instance>(&self, fifonr: usize) {
665 T::regs().ir().write(|w| w.set_rfn(fifonr, true)); 700 T::registers().regs.ir().write(|w| w.set_rfn(fifonr, true));
666 match self { 701 match self {
667 RxMode::NonBuffered(waker) => { 702 RxMode::NonBuffered(waker) => {
668 waker.wake(); 703 waker.wake();
@@ -696,7 +731,6 @@ impl RxMode {
696 } 731 }
697 } 732 }
698 733
699 //async fn read_classic<T: Instance>(&self) -> Result<Envelope, BusError> {
700 fn try_read_fd<T: Instance>(&self) -> Option<Result<FdEnvelope, BusError>> { 734 fn try_read_fd<T: Instance>(&self) -> Option<Result<FdEnvelope, BusError>> {
701 if let Some((frame, ts)) = T::registers().read(0) { 735 if let Some((frame, ts)) = T::registers().read(0) {
702 let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); 736 let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
@@ -712,14 +746,18 @@ impl RxMode {
712 } 746 }
713 } 747 }
714 748
715 fn read<T: Instance, F: CanHeader>(&self) -> Option<Result<(F, Timestamp), BusError>> { 749 fn read<F: CanHeader>(
716 if let Some((msg, ts)) = T::registers().read(0) { 750 &self,
717 let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); 751 info: &'static Info,
752 state: &'static State,
753 ) -> Option<Result<(F, Timestamp), BusError>> {
754 if let Some((msg, ts)) = info.regs.read(0) {
755 let ts = info.calc_timestamp(state.ns_per_timer_tick, ts);
718 Some(Ok((msg, ts))) 756 Some(Ok((msg, ts)))
719 } else if let Some((msg, ts)) = T::registers().read(1) { 757 } else if let Some((msg, ts)) = info.regs.read(1) {
720 let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts); 758 let ts = info.calc_timestamp(state.ns_per_timer_tick, ts);
721 Some(Ok((msg, ts))) 759 Some(Ok((msg, ts)))
722 } else if let Some(err) = T::registers().curr_error() { 760 } else if let Some(err) = info.regs.curr_error() {
723 // TODO: this is probably wrong 761 // TODO: this is probably wrong
724 Some(Err(err)) 762 Some(Err(err))
725 } else { 763 } else {
@@ -727,11 +765,16 @@ impl RxMode {
727 } 765 }
728 } 766 }
729 767
730 async fn read_async<T: Instance, F: CanHeader>(&self) -> Result<(F, Timestamp), BusError> { 768 async fn read_async<F: CanHeader>(
731 poll_fn(|cx| { 769 &self,
732 T::state().err_waker.register(cx.waker()); 770 info: &'static Info,
771 state: &'static State,
772 ) -> Result<(F, Timestamp), BusError> {
773 //let _ = self.read::<F>(info, state);
774 poll_fn(move |cx| {
775 state.err_waker.register(cx.waker());
733 self.register(cx.waker()); 776 self.register(cx.waker());
734 match self.read::<T, _>() { 777 match self.read::<_>(info, state) {
735 Some(result) => Poll::Ready(result), 778 Some(result) => Poll::Ready(result),
736 None => Poll::Pending, 779 None => Poll::Pending,
737 } 780 }
@@ -739,15 +782,15 @@ impl RxMode {
739 .await 782 .await
740 } 783 }
741 784
742 async fn read_classic<T: Instance>(&self) -> Result<Envelope, BusError> { 785 async fn read_classic(&self, info: &'static Info, state: &'static State) -> Result<Envelope, BusError> {
743 match self.read_async::<T, _>().await { 786 match self.read_async::<_>(info, state).await {
744 Ok((frame, ts)) => Ok(Envelope { ts, frame }), 787 Ok((frame, ts)) => Ok(Envelope { ts, frame }),
745 Err(e) => Err(e), 788 Err(e) => Err(e),
746 } 789 }
747 } 790 }
748 791
749 async fn read_fd<T: Instance>(&self) -> Result<FdEnvelope, BusError> { 792 async fn read_fd(&self, info: &'static Info, state: &'static State) -> Result<FdEnvelope, BusError> {
750 match self.read_async::<T, _>().await { 793 match self.read_async::<_>(info, state).await {
751 Ok((frame, ts)) => Ok(FdEnvelope { ts, frame }), 794 Ok((frame, ts)) => Ok(FdEnvelope { ts, frame }),
752 Err(e) => Err(e), 795 Err(e) => Err(e),
753 } 796 }
@@ -776,11 +819,11 @@ impl TxMode {
776 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames 819 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames
777 /// can be replaced, this call asynchronously waits for a frame to be successfully 820 /// can be replaced, this call asynchronously waits for a frame to be successfully
778 /// transmitted, then tries again. 821 /// transmitted, then tries again.
779 async fn write_generic<T: Instance, F: embedded_can::Frame + CanHeader>(&self, frame: &F) -> Option<F> { 822 async fn write_generic<F: embedded_can::Frame + CanHeader>(&self, info: &'static Info, frame: &F) -> Option<F> {
780 poll_fn(|cx| { 823 poll_fn(|cx| {
781 self.register(cx.waker()); 824 self.register(cx.waker());
782 825
783 if let Ok(dropped) = T::registers().write(frame) { 826 if let Ok(dropped) = info.regs.write(frame) {
784 return Poll::Ready(dropped); 827 return Poll::Ready(dropped);
785 } 828 }
786 829
@@ -795,68 +838,70 @@ impl TxMode {
795 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames 838 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames
796 /// can be replaced, this call asynchronously waits for a frame to be successfully 839 /// can be replaced, this call asynchronously waits for a frame to be successfully
797 /// transmitted, then tries again. 840 /// transmitted, then tries again.
798 async fn write<T: Instance>(&self, frame: &Frame) -> Option<Frame> { 841 async fn write(&self, info: &'static Info, frame: &Frame) -> Option<Frame> {
799 self.write_generic::<T, _>(frame).await 842 self.write_generic::<_>(info, frame).await
800 } 843 }
801 844
802 /// Queues the message to be sent but exerts backpressure. If a lower-priority 845 /// Queues the message to be sent but exerts backpressure. If a lower-priority
803 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames 846 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames
804 /// can be replaced, this call asynchronously waits for a frame to be successfully 847 /// can be replaced, this call asynchronously waits for a frame to be successfully
805 /// transmitted, then tries again. 848 /// transmitted, then tries again.
806 async fn write_fd<T: Instance>(&self, frame: &FdFrame) -> Option<FdFrame> { 849 async fn write_fd(&self, info: &'static Info, frame: &FdFrame) -> Option<FdFrame> {
807 self.write_generic::<T, _>(frame).await 850 self.write_generic::<_>(info, frame).await
808 } 851 }
809} 852}
810 853
811/// Common driver properties, including filters and error counters 854/// Common driver properties, including filters and error counters
812pub struct Properties<T> { 855pub struct Properties {
856 info: &'static Info,
813 // phantom pointer to ensure !Sync 857 // phantom pointer to ensure !Sync
814 instance: PhantomData<*const T>, 858 //instance: PhantomData<*const T>,
815} 859}
816 860
817impl<T: Instance> Properties<T> { 861impl Properties {
818 fn new() -> Self { 862 fn new(info: &'static Info) -> Self {
819 Self { 863 Self {
820 instance: Default::default(), 864 info,
865 //instance: Default::default(),
821 } 866 }
822 } 867 }
823 868
824 /// Set a standard address CAN filter in the specified slot in FDCAN memory. 869 /// Set a standard address CAN filter in the specified slot in FDCAN memory.
825 #[inline] 870 #[inline]
826 pub fn set_standard_filter(&self, slot: StandardFilterSlot, filter: StandardFilter) { 871 pub fn set_standard_filter(&self, slot: StandardFilterSlot, filter: StandardFilter) {
827 T::registers().msg_ram_mut().filters.flssa[slot as usize].activate(filter); 872 self.info.regs.msg_ram_mut().filters.flssa[slot as usize].activate(filter);
828 } 873 }
829 874
830 /// Set the full array of standard address CAN filters in FDCAN memory. 875 /// Set the full array of standard address CAN filters in FDCAN memory.
831 /// Overwrites all standard address filters in memory. 876 /// Overwrites all standard address filters in memory.
832 pub fn set_standard_filters(&self, filters: &[StandardFilter; STANDARD_FILTER_MAX as usize]) { 877 pub fn set_standard_filters(&self, filters: &[StandardFilter; STANDARD_FILTER_MAX as usize]) {
833 for (i, f) in filters.iter().enumerate() { 878 for (i, f) in filters.iter().enumerate() {
834 T::registers().msg_ram_mut().filters.flssa[i].activate(*f); 879 self.info.regs.msg_ram_mut().filters.flssa[i].activate(*f);
835 } 880 }
836 } 881 }
837 882
838 /// Set an extended address CAN filter in the specified slot in FDCAN memory. 883 /// Set an extended address CAN filter in the specified slot in FDCAN memory.
839 #[inline] 884 #[inline]
840 pub fn set_extended_filter(&self, slot: ExtendedFilterSlot, filter: ExtendedFilter) { 885 pub fn set_extended_filter(&self, slot: ExtendedFilterSlot, filter: ExtendedFilter) {
841 T::registers().msg_ram_mut().filters.flesa[slot as usize].activate(filter); 886 self.info.regs.msg_ram_mut().filters.flesa[slot as usize].activate(filter);
842 } 887 }
843 888
844 /// Set the full array of extended address CAN filters in FDCAN memory. 889 /// Set the full array of extended address CAN filters in FDCAN memory.
845 /// Overwrites all extended address filters in memory. 890 /// Overwrites all extended address filters in memory.
846 pub fn set_extended_filters(&self, filters: &[ExtendedFilter; EXTENDED_FILTER_MAX as usize]) { 891 pub fn set_extended_filters(&self, filters: &[ExtendedFilter; EXTENDED_FILTER_MAX as usize]) {
847 for (i, f) in filters.iter().enumerate() { 892 for (i, f) in filters.iter().enumerate() {
848 T::registers().msg_ram_mut().filters.flesa[i].activate(*f); 893 self.info.regs.msg_ram_mut().filters.flesa[i].activate(*f);
849 } 894 }
850 } 895 }
851 896
852 /// Get the CAN RX error counter 897 /// Get the CAN RX error counter
853 pub fn rx_error_count(&self) -> u8 { 898 pub fn rx_error_count(&self) -> u8 {
854 T::regs().ecr().read().rec() 899 self.info.regs.regs.ecr().read().rec()
855 } 900 }
856 901
857 /// Get the CAN TX error counter 902 /// Get the CAN TX error counter
858 pub fn tx_error_count(&self) -> u8 { 903 pub fn tx_error_count(&self) -> u8 {
859 T::regs().ecr().read().tec() 904 self.info.regs.regs.ecr().read().tec()
860 } 905 }
861 906
862 /// Get the current bus error mode 907 /// Get the current bus error mode
@@ -864,7 +909,7 @@ impl<T: Instance> Properties<T> {
864 // This read will clear LEC and DLEC. This is not ideal, but protocol 909 // This read will clear LEC and DLEC. This is not ideal, but protocol
865 // error reporting in this driver should have a big ol' FIXME on it 910 // error reporting in this driver should have a big ol' FIXME on it
866 // anyway! 911 // anyway!
867 let psr = T::regs().psr().read(); 912 let psr = self.info.regs.regs.psr().read();
868 match (psr.bo(), psr.ep()) { 913 match (psr.bo(), psr.ep()) {
869 (false, false) => BusErrorMode::ErrorActive, 914 (false, false) => BusErrorMode::ErrorActive,
870 (false, true) => BusErrorMode::ErrorPassive, 915 (false, true) => BusErrorMode::ErrorPassive,
@@ -892,10 +937,36 @@ impl State {
892 } 937 }
893} 938}
894 939
940struct Info {
941 regs: Registers,
942 interrupt0: crate::interrupt::Interrupt,
943 _interrupt1: crate::interrupt::Interrupt,
944 tx_waker: fn(),
945}
946
947impl Info {
948 #[cfg(feature = "time")]
949 fn calc_timestamp(&self, ns_per_timer_tick: u64, ts_val: u16) -> Timestamp {
950 let now_embassy = embassy_time::Instant::now();
951 if ns_per_timer_tick == 0 {
952 return now_embassy;
953 }
954 let cantime = { self.regs.regs.tscv().read().tsc() };
955 let delta = cantime.overflowing_sub(ts_val).0 as u64;
956 let ns = ns_per_timer_tick * delta as u64;
957 now_embassy - embassy_time::Duration::from_nanos(ns)
958 }
959
960 #[cfg(not(feature = "time"))]
961 fn calc_timestamp(&self, _ns_per_timer_tick: u64, ts_val: u16) -> Timestamp {
962 ts_val
963 }
964}
965
895trait SealedInstance { 966trait SealedInstance {
896 const MSG_RAM_OFFSET: usize; 967 const MSG_RAM_OFFSET: usize;
897 968
898 fn regs() -> &'static crate::pac::can::Fdcan; 969 fn info() -> &'static Info;
899 fn registers() -> crate::can::fd::peripheral::Registers; 970 fn registers() -> crate::can::fd::peripheral::Registers;
900 fn state() -> &'static State; 971 fn state() -> &'static State;
901 unsafe fn mut_state() -> &'static mut State; 972 unsafe fn mut_state() -> &'static mut State;
@@ -915,15 +986,23 @@ pub trait Instance: SealedInstance + RccPeripheral + 'static {
915pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>); 986pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>);
916 987
917macro_rules! impl_fdcan { 988macro_rules! impl_fdcan {
918 ($inst:ident, $msg_ram_inst:ident, $msg_ram_offset:literal) => { 989 ($inst:ident,
990 //$irq0:ident, $irq1:ident,
991 $msg_ram_inst:ident, $msg_ram_offset:literal) => {
919 impl SealedInstance for peripherals::$inst { 992 impl SealedInstance for peripherals::$inst {
920 const MSG_RAM_OFFSET: usize = $msg_ram_offset; 993 const MSG_RAM_OFFSET: usize = $msg_ram_offset;
921 994
922 fn regs() -> &'static crate::pac::can::Fdcan { 995 fn info() -> &'static Info {
923 &crate::pac::$inst 996 static INFO: Info = Info {
997 regs: Registers{regs: crate::pac::$inst, msgram: crate::pac::$msg_ram_inst, msg_ram_offset: $msg_ram_offset},
998 interrupt0: crate::_generated::peripheral_interrupts::$inst::IT0::IRQ,
999 _interrupt1: crate::_generated::peripheral_interrupts::$inst::IT1::IRQ,
1000 tx_waker: crate::_generated::peripheral_interrupts::$inst::IT0::pend,
1001 };
1002 &INFO
924 } 1003 }
925 fn registers() -> Registers { 1004 fn registers() -> Registers {
926 Registers{regs: &crate::pac::$inst, msgram: &crate::pac::$msg_ram_inst, msg_ram_offset: Self::MSG_RAM_OFFSET} 1005 Registers{regs: crate::pac::$inst, msgram: crate::pac::$msg_ram_inst, msg_ram_offset: Self::MSG_RAM_OFFSET}
927 } 1006 }
928 unsafe fn mut_state() -> &'static mut State { 1007 unsafe fn mut_state() -> &'static mut State {
929 static mut STATE: State = State::new(); 1008 static mut STATE: State = State::new();
@@ -939,7 +1018,7 @@ macro_rules! impl_fdcan {
939 if ns_per_timer_tick == 0 { 1018 if ns_per_timer_tick == 0 {
940 return now_embassy; 1019 return now_embassy;
941 } 1020 }
942 let cantime = { Self::regs().tscv().read().tsc() }; 1021 let cantime = { Self::registers().regs.tscv().read().tsc() };
943 let delta = cantime.overflowing_sub(ts_val).0 as u64; 1022 let delta = cantime.overflowing_sub(ts_val).0 as u64;
944 let ns = ns_per_timer_tick * delta as u64; 1023 let ns = ns_per_timer_tick * delta as u64;
945 now_embassy - embassy_time::Duration::from_nanos(ns) 1024 now_embassy - embassy_time::Duration::from_nanos(ns)
diff --git a/embassy-stm32/src/cordic/mod.rs b/embassy-stm32/src/cordic/mod.rs
index 29b11735e..fb342d2e7 100644
--- a/embassy-stm32/src/cordic/mod.rs
+++ b/embassy-stm32/src/cordic/mod.rs
@@ -4,7 +4,7 @@ use embassy_hal_internal::drop::OnDrop;
4use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; 4use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
5 5
6use crate::pac::cordic::vals; 6use crate::pac::cordic::vals;
7use crate::{dma, peripherals}; 7use crate::{dma, peripherals, rcc};
8 8
9mod enums; 9mod enums;
10pub use enums::*; 10pub use enums::*;
@@ -199,7 +199,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
199 /// If you need a peripheral -> CORDIC -> peripheral mode, 199 /// If you need a peripheral -> CORDIC -> peripheral mode,
200 /// you may want to set Cordic into [Mode::ZeroOverhead] mode, and add extra arguments with [Self::extra_config] 200 /// you may want to set Cordic into [Mode::ZeroOverhead] mode, and add extra arguments with [Self::extra_config]
201 pub fn new(peri: impl Peripheral<P = T> + 'd, config: Config) -> Self { 201 pub fn new(peri: impl Peripheral<P = T> + 'd, config: Config) -> Self {
202 T::enable_and_reset(); 202 rcc::enable_and_reset::<T>();
203 203
204 into_ref!(peri); 204 into_ref!(peri);
205 205
@@ -259,7 +259,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
259 259
260impl<'d, T: Instance> Drop for Cordic<'d, T> { 260impl<'d, T: Instance> Drop for Cordic<'d, T> {
261 fn drop(&mut self) { 261 fn drop(&mut self) {
262 T::disable(); 262 rcc::disable::<T>();
263 } 263 }
264} 264}
265 265
diff --git a/embassy-stm32/src/crc/v1.rs b/embassy-stm32/src/crc/v1.rs
index e8e0270af..f3d13de7c 100644
--- a/embassy-stm32/src/crc/v1.rs
+++ b/embassy-stm32/src/crc/v1.rs
@@ -2,8 +2,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
2 2
3use crate::pac::CRC as PAC_CRC; 3use crate::pac::CRC as PAC_CRC;
4use crate::peripherals::CRC; 4use crate::peripherals::CRC;
5use crate::rcc::SealedRccPeripheral; 5use crate::{rcc, Peripheral};
6use crate::Peripheral;
7 6
8/// CRC driver. 7/// CRC driver.
9pub struct Crc<'d> { 8pub struct Crc<'d> {
@@ -17,7 +16,7 @@ impl<'d> Crc<'d> {
17 16
18 // Note: enable and reset come from RccPeripheral. 17 // Note: enable and reset come from RccPeripheral.
19 // enable CRC clock in RCC. 18 // enable CRC clock in RCC.
20 CRC::enable_and_reset(); 19 rcc::enable_and_reset::<CRC>();
21 // Peripheral the peripheral 20 // Peripheral the peripheral
22 let mut instance = Self { _peri: peripheral }; 21 let mut instance = Self { _peri: peripheral };
23 instance.reset(); 22 instance.reset();
diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs
index ad7c79f12..09d956d7c 100644
--- a/embassy-stm32/src/crc/v2v3.rs
+++ b/embassy-stm32/src/crc/v2v3.rs
@@ -3,8 +3,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
3use crate::pac::crc::vals; 3use crate::pac::crc::vals;
4use crate::pac::CRC as PAC_CRC; 4use crate::pac::CRC as PAC_CRC;
5use crate::peripherals::CRC; 5use crate::peripherals::CRC;
6use crate::rcc::SealedRccPeripheral; 6use crate::{rcc, Peripheral};
7use crate::Peripheral;
8 7
9/// CRC driver. 8/// CRC driver.
10pub struct Crc<'d> { 9pub struct Crc<'d> {
@@ -84,7 +83,7 @@ impl<'d> Crc<'d> {
84 pub fn new(peripheral: impl Peripheral<P = CRC> + 'd, config: Config) -> Self { 83 pub fn new(peripheral: impl Peripheral<P = CRC> + 'd, config: Config) -> Self {
85 // Note: enable and reset come from RccPeripheral. 84 // Note: enable and reset come from RccPeripheral.
86 // reset to default values and enable CRC clock in RCC. 85 // reset to default values and enable CRC clock in RCC.
87 CRC::enable_and_reset(); 86 rcc::enable_and_reset::<CRC>();
88 into_ref!(peripheral); 87 into_ref!(peripheral);
89 let mut instance = Self { 88 let mut instance = Self {
90 _peripheral: peripheral, 89 _peripheral: peripheral,
diff --git a/embassy-stm32/src/cryp/mod.rs b/embassy-stm32/src/cryp/mod.rs
index f19c94fda..8d600c73c 100644
--- a/embassy-stm32/src/cryp/mod.rs
+++ b/embassy-stm32/src/cryp/mod.rs
@@ -9,7 +9,7 @@ use embassy_sync::waitqueue::AtomicWaker;
9 9
10use crate::dma::{NoDma, Transfer, TransferOptions}; 10use crate::dma::{NoDma, Transfer, TransferOptions};
11use crate::interrupt::typelevel::Interrupt; 11use crate::interrupt::typelevel::Interrupt;
12use crate::{interrupt, pac, peripherals, Peripheral}; 12use crate::{interrupt, pac, peripherals, rcc, Peripheral};
13 13
14const DES_BLOCK_SIZE: usize = 8; // 64 bits 14const DES_BLOCK_SIZE: usize = 8; // 64 bits
15const AES_BLOCK_SIZE: usize = 16; // 128 bits 15const AES_BLOCK_SIZE: usize = 16; // 128 bits
@@ -51,16 +51,16 @@ pub trait Cipher<'c> {
51 fn iv(&self) -> &[u8]; 51 fn iv(&self) -> &[u8];
52 52
53 /// Sets the processor algorithm mode according to the associated cipher. 53 /// Sets the processor algorithm mode according to the associated cipher.
54 fn set_algomode(&self, p: &pac::cryp::Cryp); 54 fn set_algomode(&self, p: pac::cryp::Cryp);
55 55
56 /// Performs any key preparation within the processor, if necessary. 56 /// Performs any key preparation within the processor, if necessary.
57 fn prepare_key(&self, _p: &pac::cryp::Cryp) {} 57 fn prepare_key(&self, _p: pac::cryp::Cryp) {}
58 58
59 /// Performs any cipher-specific initialization. 59 /// Performs any cipher-specific initialization.
60 fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, _p: &pac::cryp::Cryp, _cryp: &Cryp<T, DmaIn, DmaOut>) {} 60 fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, _p: pac::cryp::Cryp, _cryp: &Cryp<T, DmaIn, DmaOut>) {}
61 61
62 /// Performs any cipher-specific initialization. 62 /// Performs any cipher-specific initialization.
63 async fn init_phase<T: Instance, DmaIn, DmaOut>(&self, _p: &pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) 63 async fn init_phase<T: Instance, DmaIn, DmaOut>(&self, _p: pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>)
64 where 64 where
65 DmaIn: crate::cryp::DmaIn<T>, 65 DmaIn: crate::cryp::DmaIn<T>,
66 DmaOut: crate::cryp::DmaOut<T>, 66 DmaOut: crate::cryp::DmaOut<T>,
@@ -68,14 +68,14 @@ pub trait Cipher<'c> {
68 } 68 }
69 69
70 /// Called prior to processing the last data block for cipher-specific operations. 70 /// Called prior to processing the last data block for cipher-specific operations.
71 fn pre_final(&self, _p: &pac::cryp::Cryp, _dir: Direction, _padding_len: usize) -> [u32; 4] { 71 fn pre_final(&self, _p: pac::cryp::Cryp, _dir: Direction, _padding_len: usize) -> [u32; 4] {
72 return [0; 4]; 72 return [0; 4];
73 } 73 }
74 74
75 /// Called after processing the last data block for cipher-specific operations. 75 /// Called after processing the last data block for cipher-specific operations.
76 fn post_final_blocking<T: Instance, DmaIn, DmaOut>( 76 fn post_final_blocking<T: Instance, DmaIn, DmaOut>(
77 &self, 77 &self,
78 _p: &pac::cryp::Cryp, 78 _p: pac::cryp::Cryp,
79 _cryp: &Cryp<T, DmaIn, DmaOut>, 79 _cryp: &Cryp<T, DmaIn, DmaOut>,
80 _dir: Direction, 80 _dir: Direction,
81 _int_data: &mut [u8; AES_BLOCK_SIZE], 81 _int_data: &mut [u8; AES_BLOCK_SIZE],
@@ -87,7 +87,7 @@ pub trait Cipher<'c> {
87 /// Called after processing the last data block for cipher-specific operations. 87 /// Called after processing the last data block for cipher-specific operations.
88 async fn post_final<T: Instance, DmaIn, DmaOut>( 88 async fn post_final<T: Instance, DmaIn, DmaOut>(
89 &self, 89 &self,
90 _p: &pac::cryp::Cryp, 90 _p: pac::cryp::Cryp,
91 _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, 91 _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>,
92 _dir: Direction, 92 _dir: Direction,
93 _int_data: &mut [u8; AES_BLOCK_SIZE], 93 _int_data: &mut [u8; AES_BLOCK_SIZE],
@@ -142,7 +142,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for TdesEcb<'c, KEY_SIZE> {
142 self.iv 142 self.iv
143 } 143 }
144 144
145 fn set_algomode(&self, p: &pac::cryp::Cryp) { 145 fn set_algomode(&self, p: pac::cryp::Cryp) {
146 #[cfg(cryp_v1)] 146 #[cfg(cryp_v1)]
147 { 147 {
148 p.cr().modify(|w| w.set_algomode(0)); 148 p.cr().modify(|w| w.set_algomode(0));
@@ -184,7 +184,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for TdesCbc<'c, KEY_SIZE> {
184 self.iv 184 self.iv
185 } 185 }
186 186
187 fn set_algomode(&self, p: &pac::cryp::Cryp) { 187 fn set_algomode(&self, p: pac::cryp::Cryp) {
188 #[cfg(cryp_v1)] 188 #[cfg(cryp_v1)]
189 { 189 {
190 p.cr().modify(|w| w.set_algomode(1)); 190 p.cr().modify(|w| w.set_algomode(1));
@@ -226,7 +226,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for DesEcb<'c, KEY_SIZE> {
226 self.iv 226 self.iv
227 } 227 }
228 228
229 fn set_algomode(&self, p: &pac::cryp::Cryp) { 229 fn set_algomode(&self, p: pac::cryp::Cryp) {
230 #[cfg(cryp_v1)] 230 #[cfg(cryp_v1)]
231 { 231 {
232 p.cr().modify(|w| w.set_algomode(2)); 232 p.cr().modify(|w| w.set_algomode(2));
@@ -267,7 +267,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for DesCbc<'c, KEY_SIZE> {
267 self.iv 267 self.iv
268 } 268 }
269 269
270 fn set_algomode(&self, p: &pac::cryp::Cryp) { 270 fn set_algomode(&self, p: pac::cryp::Cryp) {
271 #[cfg(cryp_v1)] 271 #[cfg(cryp_v1)]
272 { 272 {
273 p.cr().modify(|w| w.set_algomode(3)); 273 p.cr().modify(|w| w.set_algomode(3));
@@ -308,7 +308,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesEcb<'c, KEY_SIZE> {
308 self.iv 308 self.iv
309 } 309 }
310 310
311 fn prepare_key(&self, p: &pac::cryp::Cryp) { 311 fn prepare_key(&self, p: pac::cryp::Cryp) {
312 #[cfg(cryp_v1)] 312 #[cfg(cryp_v1)]
313 { 313 {
314 p.cr().modify(|w| w.set_algomode(7)); 314 p.cr().modify(|w| w.set_algomode(7));
@@ -322,7 +322,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesEcb<'c, KEY_SIZE> {
322 while p.sr().read().busy() {} 322 while p.sr().read().busy() {}
323 } 323 }
324 324
325 fn set_algomode(&self, p: &pac::cryp::Cryp) { 325 fn set_algomode(&self, p: pac::cryp::Cryp) {
326 #[cfg(cryp_v1)] 326 #[cfg(cryp_v1)]
327 { 327 {
328 p.cr().modify(|w| w.set_algomode(2)); 328 p.cr().modify(|w| w.set_algomode(2));
@@ -365,7 +365,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCbc<'c, KEY_SIZE> {
365 self.iv 365 self.iv
366 } 366 }
367 367
368 fn prepare_key(&self, p: &pac::cryp::Cryp) { 368 fn prepare_key(&self, p: pac::cryp::Cryp) {
369 #[cfg(cryp_v1)] 369 #[cfg(cryp_v1)]
370 { 370 {
371 p.cr().modify(|w| w.set_algomode(7)); 371 p.cr().modify(|w| w.set_algomode(7));
@@ -379,7 +379,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCbc<'c, KEY_SIZE> {
379 while p.sr().read().busy() {} 379 while p.sr().read().busy() {}
380 } 380 }
381 381
382 fn set_algomode(&self, p: &pac::cryp::Cryp) { 382 fn set_algomode(&self, p: pac::cryp::Cryp) {
383 #[cfg(cryp_v1)] 383 #[cfg(cryp_v1)]
384 { 384 {
385 p.cr().modify(|w| w.set_algomode(5)); 385 p.cr().modify(|w| w.set_algomode(5));
@@ -421,7 +421,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesCtr<'c, KEY_SIZE> {
421 self.iv 421 self.iv
422 } 422 }
423 423
424 fn set_algomode(&self, p: &pac::cryp::Cryp) { 424 fn set_algomode(&self, p: pac::cryp::Cryp) {
425 #[cfg(cryp_v1)] 425 #[cfg(cryp_v1)]
426 { 426 {
427 p.cr().modify(|w| w.set_algomode(6)); 427 p.cr().modify(|w| w.set_algomode(6));
@@ -469,29 +469,25 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
469 self.iv.as_slice() 469 self.iv.as_slice()
470 } 470 }
471 471
472 fn set_algomode(&self, p: &pac::cryp::Cryp) { 472 fn set_algomode(&self, p: pac::cryp::Cryp) {
473 p.cr().modify(|w| w.set_algomode0(0)); 473 p.cr().modify(|w| w.set_algomode0(0));
474 p.cr().modify(|w| w.set_algomode3(true)); 474 p.cr().modify(|w| w.set_algomode3(true));
475 } 475 }
476 476
477 fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, p: &pac::cryp::Cryp, _cryp: &Cryp<T, DmaIn, DmaOut>) { 477 fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, p: pac::cryp::Cryp, _cryp: &Cryp<T, DmaIn, DmaOut>) {
478 p.cr().modify(|w| w.set_gcm_ccmph(0)); 478 p.cr().modify(|w| w.set_gcm_ccmph(0));
479 p.cr().modify(|w| w.set_crypen(true)); 479 p.cr().modify(|w| w.set_crypen(true));
480 while p.cr().read().crypen() {} 480 while p.cr().read().crypen() {}
481 } 481 }
482 482
483 async fn init_phase<T: Instance, DmaIn, DmaOut>( 483 async fn init_phase<T: Instance, DmaIn, DmaOut>(&self, p: pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) {
484 &self,
485 p: &pac::cryp::Cryp,
486 _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>,
487 ) {
488 p.cr().modify(|w| w.set_gcm_ccmph(0)); 484 p.cr().modify(|w| w.set_gcm_ccmph(0));
489 p.cr().modify(|w| w.set_crypen(true)); 485 p.cr().modify(|w| w.set_crypen(true));
490 while p.cr().read().crypen() {} 486 while p.cr().read().crypen() {}
491 } 487 }
492 488
493 #[cfg(cryp_v2)] 489 #[cfg(cryp_v2)]
494 fn pre_final(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] { 490 fn pre_final(&self, p: pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] {
495 //Handle special GCM partial block process. 491 //Handle special GCM partial block process.
496 if dir == Direction::Encrypt { 492 if dir == Direction::Encrypt {
497 p.cr().modify(|w| w.set_crypen(false)); 493 p.cr().modify(|w| w.set_crypen(false));
@@ -505,7 +501,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
505 } 501 }
506 502
507 #[cfg(any(cryp_v3, cryp_v4))] 503 #[cfg(any(cryp_v3, cryp_v4))]
508 fn pre_final(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { 504 fn pre_final(&self, p: pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] {
509 //Handle special GCM partial block process. 505 //Handle special GCM partial block process.
510 p.cr().modify(|w| w.set_npblb(padding_len as u8)); 506 p.cr().modify(|w| w.set_npblb(padding_len as u8));
511 [0; 4] 507 [0; 4]
@@ -514,7 +510,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
514 #[cfg(cryp_v2)] 510 #[cfg(cryp_v2)]
515 fn post_final_blocking<T: Instance, DmaIn, DmaOut>( 511 fn post_final_blocking<T: Instance, DmaIn, DmaOut>(
516 &self, 512 &self,
517 p: &pac::cryp::Cryp, 513 p: pac::cryp::Cryp,
518 cryp: &Cryp<T, DmaIn, DmaOut>, 514 cryp: &Cryp<T, DmaIn, DmaOut>,
519 dir: Direction, 515 dir: Direction,
520 int_data: &mut [u8; AES_BLOCK_SIZE], 516 int_data: &mut [u8; AES_BLOCK_SIZE],
@@ -540,7 +536,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
540 #[cfg(cryp_v2)] 536 #[cfg(cryp_v2)]
541 async fn post_final<T: Instance, DmaIn, DmaOut>( 537 async fn post_final<T: Instance, DmaIn, DmaOut>(
542 &self, 538 &self,
543 p: &pac::cryp::Cryp, 539 p: pac::cryp::Cryp,
544 cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, 540 cryp: &mut Cryp<'_, T, DmaIn, DmaOut>,
545 dir: Direction, 541 dir: Direction,
546 int_data: &mut [u8; AES_BLOCK_SIZE], 542 int_data: &mut [u8; AES_BLOCK_SIZE],
@@ -614,29 +610,25 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
614 self.iv.as_slice() 610 self.iv.as_slice()
615 } 611 }
616 612
617 fn set_algomode(&self, p: &pac::cryp::Cryp) { 613 fn set_algomode(&self, p: pac::cryp::Cryp) {
618 p.cr().modify(|w| w.set_algomode0(0)); 614 p.cr().modify(|w| w.set_algomode0(0));
619 p.cr().modify(|w| w.set_algomode3(true)); 615 p.cr().modify(|w| w.set_algomode3(true));
620 } 616 }
621 617
622 fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, p: &pac::cryp::Cryp, _cryp: &Cryp<T, DmaIn, DmaOut>) { 618 fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, p: pac::cryp::Cryp, _cryp: &Cryp<T, DmaIn, DmaOut>) {
623 p.cr().modify(|w| w.set_gcm_ccmph(0)); 619 p.cr().modify(|w| w.set_gcm_ccmph(0));
624 p.cr().modify(|w| w.set_crypen(true)); 620 p.cr().modify(|w| w.set_crypen(true));
625 while p.cr().read().crypen() {} 621 while p.cr().read().crypen() {}
626 } 622 }
627 623
628 async fn init_phase<T: Instance, DmaIn, DmaOut>( 624 async fn init_phase<T: Instance, DmaIn, DmaOut>(&self, p: pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) {
629 &self,
630 p: &pac::cryp::Cryp,
631 _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>,
632 ) {
633 p.cr().modify(|w| w.set_gcm_ccmph(0)); 625 p.cr().modify(|w| w.set_gcm_ccmph(0));
634 p.cr().modify(|w| w.set_crypen(true)); 626 p.cr().modify(|w| w.set_crypen(true));
635 while p.cr().read().crypen() {} 627 while p.cr().read().crypen() {}
636 } 628 }
637 629
638 #[cfg(cryp_v2)] 630 #[cfg(cryp_v2)]
639 fn pre_final(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] { 631 fn pre_final(&self, p: pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] {
640 //Handle special GCM partial block process. 632 //Handle special GCM partial block process.
641 if dir == Direction::Encrypt { 633 if dir == Direction::Encrypt {
642 p.cr().modify(|w| w.set_crypen(false)); 634 p.cr().modify(|w| w.set_crypen(false));
@@ -650,7 +642,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
650 } 642 }
651 643
652 #[cfg(any(cryp_v3, cryp_v4))] 644 #[cfg(any(cryp_v3, cryp_v4))]
653 fn pre_final(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { 645 fn pre_final(&self, p: pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] {
654 //Handle special GCM partial block process. 646 //Handle special GCM partial block process.
655 p.cr().modify(|w| w.set_npblb(padding_len as u8)); 647 p.cr().modify(|w| w.set_npblb(padding_len as u8));
656 [0; 4] 648 [0; 4]
@@ -659,7 +651,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
659 #[cfg(cryp_v2)] 651 #[cfg(cryp_v2)]
660 fn post_final_blocking<T: Instance, DmaIn, DmaOut>( 652 fn post_final_blocking<T: Instance, DmaIn, DmaOut>(
661 &self, 653 &self,
662 p: &pac::cryp::Cryp, 654 p: pac::cryp::Cryp,
663 cryp: &Cryp<T, DmaIn, DmaOut>, 655 cryp: &Cryp<T, DmaIn, DmaOut>,
664 dir: Direction, 656 dir: Direction,
665 int_data: &mut [u8; AES_BLOCK_SIZE], 657 int_data: &mut [u8; AES_BLOCK_SIZE],
@@ -685,7 +677,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
685 #[cfg(cryp_v2)] 677 #[cfg(cryp_v2)]
686 async fn post_final<T: Instance, DmaIn, DmaOut>( 678 async fn post_final<T: Instance, DmaIn, DmaOut>(
687 &self, 679 &self,
688 p: &pac::cryp::Cryp, 680 p: pac::cryp::Cryp,
689 cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, 681 cryp: &mut Cryp<'_, T, DmaIn, DmaOut>,
690 dir: Direction, 682 dir: Direction,
691 int_data: &mut [u8; AES_BLOCK_SIZE], 683 int_data: &mut [u8; AES_BLOCK_SIZE],
@@ -752,7 +744,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Aes
752 } else { 744 } else {
753 aad_header[0] = 0xFF; 745 aad_header[0] = 0xFF;
754 aad_header[1] = 0xFE; 746 aad_header[1] = 0xFE;
755 let aad_len_bytes: [u8; 4] = aad_len.to_be_bytes(); 747 let aad_len_bytes: [u8; 4] = (aad_len as u32).to_be_bytes();
756 aad_header[2] = aad_len_bytes[0]; 748 aad_header[2] = aad_len_bytes[0];
757 aad_header[3] = aad_len_bytes[1]; 749 aad_header[3] = aad_len_bytes[1];
758 aad_header[4] = aad_len_bytes[2]; 750 aad_header[4] = aad_len_bytes[2];
@@ -773,7 +765,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Aes
773 block0[0] |= ((((TAG_SIZE as u8) - 2) >> 1) & 0x07) << 3; 765 block0[0] |= ((((TAG_SIZE as u8) - 2) >> 1) & 0x07) << 3;
774 block0[0] |= ((15 - (iv.len() as u8)) - 1) & 0x07; 766 block0[0] |= ((15 - (iv.len() as u8)) - 1) & 0x07;
775 block0[1..1 + iv.len()].copy_from_slice(iv); 767 block0[1..1 + iv.len()].copy_from_slice(iv);
776 let payload_len_bytes: [u8; 4] = payload_len.to_be_bytes(); 768 let payload_len_bytes: [u8; 4] = (payload_len as u32).to_be_bytes();
777 if iv.len() <= 11 { 769 if iv.len() <= 11 {
778 block0[12] = payload_len_bytes[0]; 770 block0[12] = payload_len_bytes[0];
779 } else if payload_len_bytes[0] > 0 { 771 } else if payload_len_bytes[0] > 0 {
@@ -815,12 +807,12 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip
815 self.ctr.as_slice() 807 self.ctr.as_slice()
816 } 808 }
817 809
818 fn set_algomode(&self, p: &pac::cryp::Cryp) { 810 fn set_algomode(&self, p: pac::cryp::Cryp) {
819 p.cr().modify(|w| w.set_algomode0(1)); 811 p.cr().modify(|w| w.set_algomode0(1));
820 p.cr().modify(|w| w.set_algomode3(true)); 812 p.cr().modify(|w| w.set_algomode3(true));
821 } 813 }
822 814
823 fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, p: &pac::cryp::Cryp, cryp: &Cryp<T, DmaIn, DmaOut>) { 815 fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, p: pac::cryp::Cryp, cryp: &Cryp<T, DmaIn, DmaOut>) {
824 p.cr().modify(|w| w.set_gcm_ccmph(0)); 816 p.cr().modify(|w| w.set_gcm_ccmph(0));
825 817
826 cryp.write_bytes_blocking(Self::BLOCK_SIZE, &self.block0); 818 cryp.write_bytes_blocking(Self::BLOCK_SIZE, &self.block0);
@@ -829,7 +821,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip
829 while p.cr().read().crypen() {} 821 while p.cr().read().crypen() {}
830 } 822 }
831 823
832 async fn init_phase<T: Instance, DmaIn, DmaOut>(&self, p: &pac::cryp::Cryp, cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) 824 async fn init_phase<T: Instance, DmaIn, DmaOut>(&self, p: pac::cryp::Cryp, cryp: &mut Cryp<'_, T, DmaIn, DmaOut>)
833 where 825 where
834 DmaIn: crate::cryp::DmaIn<T>, 826 DmaIn: crate::cryp::DmaIn<T>,
835 DmaOut: crate::cryp::DmaOut<T>, 827 DmaOut: crate::cryp::DmaOut<T>,
@@ -847,7 +839,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip
847 } 839 }
848 840
849 #[cfg(cryp_v2)] 841 #[cfg(cryp_v2)]
850 fn pre_final(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] { 842 fn pre_final(&self, p: pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] {
851 //Handle special CCM partial block process. 843 //Handle special CCM partial block process.
852 let mut temp1 = [0; 4]; 844 let mut temp1 = [0; 4];
853 if dir == Direction::Decrypt { 845 if dir == Direction::Decrypt {
@@ -866,7 +858,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip
866 } 858 }
867 859
868 #[cfg(any(cryp_v3, cryp_v4))] 860 #[cfg(any(cryp_v3, cryp_v4))]
869 fn pre_final(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] { 861 fn pre_final(&self, p: pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] {
870 //Handle special GCM partial block process. 862 //Handle special GCM partial block process.
871 p.cr().modify(|w| w.set_npblb(padding_len as u8)); 863 p.cr().modify(|w| w.set_npblb(padding_len as u8));
872 [0; 4] 864 [0; 4]
@@ -875,7 +867,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip
875 #[cfg(cryp_v2)] 867 #[cfg(cryp_v2)]
876 fn post_final_blocking<T: Instance, DmaIn, DmaOut>( 868 fn post_final_blocking<T: Instance, DmaIn, DmaOut>(
877 &self, 869 &self,
878 p: &pac::cryp::Cryp, 870 p: pac::cryp::Cryp,
879 cryp: &Cryp<T, DmaIn, DmaOut>, 871 cryp: &Cryp<T, DmaIn, DmaOut>,
880 dir: Direction, 872 dir: Direction,
881 int_data: &mut [u8; AES_BLOCK_SIZE], 873 int_data: &mut [u8; AES_BLOCK_SIZE],
@@ -912,7 +904,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip
912 #[cfg(cryp_v2)] 904 #[cfg(cryp_v2)]
913 async fn post_final<T: Instance, DmaIn, DmaOut>( 905 async fn post_final<T: Instance, DmaIn, DmaOut>(
914 &self, 906 &self,
915 p: &pac::cryp::Cryp, 907 p: pac::cryp::Cryp,
916 cryp: &mut Cryp<'_, T, DmaIn, DmaOut>, 908 cryp: &mut Cryp<'_, T, DmaIn, DmaOut>,
917 dir: Direction, 909 dir: Direction,
918 int_data: &mut [u8; AES_BLOCK_SIZE], 910 int_data: &mut [u8; AES_BLOCK_SIZE],
@@ -1029,7 +1021,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
1029 outdma: impl Peripheral<P = DmaOut> + 'd, 1021 outdma: impl Peripheral<P = DmaOut> + 'd,
1030 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 1022 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
1031 ) -> Self { 1023 ) -> Self {
1032 T::enable_and_reset(); 1024 rcc::enable_and_reset::<T>();
1033 into_ref!(peri, indma, outdma); 1025 into_ref!(peri, indma, outdma);
1034 let instance = Self { 1026 let instance = Self {
1035 _peripheral: peri, 1027 _peripheral: peri,
@@ -1083,9 +1075,9 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
1083 // Set data type to 8-bit. This will match software implementations. 1075 // Set data type to 8-bit. This will match software implementations.
1084 T::regs().cr().modify(|w| w.set_datatype(2)); 1076 T::regs().cr().modify(|w| w.set_datatype(2));
1085 1077
1086 ctx.cipher.prepare_key(&T::regs()); 1078 ctx.cipher.prepare_key(T::regs());
1087 1079
1088 ctx.cipher.set_algomode(&T::regs()); 1080 ctx.cipher.set_algomode(T::regs());
1089 1081
1090 // Set encrypt/decrypt 1082 // Set encrypt/decrypt
1091 if dir == Direction::Encrypt { 1083 if dir == Direction::Encrypt {
@@ -1115,7 +1107,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
1115 // Flush in/out FIFOs 1107 // Flush in/out FIFOs
1116 T::regs().cr().modify(|w| w.fflush()); 1108 T::regs().cr().modify(|w| w.fflush());
1117 1109
1118 ctx.cipher.init_phase_blocking(&T::regs(), self); 1110 ctx.cipher.init_phase_blocking(T::regs(), self);
1119 1111
1120 self.store_context(&mut ctx); 1112 self.store_context(&mut ctx);
1121 1113
@@ -1166,9 +1158,9 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
1166 // Set data type to 8-bit. This will match software implementations. 1158 // Set data type to 8-bit. This will match software implementations.
1167 T::regs().cr().modify(|w| w.set_datatype(2)); 1159 T::regs().cr().modify(|w| w.set_datatype(2));
1168 1160
1169 ctx.cipher.prepare_key(&T::regs()); 1161 ctx.cipher.prepare_key(T::regs());
1170 1162
1171 ctx.cipher.set_algomode(&T::regs()); 1163 ctx.cipher.set_algomode(T::regs());
1172 1164
1173 // Set encrypt/decrypt 1165 // Set encrypt/decrypt
1174 if dir == Direction::Encrypt { 1166 if dir == Direction::Encrypt {
@@ -1198,7 +1190,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
1198 // Flush in/out FIFOs 1190 // Flush in/out FIFOs
1199 T::regs().cr().modify(|w| w.fflush()); 1191 T::regs().cr().modify(|w| w.fflush());
1200 1192
1201 ctx.cipher.init_phase(&T::regs(), self).await; 1193 ctx.cipher.init_phase(T::regs(), self).await;
1202 1194
1203 self.store_context(&mut ctx); 1195 self.store_context(&mut ctx);
1204 1196
@@ -1462,7 +1454,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
1462 // Handle the final block, which is incomplete. 1454 // Handle the final block, which is incomplete.
1463 if last_block_remainder > 0 { 1455 if last_block_remainder > 0 {
1464 let padding_len = C::BLOCK_SIZE - last_block_remainder; 1456 let padding_len = C::BLOCK_SIZE - last_block_remainder;
1465 let temp1 = ctx.cipher.pre_final(&T::regs(), ctx.dir, padding_len); 1457 let temp1 = ctx.cipher.pre_final(T::regs(), ctx.dir, padding_len);
1466 1458
1467 let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; 1459 let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
1468 let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; 1460 let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
@@ -1478,7 +1470,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
1478 let mut mask: [u8; 16] = [0; 16]; 1470 let mut mask: [u8; 16] = [0; 16];
1479 mask[..last_block_remainder].fill(0xFF); 1471 mask[..last_block_remainder].fill(0xFF);
1480 ctx.cipher 1472 ctx.cipher
1481 .post_final_blocking(&T::regs(), self, ctx.dir, &mut intermediate_data, temp1, mask); 1473 .post_final_blocking(T::regs(), self, ctx.dir, &mut intermediate_data, temp1, mask);
1482 } 1474 }
1483 1475
1484 ctx.payload_len += input.len() as u64; 1476 ctx.payload_len += input.len() as u64;
@@ -1559,7 +1551,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
1559 // Handle the final block, which is incomplete. 1551 // Handle the final block, which is incomplete.
1560 if last_block_remainder > 0 { 1552 if last_block_remainder > 0 {
1561 let padding_len = C::BLOCK_SIZE - last_block_remainder; 1553 let padding_len = C::BLOCK_SIZE - last_block_remainder;
1562 let temp1 = ctx.cipher.pre_final(&T::regs(), ctx.dir, padding_len); 1554 let temp1 = ctx.cipher.pre_final(T::regs(), ctx.dir, padding_len);
1563 1555
1564 let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; 1556 let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
1565 let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE]; 1557 let mut last_block: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
@@ -1576,7 +1568,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
1576 let mut mask: [u8; 16] = [0; 16]; 1568 let mut mask: [u8; 16] = [0; 16];
1577 mask[..last_block_remainder].fill(0xFF); 1569 mask[..last_block_remainder].fill(0xFF);
1578 ctx.cipher 1570 ctx.cipher
1579 .post_final(&T::regs(), self, ctx.dir, &mut intermediate_data, temp1, mask) 1571 .post_final(T::regs(), self, ctx.dir, &mut intermediate_data, temp1, mask)
1580 .await; 1572 .await;
1581 } 1573 }
1582 1574
@@ -1758,7 +1750,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
1758 self.load_key(ctx.cipher.key()); 1750 self.load_key(ctx.cipher.key());
1759 1751
1760 // Prepare key if applicable. 1752 // Prepare key if applicable.
1761 ctx.cipher.prepare_key(&T::regs()); 1753 ctx.cipher.prepare_key(T::regs());
1762 T::regs().cr().write(|w| w.0 = ctx.cr); 1754 T::regs().cr().write(|w| w.0 = ctx.cr);
1763 1755
1764 // Enable crypto processor. 1756 // Enable crypto processor.
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 8a748ad72..8bba5ded0 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -8,7 +8,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
8use crate::dma::NoDma; 8use crate::dma::NoDma;
9#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))] 9#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
10use crate::pac::dac; 10use crate::pac::dac;
11use crate::rcc::RccPeripheral; 11use crate::rcc::{self, RccPeripheral};
12use crate::{peripherals, Peripheral}; 12use crate::{peripherals, Peripheral};
13 13
14mod tsel; 14mod tsel;
@@ -131,7 +131,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
131 ) -> Self { 131 ) -> Self {
132 into_ref!(dma, pin); 132 into_ref!(dma, pin);
133 pin.set_as_analog(); 133 pin.set_as_analog();
134 T::enable_and_reset(); 134 rcc::enable_and_reset::<T>();
135 let mut dac = Self { 135 let mut dac = Self {
136 phantom: PhantomData, 136 phantom: PhantomData,
137 dma, 137 dma,
@@ -157,7 +157,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
157 #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))] 157 #[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))]
158 pub fn new_internal(_peri: impl Peripheral<P = T> + 'd, dma: impl Peripheral<P = DMA> + 'd) -> Self { 158 pub fn new_internal(_peri: impl Peripheral<P = T> + 'd, dma: impl Peripheral<P = DMA> + 'd) -> Self {
159 into_ref!(dma); 159 into_ref!(dma);
160 T::enable_and_reset(); 160 rcc::enable_and_reset::<T>();
161 let mut dac = Self { 161 let mut dac = Self {
162 phantom: PhantomData, 162 phantom: PhantomData,
163 dma, 163 dma,
@@ -356,7 +356,7 @@ impl_dma_methods!(2, DacDma2);
356 356
357impl<'d, T: Instance, const N: u8, DMA> Drop for DacChannel<'d, T, N, DMA> { 357impl<'d, T: Instance, const N: u8, DMA> Drop for DacChannel<'d, T, N, DMA> {
358 fn drop(&mut self) { 358 fn drop(&mut self) {
359 T::disable(); 359 rcc::disable::<T>();
360 } 360 }
361} 361}
362 362
@@ -400,8 +400,8 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
400 pin_ch2.set_as_analog(); 400 pin_ch2.set_as_analog();
401 401
402 // Enable twice to increment the DAC refcount for each channel. 402 // Enable twice to increment the DAC refcount for each channel.
403 T::enable_and_reset(); 403 rcc::enable_and_reset::<T>();
404 T::enable_and_reset(); 404 rcc::enable_and_reset::<T>();
405 405
406 let mut ch1 = DacCh1 { 406 let mut ch1 = DacCh1 {
407 phantom: PhantomData, 407 phantom: PhantomData,
@@ -444,8 +444,8 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
444 ) -> Self { 444 ) -> Self {
445 into_ref!(dma_ch1, dma_ch2); 445 into_ref!(dma_ch1, dma_ch2);
446 // Enable twice to increment the DAC refcount for each channel. 446 // Enable twice to increment the DAC refcount for each channel.
447 T::enable_and_reset(); 447 rcc::enable_and_reset::<T>();
448 T::enable_and_reset(); 448 rcc::enable_and_reset::<T>();
449 449
450 let mut ch1 = DacCh1 { 450 let mut ch1 = DacCh1 {
451 phantom: PhantomData, 451 phantom: PhantomData,
@@ -508,7 +508,7 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
508} 508}
509 509
510trait SealedInstance { 510trait SealedInstance {
511 fn regs() -> &'static crate::pac::dac::Dac; 511 fn regs() -> crate::pac::dac::Dac;
512} 512}
513 513
514/// DAC instance. 514/// DAC instance.
@@ -523,8 +523,8 @@ pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
523foreach_peripheral!( 523foreach_peripheral!(
524 (dac, $inst:ident) => { 524 (dac, $inst:ident) => {
525 impl crate::dac::SealedInstance for peripherals::$inst { 525 impl crate::dac::SealedInstance for peripherals::$inst {
526 fn regs() -> &'static crate::pac::dac::Dac { 526 fn regs() -> crate::pac::dac::Dac {
527 &crate::pac::$inst 527 crate::pac::$inst
528 } 528 }
529 } 529 }
530 530
diff --git a/embassy-stm32/src/dcmi.rs b/embassy-stm32/src/dcmi.rs
index 646ee2ce2..858ae49ca 100644
--- a/embassy-stm32/src/dcmi.rs
+++ b/embassy-stm32/src/dcmi.rs
@@ -9,7 +9,7 @@ use embassy_sync::waitqueue::AtomicWaker;
9use crate::dma::Transfer; 9use crate::dma::Transfer;
10use crate::gpio::{AFType, Speed}; 10use crate::gpio::{AFType, Speed};
11use crate::interrupt::typelevel::Interrupt; 11use crate::interrupt::typelevel::Interrupt;
12use crate::{interrupt, Peripheral}; 12use crate::{interrupt, rcc, Peripheral};
13 13
14/// Interrupt handler. 14/// Interrupt handler.
15pub struct InterruptHandler<T: Instance> { 15pub struct InterruptHandler<T: Instance> {
@@ -350,7 +350,7 @@ where
350 use_embedded_synchronization: bool, 350 use_embedded_synchronization: bool,
351 edm: u8, 351 edm: u8,
352 ) -> Self { 352 ) -> Self {
353 T::enable_and_reset(); 353 rcc::enable_and_reset::<T>();
354 354
355 peri.regs().cr().modify(|r| { 355 peri.regs().cr().modify(|r| {
356 r.set_cm(true); // disable continuous mode (snapshot mode) 356 r.set_cm(true); // disable continuous mode (snapshot mode)
diff --git a/embassy-stm32/src/dma/util.rs b/embassy-stm32/src/dma/util.rs
index 962ea2501..5aaca57c9 100644
--- a/embassy-stm32/src/dma/util.rs
+++ b/embassy-stm32/src/dma/util.rs
@@ -48,6 +48,7 @@ impl<'d> ChannelAndRequest<'d> {
48 Transfer::new_write_raw(&mut self.channel, self.request, buf, peri_addr, options) 48 Transfer::new_write_raw(&mut self.channel, self.request, buf, peri_addr, options)
49 } 49 }
50 50
51 #[allow(dead_code)]
51 pub unsafe fn write_repeated<'a, W: Word>( 52 pub unsafe fn write_repeated<'a, W: Word>(
52 &'a mut self, 53 &'a mut self,
53 repeated: &'a W, 54 repeated: &'a W,
diff --git a/embassy-stm32/src/dsihost.rs b/embassy-stm32/src/dsihost.rs
index f1c737fdc..e1fb3b0b0 100644
--- a/embassy-stm32/src/dsihost.rs
+++ b/embassy-stm32/src/dsihost.rs
@@ -6,14 +6,14 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
6 6
7//use crate::gpio::{AnyPin, SealedPin}; 7//use crate::gpio::{AnyPin, SealedPin};
8use crate::gpio::{AFType, AnyPin, Pull, Speed}; 8use crate::gpio::{AFType, AnyPin, Pull, Speed};
9use crate::rcc::RccPeripheral; 9use crate::rcc::{self, RccPeripheral};
10use crate::{peripherals, Peripheral}; 10use crate::{peripherals, Peripheral};
11 11
12/// Performs a busy-wait delay for a specified number of microseconds. 12/// Performs a busy-wait delay for a specified number of microseconds.
13pub fn blocking_delay_ms(ms: u32) { 13pub fn blocking_delay_ms(ms: u32) {
14 #[cfg(time)] 14 #[cfg(feature = "time")]
15 embassy_time::block_for(embassy_time::Duration::from_millis(ms)); 15 embassy_time::block_for(embassy_time::Duration::from_millis(ms as u64));
16 #[cfg(not(time))] 16 #[cfg(not(feature = "time"))]
17 cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 1_000 * ms); 17 cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 1_000 * ms);
18} 18}
19 19
@@ -77,7 +77,7 @@ impl<'d, T: Instance> DsiHost<'d, T> {
77 pub fn new(_peri: impl Peripheral<P = T> + 'd, te: impl Peripheral<P = impl TePin<T>> + 'd) -> Self { 77 pub fn new(_peri: impl Peripheral<P = T> + 'd, te: impl Peripheral<P = impl TePin<T>> + 'd) -> Self {
78 into_ref!(te); 78 into_ref!(te);
79 79
80 T::enable_and_reset(); 80 rcc::enable_and_reset::<T>();
81 81
82 // Set Tearing Enable pin according to CubeMx example 82 // Set Tearing Enable pin according to CubeMx example
83 te.set_as_af_pull(te.af_num(), AFType::OutputPushPull, Pull::None); 83 te.set_as_af_pull(te.af_num(), AFType::OutputPushPull, Pull::None);
@@ -407,7 +407,7 @@ impl<'d, T: Instance> Drop for DsiHost<'d, T> {
407} 407}
408 408
409trait SealedInstance: crate::rcc::SealedRccPeripheral { 409trait SealedInstance: crate::rcc::SealedRccPeripheral {
410 fn regs() -> &'static crate::pac::dsihost::Dsihost; 410 fn regs() -> crate::pac::dsihost::Dsihost;
411} 411}
412 412
413/// DSI instance trait. 413/// DSI instance trait.
@@ -419,8 +419,8 @@ pin_trait!(TePin, Instance);
419foreach_peripheral!( 419foreach_peripheral!(
420 (dsihost, $inst:ident) => { 420 (dsihost, $inst:ident) => {
421 impl crate::dsihost::SealedInstance for peripherals::$inst { 421 impl crate::dsihost::SealedInstance for peripherals::$inst {
422 fn regs() -> &'static crate::pac::dsihost::Dsihost { 422 fn regs() -> crate::pac::dsihost::Dsihost {
423 &crate::pac::$inst 423 crate::pac::$inst
424 } 424 }
425 } 425 }
426 426
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs
index 8c6ca2471..ce2d1a04c 100644
--- a/embassy-stm32/src/flash/mod.rs
+++ b/embassy-stm32/src/flash/mod.rs
@@ -96,7 +96,7 @@ pub enum FlashBank {
96#[cfg_attr(any(flash_f1, flash_f3), path = "f1f3.rs")] 96#[cfg_attr(any(flash_f1, flash_f3), path = "f1f3.rs")]
97#[cfg_attr(flash_f4, path = "f4.rs")] 97#[cfg_attr(flash_f4, path = "f4.rs")]
98#[cfg_attr(flash_f7, path = "f7.rs")] 98#[cfg_attr(flash_f7, path = "f7.rs")]
99#[cfg_attr(any(flash_g0, flash_g4), path = "g.rs")] 99#[cfg_attr(any(flash_g0, flash_g4c2, flash_g4c3, flash_g4c4), path = "g.rs")]
100#[cfg_attr(flash_h7, path = "h7.rs")] 100#[cfg_attr(flash_h7, path = "h7.rs")]
101#[cfg_attr(flash_h7ab, path = "h7.rs")] 101#[cfg_attr(flash_h7ab, path = "h7.rs")]
102#[cfg_attr(flash_u5, path = "u5.rs")] 102#[cfg_attr(flash_u5, path = "u5.rs")]
@@ -105,7 +105,7 @@ pub enum FlashBank {
105#[cfg_attr( 105#[cfg_attr(
106 not(any( 106 not(any(
107 flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f1, flash_f3, flash_f4, flash_f7, flash_g0, 107 flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f1, flash_f3, flash_f4, flash_f7, flash_g0,
108 flash_g4, flash_h7, flash_h7ab, flash_u5, flash_h50, flash_u0 108 flash_g4c2, flash_g4c3, flash_g4c4, flash_h7, flash_h7ab, flash_u5, flash_h50, flash_u0
109 )), 109 )),
110 path = "other.rs" 110 path = "other.rs"
111)] 111)]
diff --git a/embassy-stm32/src/fmc.rs b/embassy-stm32/src/fmc.rs
index aced69878..82d8089f4 100644
--- a/embassy-stm32/src/fmc.rs
+++ b/embassy-stm32/src/fmc.rs
@@ -4,7 +4,7 @@ use core::marker::PhantomData;
4use embassy_hal_internal::into_ref; 4use embassy_hal_internal::into_ref;
5 5
6use crate::gpio::{AFType, Pull, Speed}; 6use crate::gpio::{AFType, Pull, Speed};
7use crate::Peripheral; 7use crate::{rcc, Peripheral};
8 8
9/// FMC driver 9/// FMC driver
10pub struct Fmc<'d, T: Instance> { 10pub struct Fmc<'d, T: Instance> {
@@ -27,7 +27,7 @@ where
27 27
28 /// Enable the FMC peripheral and reset it. 28 /// Enable the FMC peripheral and reset it.
29 pub fn enable(&mut self) { 29 pub fn enable(&mut self) {
30 T::enable_and_reset(); 30 rcc::enable_and_reset::<T>();
31 } 31 }
32 32
33 /// Enable the memory controller on applicable chips. 33 /// Enable the memory controller on applicable chips.
@@ -35,7 +35,7 @@ where
35 // fmc v1 and v2 does not have the fmcen bit 35 // fmc v1 and v2 does not have the fmcen bit
36 // fsmc v1, v2 and v3 does not have the fmcen bit 36 // fsmc v1, v2 and v3 does not have the fmcen bit
37 // This is a "not" because it is expected that all future versions have this bit 37 // This is a "not" because it is expected that all future versions have this bit
38 #[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1, fmc_v4)))] 38 #[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fmc_v4)))]
39 T::REGS.bcr1().modify(|r| r.set_fmcen(true)); 39 T::REGS.bcr1().modify(|r| r.set_fmcen(true));
40 #[cfg(any(fmc_v4))] 40 #[cfg(any(fmc_v4))]
41 T::REGS.nor_psram().bcr1().modify(|r| r.set_fmcen(true)); 41 T::REGS.nor_psram().bcr1().modify(|r| r.set_fmcen(true));
@@ -54,14 +54,14 @@ where
54 const REGISTERS: *const () = T::REGS.as_ptr() as *const _; 54 const REGISTERS: *const () = T::REGS.as_ptr() as *const _;
55 55
56 fn enable(&mut self) { 56 fn enable(&mut self) {
57 T::enable_and_reset(); 57 rcc::enable_and_reset::<T>();
58 } 58 }
59 59
60 fn memory_controller_enable(&mut self) { 60 fn memory_controller_enable(&mut self) {
61 // fmc v1 and v2 does not have the fmcen bit 61 // fmc v1 and v2 does not have the fmcen bit
62 // fsmc v1, v2 and v3 does not have the fmcen bit 62 // fsmc v1, v2 and v3 does not have the fmcen bit
63 // This is a "not" because it is expected that all future versions have this bit 63 // This is a "not" because it is expected that all future versions have this bit
64 #[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1, fmc_v4)))] 64 #[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fmc_v4)))]
65 T::REGS.bcr1().modify(|r| r.set_fmcen(true)); 65 T::REGS.bcr1().modify(|r| r.set_fmcen(true));
66 #[cfg(any(fmc_v4))] 66 #[cfg(any(fmc_v4))]
67 T::REGS.nor_psram().bcr1().modify(|r| r.set_fmcen(true)); 67 T::REGS.nor_psram().bcr1().modify(|r| r.set_fmcen(true));
@@ -200,7 +200,7 @@ impl<'d, T: Instance> Fmc<'d, T> {
200 )); 200 ));
201} 201}
202 202
203trait SealedInstance: crate::rcc::SealedRccPeripheral { 203trait SealedInstance: crate::rcc::RccPeripheral {
204 const REGS: crate::pac::fmc::Fmc; 204 const REGS: crate::pac::fmc::Fmc;
205} 205}
206 206
diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs
index d60a857ef..de08127cf 100644
--- a/embassy-stm32/src/gpio.rs
+++ b/embassy-stm32/src/gpio.rs
@@ -822,7 +822,7 @@ foreach_pin!(
822 822
823pub(crate) unsafe fn init(_cs: CriticalSection) { 823pub(crate) unsafe fn init(_cs: CriticalSection) {
824 #[cfg(afio)] 824 #[cfg(afio)]
825 <crate::peripherals::AFIO as crate::rcc::SealedRccPeripheral>::enable_and_reset_with_cs(_cs); 825 crate::rcc::enable_and_reset_with_cs::<crate::peripherals::AFIO>(_cs);
826 826
827 crate::_generated::init_gpio(); 827 crate::_generated::init_gpio();
828} 828}
diff --git a/embassy-stm32/src/hash/mod.rs b/embassy-stm32/src/hash/mod.rs
index 787d5b1c9..4d4a8ec5b 100644
--- a/embassy-stm32/src/hash/mod.rs
+++ b/embassy-stm32/src/hash/mod.rs
@@ -17,8 +17,7 @@ use crate::dma::NoDma;
17use crate::dma::Transfer; 17use crate::dma::Transfer;
18use crate::interrupt::typelevel::Interrupt; 18use crate::interrupt::typelevel::Interrupt;
19use crate::peripherals::HASH; 19use crate::peripherals::HASH;
20use crate::rcc::SealedRccPeripheral; 20use crate::{interrupt, pac, peripherals, rcc, Peripheral};
21use crate::{interrupt, pac, peripherals, Peripheral};
22 21
23#[cfg(hash_v1)] 22#[cfg(hash_v1)]
24const NUM_CONTEXT_REGS: usize = 51; 23const NUM_CONTEXT_REGS: usize = 51;
@@ -130,7 +129,7 @@ impl<'d, T: Instance, D> Hash<'d, T, D> {
130 dma: impl Peripheral<P = D> + 'd, 129 dma: impl Peripheral<P = D> + 'd,
131 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 130 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
132 ) -> Self { 131 ) -> Self {
133 HASH::enable_and_reset(); 132 rcc::enable_and_reset::<HASH>();
134 into_ref!(peripheral, dma); 133 into_ref!(peripheral, dma);
135 let instance = Self { 134 let instance = Self {
136 _peripheral: peripheral, 135 _peripheral: peripheral,
diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs
index 02e45819c..c9d5bff17 100644
--- a/embassy-stm32/src/hrtim/mod.rs
+++ b/embassy-stm32/src/hrtim/mod.rs
@@ -9,7 +9,7 @@ pub use traits::Instance;
9 9
10use crate::gpio::{AFType, AnyPin}; 10use crate::gpio::{AFType, AnyPin};
11use crate::time::Hertz; 11use crate::time::Hertz;
12use crate::Peripheral; 12use crate::{rcc, Peripheral};
13 13
14/// HRTIM burst controller instance. 14/// HRTIM burst controller instance.
15pub struct BurstController<T: Instance> { 15pub struct BurstController<T: Instance> {
@@ -172,7 +172,7 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> {
172 fn new_inner(tim: impl Peripheral<P = T> + 'd) -> Self { 172 fn new_inner(tim: impl Peripheral<P = T> + 'd) -> Self {
173 into_ref!(tim); 173 into_ref!(tim);
174 174
175 T::enable_and_reset(); 175 rcc::enable_and_reset::<T>();
176 176
177 #[cfg(stm32f334)] 177 #[cfg(stm32f334)]
178 if crate::pac::RCC.cfgr3().read().hrtim1sw() == crate::pac::rcc::vals::Timsw::PLL1_P { 178 if crate::pac::RCC.cfgr3().read().hrtim1sw() == crate::pac::rcc::vals::Timsw::PLL1_P {
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index ef5fd0972..6d12af2cc 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -9,16 +9,16 @@ use core::future::Future;
9use core::iter; 9use core::iter;
10use core::marker::PhantomData; 10use core::marker::PhantomData;
11 11
12use embassy_hal_internal::{into_ref, Peripheral}; 12use embassy_hal_internal::{Peripheral, PeripheralRef};
13use embassy_sync::waitqueue::AtomicWaker; 13use embassy_sync::waitqueue::AtomicWaker;
14#[cfg(feature = "time")] 14#[cfg(feature = "time")]
15use embassy_time::{Duration, Instant}; 15use embassy_time::{Duration, Instant};
16 16
17use crate::dma::ChannelAndRequest; 17use crate::dma::ChannelAndRequest;
18use crate::gpio::{AFType, Pull}; 18use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed};
19use crate::interrupt::typelevel::Interrupt; 19use crate::interrupt::typelevel::Interrupt;
20use crate::mode::{Async, Blocking, Mode}; 20use crate::mode::{Async, Blocking, Mode};
21use crate::rcc::{ClockEnableBit, SealedRccPeripheral}; 21use crate::rcc::{RccInfo, SealedRccPeripheral};
22use crate::time::Hertz; 22use crate::time::Hertz;
23use crate::{interrupt, peripherals}; 23use crate::{interrupt, peripherals};
24 24
@@ -72,11 +72,29 @@ impl Default for Config {
72 } 72 }
73} 73}
74 74
75impl Config {
76 fn scl_pull_mode(&self) -> Pull {
77 match self.scl_pullup {
78 true => Pull::Up,
79 false => Pull::Down,
80 }
81 }
82
83 fn sda_pull_mode(&self) -> Pull {
84 match self.sda_pullup {
85 true => Pull::Up,
86 false => Pull::Down,
87 }
88 }
89}
90
75/// I2C driver. 91/// I2C driver.
76pub struct I2c<'d, M: Mode> { 92pub struct I2c<'d, M: Mode> {
77 info: &'static Info, 93 info: &'static Info,
78 state: &'static State, 94 state: &'static State,
79 kernel_clock: Hertz, 95 kernel_clock: Hertz,
96 scl: Option<PeripheralRef<'d, AnyPin>>,
97 sda: Option<PeripheralRef<'d, AnyPin>>,
80 tx_dma: Option<ChannelAndRequest<'d>>, 98 tx_dma: Option<ChannelAndRequest<'d>>,
81 rx_dma: Option<ChannelAndRequest<'d>>, 99 rx_dma: Option<ChannelAndRequest<'d>>,
82 #[cfg(feature = "time")] 100 #[cfg(feature = "time")]
@@ -98,7 +116,15 @@ impl<'d> I2c<'d, Async> {
98 freq: Hertz, 116 freq: Hertz,
99 config: Config, 117 config: Config,
100 ) -> Self { 118 ) -> Self {
101 Self::new_inner(peri, scl, sda, new_dma!(tx_dma), new_dma!(rx_dma), freq, config) 119 Self::new_inner(
120 peri,
121 new_pin!(scl, AFType::OutputOpenDrain, Speed::Medium, config.scl_pull_mode()),
122 new_pin!(sda, AFType::OutputOpenDrain, Speed::Medium, config.sda_pull_mode()),
123 new_dma!(tx_dma),
124 new_dma!(rx_dma),
125 freq,
126 config,
127 )
102 } 128 }
103} 129}
104 130
@@ -111,7 +137,15 @@ impl<'d> I2c<'d, Blocking> {
111 freq: Hertz, 137 freq: Hertz,
112 config: Config, 138 config: Config,
113 ) -> Self { 139 ) -> Self {
114 Self::new_inner(peri, scl, sda, None, None, freq, config) 140 Self::new_inner(
141 peri,
142 new_pin!(scl, AFType::OutputOpenDrain, Speed::Medium, config.scl_pull_mode()),
143 new_pin!(sda, AFType::OutputOpenDrain, Speed::Medium, config.sda_pull_mode()),
144 None,
145 None,
146 freq,
147 config,
148 )
115 } 149 }
116} 150}
117 151
@@ -119,34 +153,13 @@ impl<'d, M: Mode> I2c<'d, M> {
119 /// Create a new I2C driver. 153 /// Create a new I2C driver.
120 fn new_inner<T: Instance>( 154 fn new_inner<T: Instance>(
121 _peri: impl Peripheral<P = T> + 'd, 155 _peri: impl Peripheral<P = T> + 'd,
122 scl: impl Peripheral<P = impl SclPin<T>> + 'd, 156 scl: Option<PeripheralRef<'d, AnyPin>>,
123 sda: impl Peripheral<P = impl SdaPin<T>> + 'd, 157 sda: Option<PeripheralRef<'d, AnyPin>>,
124 tx_dma: Option<ChannelAndRequest<'d>>, 158 tx_dma: Option<ChannelAndRequest<'d>>,
125 rx_dma: Option<ChannelAndRequest<'d>>, 159 rx_dma: Option<ChannelAndRequest<'d>>,
126 freq: Hertz, 160 freq: Hertz,
127 config: Config, 161 config: Config,
128 ) -> Self { 162 ) -> Self {
129 into_ref!(scl, sda);
130
131 T::enable_and_reset();
132
133 scl.set_as_af_pull(
134 scl.af_num(),
135 AFType::OutputOpenDrain,
136 match config.scl_pullup {
137 true => Pull::Up,
138 false => Pull::None,
139 },
140 );
141 sda.set_as_af_pull(
142 sda.af_num(),
143 AFType::OutputOpenDrain,
144 match config.sda_pullup {
145 true => Pull::Up,
146 false => Pull::None,
147 },
148 );
149
150 unsafe { T::EventInterrupt::enable() }; 163 unsafe { T::EventInterrupt::enable() };
151 unsafe { T::ErrorInterrupt::enable() }; 164 unsafe { T::ErrorInterrupt::enable() };
152 165
@@ -154,18 +167,23 @@ impl<'d, M: Mode> I2c<'d, M> {
154 info: T::info(), 167 info: T::info(),
155 state: T::state(), 168 state: T::state(),
156 kernel_clock: T::frequency(), 169 kernel_clock: T::frequency(),
170 scl,
171 sda,
157 tx_dma, 172 tx_dma,
158 rx_dma, 173 rx_dma,
159 #[cfg(feature = "time")] 174 #[cfg(feature = "time")]
160 timeout: config.timeout, 175 timeout: config.timeout,
161 _phantom: PhantomData, 176 _phantom: PhantomData,
162 }; 177 };
163 178 this.enable_and_init(freq, config);
164 this.init(freq, config);
165
166 this 179 this
167 } 180 }
168 181
182 fn enable_and_init(&mut self, freq: Hertz, config: Config) {
183 self.info.rcc.enable_and_reset();
184 self.init(freq, config);
185 }
186
169 fn timeout(&self) -> Timeout { 187 fn timeout(&self) -> Timeout {
170 Timeout { 188 Timeout {
171 #[cfg(feature = "time")] 189 #[cfg(feature = "time")]
@@ -174,6 +192,15 @@ impl<'d, M: Mode> I2c<'d, M> {
174 } 192 }
175} 193}
176 194
195impl<'d, M: Mode> Drop for I2c<'d, M> {
196 fn drop(&mut self) {
197 self.scl.as_ref().map(|x| x.set_as_disconnected());
198 self.sda.as_ref().map(|x| x.set_as_disconnected());
199
200 self.info.rcc.disable()
201 }
202}
203
177#[derive(Copy, Clone)] 204#[derive(Copy, Clone)]
178struct Timeout { 205struct Timeout {
179 #[cfg(feature = "time")] 206 #[cfg(feature = "time")]
@@ -224,7 +251,7 @@ impl State {
224 251
225struct Info { 252struct Info {
226 regs: crate::pac::i2c::I2c, 253 regs: crate::pac::i2c::I2c,
227 pub(crate) enable_bit: ClockEnableBit, 254 rcc: RccInfo,
228} 255}
229 256
230peri_trait!( 257peri_trait!(
@@ -265,7 +292,7 @@ foreach_peripheral!(
265 fn info() -> &'static Info { 292 fn info() -> &'static Info {
266 static INFO: Info = Info{ 293 static INFO: Info = Info{
267 regs: crate::pac::$inst, 294 regs: crate::pac::$inst,
268 enable_bit: crate::peripherals::$inst::ENABLE_BIT, 295 rcc: crate::peripherals::$inst::RCC_INFO,
269 }; 296 };
270 &INFO 297 &INFO
271 } 298 }
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index 0269e53aa..28026f83c 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -700,12 +700,6 @@ impl<'d> I2c<'d, Async> {
700 } 700 }
701} 701}
702 702
703impl<'d, M: PeriMode> Drop for I2c<'d, M> {
704 fn drop(&mut self) {
705 self.info.enable_bit.disable()
706 }
707}
708
709enum Mode { 703enum Mode {
710 Fast, 704 Fast,
711 Standard, 705 Standard,
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index aa6daf786..80163c287 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -671,12 +671,6 @@ impl<'d> I2c<'d, Async> {
671 } 671 }
672} 672}
673 673
674impl<'d, M: Mode> Drop for I2c<'d, M> {
675 fn drop(&mut self) {
676 self.info.enable_bit.disable();
677 }
678}
679
680/// I2C Stop Configuration 674/// I2C Stop Configuration
681/// 675///
682/// Peripheral options for generating the STOP condition 676/// Peripheral options for generating the STOP condition
diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs
index c78810a38..f893dd235 100644
--- a/embassy-stm32/src/i2s.rs
+++ b/embassy-stm32/src/i2s.rs
@@ -1,7 +1,9 @@
1//! Inter-IC Sound (I2S) 1//! Inter-IC Sound (I2S)
2
2use embassy_hal_internal::into_ref; 3use embassy_hal_internal::into_ref;
3 4
4use crate::gpio::{AFType, AnyPin, SealedPin}; 5use crate::dma::ChannelAndRequest;
6use crate::gpio::{AFType, AnyPin, SealedPin, Speed};
5use crate::mode::Async; 7use crate::mode::Async;
6use crate::pac::spi::vals; 8use crate::pac::spi::vals;
7use crate::spi::{Config as SpiConfig, *}; 9use crate::spi::{Config as SpiConfig, *};
@@ -17,15 +19,6 @@ pub enum Mode {
17 Slave, 19 Slave,
18} 20}
19 21
20/// I2S function
21#[derive(Copy, Clone)]
22pub enum Function {
23 /// Transmit audio data
24 Transmit,
25 /// Receive audio data
26 Receive,
27}
28
29/// I2C standard 22/// I2C standard
30#[derive(Copy, Clone)] 23#[derive(Copy, Clone)]
31pub enum Standard { 24pub enum Standard {
@@ -42,7 +35,7 @@ pub enum Standard {
42} 35}
43 36
44impl Standard { 37impl Standard {
45 #[cfg(any(spi_v1, spi_f1))] 38 #[cfg(any(spi_v1, spi_v3, spi_f1))]
46 const fn i2sstd(&self) -> vals::I2sstd { 39 const fn i2sstd(&self) -> vals::I2sstd {
47 match self { 40 match self {
48 Standard::Philips => vals::I2sstd::PHILIPS, 41 Standard::Philips => vals::I2sstd::PHILIPS,
@@ -53,7 +46,7 @@ impl Standard {
53 } 46 }
54 } 47 }
55 48
56 #[cfg(any(spi_v1, spi_f1))] 49 #[cfg(any(spi_v1, spi_v3, spi_f1))]
57 const fn pcmsync(&self) -> vals::Pcmsync { 50 const fn pcmsync(&self) -> vals::Pcmsync {
58 match self { 51 match self {
59 Standard::PcmLongSync => vals::Pcmsync::LONG, 52 Standard::PcmLongSync => vals::Pcmsync::LONG,
@@ -76,7 +69,7 @@ pub enum Format {
76} 69}
77 70
78impl Format { 71impl Format {
79 #[cfg(any(spi_v1, spi_f1))] 72 #[cfg(any(spi_v1, spi_v3, spi_f1))]
80 const fn datlen(&self) -> vals::Datlen { 73 const fn datlen(&self) -> vals::Datlen {
81 match self { 74 match self {
82 Format::Data16Channel16 => vals::Datlen::BITS16, 75 Format::Data16Channel16 => vals::Datlen::BITS16,
@@ -86,7 +79,7 @@ impl Format {
86 } 79 }
87 } 80 }
88 81
89 #[cfg(any(spi_v1, spi_f1))] 82 #[cfg(any(spi_v1, spi_v3, spi_f1))]
90 const fn chlen(&self) -> vals::Chlen { 83 const fn chlen(&self) -> vals::Chlen {
91 match self { 84 match self {
92 Format::Data16Channel16 => vals::Chlen::BITS16, 85 Format::Data16Channel16 => vals::Chlen::BITS16,
@@ -107,7 +100,7 @@ pub enum ClockPolarity {
107} 100}
108 101
109impl ClockPolarity { 102impl ClockPolarity {
110 #[cfg(any(spi_v1, spi_f1))] 103 #[cfg(any(spi_v1, spi_v3, spi_f1))]
111 const fn ckpol(&self) -> vals::Ckpol { 104 const fn ckpol(&self) -> vals::Ckpol {
112 match self { 105 match self {
113 ClockPolarity::IdleHigh => vals::Ckpol::IDLEHIGH, 106 ClockPolarity::IdleHigh => vals::Ckpol::IDLEHIGH,
@@ -127,15 +120,13 @@ impl ClockPolarity {
127pub struct Config { 120pub struct Config {
128 /// Mode 121 /// Mode
129 pub mode: Mode, 122 pub mode: Mode,
130 /// Function (transmit, receive)
131 pub function: Function,
132 /// Which I2S standard to use. 123 /// Which I2S standard to use.
133 pub standard: Standard, 124 pub standard: Standard,
134 /// Data format. 125 /// Data format.
135 pub format: Format, 126 pub format: Format,
136 /// Clock polarity. 127 /// Clock polarity.
137 pub clock_polarity: ClockPolarity, 128 pub clock_polarity: ClockPolarity,
138 /// True to eanble master clock output from this instance. 129 /// True to enable master clock output from this instance.
139 pub master_clock: bool, 130 pub master_clock: bool,
140} 131}
141 132
@@ -143,7 +134,6 @@ impl Default for Config {
143 fn default() -> Self { 134 fn default() -> Self {
144 Self { 135 Self {
145 mode: Mode::Master, 136 mode: Mode::Master,
146 function: Function::Transmit,
147 standard: Standard::Philips, 137 standard: Standard::Philips,
148 format: Format::Data16Channel16, 138 format: Format::Data16Channel16,
149 clock_polarity: ClockPolarity::IdleLow, 139 clock_polarity: ClockPolarity::IdleLow,
@@ -155,43 +145,169 @@ impl Default for Config {
155/// I2S driver. 145/// I2S driver.
156pub struct I2S<'d> { 146pub struct I2S<'d> {
157 _peri: Spi<'d, Async>, 147 _peri: Spi<'d, Async>,
158 sd: Option<PeripheralRef<'d, AnyPin>>, 148 txsd: Option<PeripheralRef<'d, AnyPin>>,
149 rxsd: Option<PeripheralRef<'d, AnyPin>>,
159 ws: Option<PeripheralRef<'d, AnyPin>>, 150 ws: Option<PeripheralRef<'d, AnyPin>>,
160 ck: Option<PeripheralRef<'d, AnyPin>>, 151 ck: Option<PeripheralRef<'d, AnyPin>>,
161 mck: Option<PeripheralRef<'d, AnyPin>>, 152 mck: Option<PeripheralRef<'d, AnyPin>>,
162} 153}
163 154
155/// I2S function
156#[derive(Copy, Clone)]
157#[allow(dead_code)]
158enum Function {
159 /// Transmit audio data
160 Transmit,
161 /// Receive audio data
162 Receive,
163 #[cfg(spi_v3)]
164 /// Transmit and Receive audio data
165 FullDuplex,
166}
167
164impl<'d> I2S<'d> { 168impl<'d> I2S<'d> {
165 /// Note: Full-Duplex modes are not supported at this time 169 /// Create a transmitter driver
166 pub fn new<T: Instance>( 170 pub fn new_txonly<T: Instance>(
167 peri: impl Peripheral<P = T> + 'd, 171 peri: impl Peripheral<P = T> + 'd,
168 sd: impl Peripheral<P = impl MosiPin<T>> + 'd, 172 sd: impl Peripheral<P = impl MosiPin<T>> + 'd,
169 ws: impl Peripheral<P = impl WsPin<T>> + 'd, 173 ws: impl Peripheral<P = impl WsPin<T>> + 'd,
170 ck: impl Peripheral<P = impl CkPin<T>> + 'd, 174 ck: impl Peripheral<P = impl CkPin<T>> + 'd,
171 mck: impl Peripheral<P = impl MckPin<T>> + 'd, 175 mck: impl Peripheral<P = impl MckPin<T>> + 'd,
172 txdma: impl Peripheral<P = impl TxDma<T>> + 'd, 176 txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
177 freq: Hertz,
178 config: Config,
179 ) -> Self {
180 into_ref!(sd);
181 Self::new_inner(
182 peri,
183 new_pin!(sd, AFType::OutputPushPull, Speed::VeryHigh),
184 None,
185 ws,
186 ck,
187 mck,
188 new_dma!(txdma),
189 None,
190 freq,
191 config,
192 Function::Transmit,
193 )
194 }
195
196 /// Create a receiver driver
197 pub fn new_rxonly<T: Instance>(
198 peri: impl Peripheral<P = T> + 'd,
199 sd: impl Peripheral<P = impl MisoPin<T>> + 'd,
200 ws: impl Peripheral<P = impl WsPin<T>> + 'd,
201 ck: impl Peripheral<P = impl CkPin<T>> + 'd,
202 mck: impl Peripheral<P = impl MckPin<T>> + 'd,
203 #[cfg(not(spi_v3))] txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
204 rxdma: impl Peripheral<P = impl RxDma<T>> + 'd,
205 freq: Hertz,
206 config: Config,
207 ) -> Self {
208 into_ref!(sd);
209 Self::new_inner(
210 peri,
211 None,
212 new_pin!(sd, AFType::OutputPushPull, Speed::VeryHigh),
213 ws,
214 ck,
215 mck,
216 #[cfg(not(spi_v3))]
217 new_dma!(txdma),
218 #[cfg(spi_v3)]
219 None,
220 new_dma!(rxdma),
221 freq,
222 config,
223 #[cfg(not(spi_v3))]
224 Function::Transmit,
225 #[cfg(spi_v3)]
226 Function::Receive,
227 )
228 }
229
230 #[cfg(spi_v3)]
231 /// Create a full duplex transmitter driver
232 pub fn new_full_duplex<T: Instance>(
233 peri: impl Peripheral<P = T> + 'd,
234 txsd: impl Peripheral<P = impl MosiPin<T>> + 'd,
235 rxsd: impl Peripheral<P = impl MisoPin<T>> + 'd,
236 ws: impl Peripheral<P = impl WsPin<T>> + 'd,
237 ck: impl Peripheral<P = impl CkPin<T>> + 'd,
238 mck: impl Peripheral<P = impl MckPin<T>> + 'd,
239 txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
173 rxdma: impl Peripheral<P = impl RxDma<T>> + 'd, 240 rxdma: impl Peripheral<P = impl RxDma<T>> + 'd,
174 freq: Hertz, 241 freq: Hertz,
175 config: Config, 242 config: Config,
176 ) -> Self { 243 ) -> Self {
177 into_ref!(sd, ws, ck, mck); 244 into_ref!(txsd, rxsd);
245 Self::new_inner(
246 peri,
247 new_pin!(txsd, AFType::OutputPushPull, Speed::VeryHigh),
248 new_pin!(rxsd, AFType::OutputPushPull, Speed::VeryHigh),
249 ws,
250 ck,
251 mck,
252 new_dma!(txdma),
253 new_dma!(rxdma),
254 freq,
255 config,
256 Function::FullDuplex,
257 )
258 }
259
260 /// Write audio data.
261 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
262 self._peri.read(data).await
263 }
264
265 /// Write audio data.
266 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> {
267 self._peri.write(data).await
268 }
269
270 /// Transfer audio data.
271 pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
272 self._peri.transfer(read, write).await
273 }
178 274
179 sd.set_as_af(sd.af_num(), AFType::OutputPushPull); 275 /// Transfer audio data in place.
180 sd.set_speed(crate::gpio::Speed::VeryHigh); 276 pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
277 self._peri.transfer_in_place(data).await
278 }
279
280 fn new_inner<T: Instance>(
281 peri: impl Peripheral<P = T> + 'd,
282 txsd: Option<PeripheralRef<'d, AnyPin>>,
283 rxsd: Option<PeripheralRef<'d, AnyPin>>,
284 ws: impl Peripheral<P = impl WsPin<T>> + 'd,
285 ck: impl Peripheral<P = impl CkPin<T>> + 'd,
286 mck: impl Peripheral<P = impl MckPin<T>> + 'd,
287 txdma: Option<ChannelAndRequest<'d>>,
288 rxdma: Option<ChannelAndRequest<'d>>,
289 freq: Hertz,
290 config: Config,
291 function: Function,
292 ) -> Self {
293 into_ref!(ws, ck, mck);
181 294
182 ws.set_as_af(ws.af_num(), AFType::OutputPushPull); 295 ws.set_as_af(ws.af_num(), AFType::OutputPushPull);
183 ws.set_speed(crate::gpio::Speed::VeryHigh); 296 ws.set_speed(Speed::VeryHigh);
184 297
185 ck.set_as_af(ck.af_num(), AFType::OutputPushPull); 298 ck.set_as_af(ck.af_num(), AFType::OutputPushPull);
186 ck.set_speed(crate::gpio::Speed::VeryHigh); 299 ck.set_speed(Speed::VeryHigh);
187 300
188 mck.set_as_af(mck.af_num(), AFType::OutputPushPull); 301 mck.set_as_af(mck.af_num(), AFType::OutputPushPull);
189 mck.set_speed(crate::gpio::Speed::VeryHigh); 302 mck.set_speed(Speed::VeryHigh);
190 303
191 let mut spi_cfg = SpiConfig::default(); 304 let mut spi_cfg = SpiConfig::default();
192 spi_cfg.frequency = freq; 305 spi_cfg.frequency = freq;
306
193 let spi = Spi::new_internal(peri, txdma, rxdma, spi_cfg); 307 let spi = Spi::new_internal(peri, txdma, rxdma, spi_cfg);
194 308
309 let regs = T::info().regs;
310
195 // TODO move i2s to the new mux infra. 311 // TODO move i2s to the new mux infra.
196 //#[cfg(all(rcc_f4, not(stm32f410)))] 312 //#[cfg(all(rcc_f4, not(stm32f410)))]
197 //let pclk = unsafe { get_freqs() }.plli2s1_q.unwrap(); 313 //let pclk = unsafe { get_freqs() }.plli2s1_q.unwrap();
@@ -200,26 +316,23 @@ impl<'d> I2S<'d> {
200 316
201 let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format); 317 let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format);
202 318
203 #[cfg(any(spi_v1, spi_f1))] 319 #[cfg(any(spi_v1, spi_v3, spi_f1))]
204 { 320 {
205 use stm32_metapac::spi::vals::{I2scfg, Odd}; 321 #[cfg(spi_v3)]
322 {
323 regs.cr1().modify(|w| w.set_spe(false));
206 324
207 // 1. Select the I2SDIV[7:0] bits in the SPI_I2SPR register to define the serial clock baud 325 reset_incompatible_bitfields::<T>();
208 // rate to reach the proper audio sample frequency. The ODD bit in the SPI_I2SPR 326 }
209 // register also has to be defined.
210 327
211 spi.info.regs.i2spr().modify(|w| { 328 use stm32_metapac::spi::vals::{I2scfg, Odd};
212 w.set_i2sdiv(div);
213 w.set_odd(match odd {
214 true => Odd::ODD,
215 false => Odd::EVEN,
216 });
217 329
218 w.set_mckoe(config.master_clock); 330 // 1. Select the I2SDIV[7:0] bits in the SPI_I2SPR/SPI_I2SCFGR register to define the serial clock baud
219 }); 331 // rate to reach the proper audio sample frequency. The ODD bit in the
332 // SPI_I2SPR/SPI_I2SCFGR register also has to be defined.
220 333
221 // 2. Select the CKPOL bit to define the steady level for the communication clock. Set the 334 // 2. Select the CKPOL bit to define the steady level for the communication clock. Set the
222 // MCKOE bit in the SPI_I2SPR register if the master clock MCK needs to be provided to 335 // MCKOE bit in the SPI_I2SPR/SPI_I2SCFGR register if the master clock MCK needs to be provided to
223 // the external DAC/ADC audio component (the I2SDIV and ODD values should be 336 // the external DAC/ADC audio component (the I2SDIV and ODD values should be
224 // computed depending on the state of the MCK output, for more details refer to 337 // computed depending on the state of the MCK output, for more details refer to
225 // Section 28.4.4: Clock generator). 338 // Section 28.4.4: Clock generator).
@@ -235,50 +348,72 @@ impl<'d> I2S<'d> {
235 348
236 // 5. The I2SE bit in SPI_I2SCFGR register must be set. 349 // 5. The I2SE bit in SPI_I2SCFGR register must be set.
237 350
238 spi.info.regs.i2scfgr().modify(|w| { 351 let clk_reg = {
352 #[cfg(any(spi_v1, spi_f1))]
353 {
354 regs.i2spr()
355 }
356 #[cfg(spi_v3)]
357 {
358 regs.i2scfgr()
359 }
360 };
361
362 clk_reg.modify(|w| {
363 w.set_i2sdiv(div);
364 w.set_odd(match odd {
365 true => Odd::ODD,
366 false => Odd::EVEN,
367 });
368
369 w.set_mckoe(config.master_clock);
370 });
371
372 regs.i2scfgr().modify(|w| {
239 w.set_ckpol(config.clock_polarity.ckpol()); 373 w.set_ckpol(config.clock_polarity.ckpol());
240 374
241 w.set_i2smod(true); 375 w.set_i2smod(true);
376
242 w.set_i2sstd(config.standard.i2sstd()); 377 w.set_i2sstd(config.standard.i2sstd());
243 w.set_pcmsync(config.standard.pcmsync()); 378 w.set_pcmsync(config.standard.pcmsync());
244 379
245 w.set_datlen(config.format.datlen()); 380 w.set_datlen(config.format.datlen());
246 w.set_chlen(config.format.chlen()); 381 w.set_chlen(config.format.chlen());
247 382
248 w.set_i2scfg(match (config.mode, config.function) { 383 w.set_i2scfg(match (config.mode, function) {
249 (Mode::Master, Function::Transmit) => I2scfg::MASTERTX, 384 (Mode::Master, Function::Transmit) => I2scfg::MASTERTX,
250 (Mode::Master, Function::Receive) => I2scfg::MASTERRX, 385 (Mode::Master, Function::Receive) => I2scfg::MASTERRX,
386 #[cfg(spi_v3)]
387 (Mode::Master, Function::FullDuplex) => I2scfg::MASTERFULLDUPLEX,
251 (Mode::Slave, Function::Transmit) => I2scfg::SLAVETX, 388 (Mode::Slave, Function::Transmit) => I2scfg::SLAVETX,
252 (Mode::Slave, Function::Receive) => I2scfg::SLAVERX, 389 (Mode::Slave, Function::Receive) => I2scfg::SLAVERX,
390 #[cfg(spi_v3)]
391 (Mode::Slave, Function::FullDuplex) => I2scfg::SLAVEFULLDUPLEX,
253 }); 392 });
254 393
255 w.set_i2se(true) 394 #[cfg(any(spi_v1, spi_f1))]
395 w.set_i2se(true);
256 }); 396 });
397
398 #[cfg(spi_v3)]
399 regs.cr1().modify(|w| w.set_spe(true));
257 } 400 }
258 401
259 Self { 402 Self {
260 _peri: spi, 403 _peri: spi,
261 sd: Some(sd.map_into()), 404 txsd: txsd.map(|w| w.map_into()),
405 rxsd: rxsd.map(|w| w.map_into()),
262 ws: Some(ws.map_into()), 406 ws: Some(ws.map_into()),
263 ck: Some(ck.map_into()), 407 ck: Some(ck.map_into()),
264 mck: Some(mck.map_into()), 408 mck: Some(mck.map_into()),
265 } 409 }
266 } 410 }
267
268 /// Write audio data.
269 pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> {
270 self._peri.write(data).await
271 }
272
273 /// Read audio data.
274 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
275 self._peri.read(data).await
276 }
277} 411}
278 412
279impl<'d> Drop for I2S<'d> { 413impl<'d> Drop for I2S<'d> {
280 fn drop(&mut self) { 414 fn drop(&mut self) {
281 self.sd.as_ref().map(|x| x.set_as_disconnected()); 415 self.txsd.as_ref().map(|x| x.set_as_disconnected());
416 self.rxsd.as_ref().map(|x| x.set_as_disconnected());
282 self.ws.as_ref().map(|x| x.set_as_disconnected()); 417 self.ws.as_ref().map(|x| x.set_as_disconnected());
283 self.ck.as_ref().map(|x| x.set_as_disconnected()); 418 self.ck.as_ref().map(|x| x.set_as_disconnected());
284 self.mck.as_ref().map(|x| x.set_as_disconnected()); 419 self.mck.as_ref().map(|x| x.set_as_disconnected());
@@ -320,3 +455,71 @@ fn compute_baud_rate(i2s_clock: Hertz, request_freq: Hertz, mclk: bool, data_for
320 ((division & 1) == 1, (division >> 1) as u8) 455 ((division & 1) == 1, (division >> 1) as u8)
321 } 456 }
322} 457}
458
459#[cfg(spi_v3)]
460// The STM32H7 reference manual specifies that any incompatible bitfields should be reset
461// to their reset values while operating in I2S mode.
462fn reset_incompatible_bitfields<T: Instance>() {
463 let regs = T::info().regs;
464 regs.cr1().modify(|w| {
465 let iolock = w.iolock();
466 let csusp = w.csusp();
467 let spe = w.cstart();
468 let cstart = w.cstart();
469 w.0 = 0;
470 w.set_iolock(iolock);
471 w.set_csusp(csusp);
472 w.set_spe(spe);
473 w.set_cstart(cstart);
474 });
475
476 regs.cr2().write(|w| w.0 = 0);
477
478 regs.cfg1().modify(|w| {
479 let txdmaen = w.txdmaen();
480 let rxdmaen = w.rxdmaen();
481 let fthlv = w.fthlv();
482 w.0 = 0;
483 w.set_txdmaen(txdmaen);
484 w.set_rxdmaen(rxdmaen);
485 w.set_fthlv(fthlv);
486 });
487
488 regs.cfg2().modify(|w| {
489 let afcntr = w.afcntr();
490 let lsbfirst = w.lsbfirst();
491 let ioswp = w.ioswp();
492 w.0 = 0;
493 w.set_afcntr(afcntr);
494 w.set_lsbfirst(lsbfirst);
495 w.set_ioswp(ioswp);
496 });
497
498 regs.ier().modify(|w| {
499 let tifreie = w.tifreie();
500 let ovrie = w.ovrie();
501 let udrie = w.udrie();
502 let txpie = w.txpie();
503 let rxpie = w.rxpie();
504
505 w.0 = 0;
506
507 w.set_tifreie(tifreie);
508 w.set_ovrie(ovrie);
509 w.set_udrie(udrie);
510 w.set_txpie(txpie);
511 w.set_rxpie(rxpie);
512 });
513
514 regs.ifcr().write(|w| {
515 w.set_suspc(true);
516 w.set_tifrec(true);
517 w.set_ovrc(true);
518 w.set_udrc(true);
519 });
520
521 regs.crcpoly().write(|w| w.0 = 0x107);
522 regs.txcrc().write(|w| w.0 = 0);
523 regs.rxcrc().write(|w| w.0 = 0);
524 regs.udrdr().write(|w| w.0 = 0);
525}
diff --git a/embassy-stm32/src/ipcc.rs b/embassy-stm32/src/ipcc.rs
index 4d535cce2..6c8347311 100644
--- a/embassy-stm32/src/ipcc.rs
+++ b/embassy-stm32/src/ipcc.rs
@@ -6,10 +6,9 @@ use core::task::Poll;
6 6
7use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
8 8
9use crate::interrupt;
10use crate::interrupt::typelevel::Interrupt; 9use crate::interrupt::typelevel::Interrupt;
11use crate::peripherals::IPCC; 10use crate::peripherals::IPCC;
12use crate::rcc::SealedRccPeripheral; 11use crate::{interrupt, rcc};
13 12
14/// Interrupt handler. 13/// Interrupt handler.
15pub struct ReceiveInterruptHandler {} 14pub struct ReceiveInterruptHandler {}
@@ -102,7 +101,7 @@ pub struct Ipcc;
102impl Ipcc { 101impl Ipcc {
103 /// Enable IPCC. 102 /// Enable IPCC.
104 pub fn enable(_config: Config) { 103 pub fn enable(_config: Config) {
105 IPCC::enable_and_reset(); 104 rcc::enable_and_reset::<IPCC>();
106 IPCC::set_cpu2(true); 105 IPCC::set_cpu2(true);
107 106
108 // set RF wake-up clock = LSE 107 // set RF wake-up clock = LSE
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 81ee60c1c..95f59360a 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -83,7 +83,7 @@ pub mod hrtim;
83pub mod hsem; 83pub mod hsem;
84#[cfg(i2c)] 84#[cfg(i2c)]
85pub mod i2c; 85pub mod i2c;
86#[cfg(all(spi_v1, rcc_f4))] 86#[cfg(any(all(spi_v1, rcc_f4), spi_v3))]
87pub mod i2s; 87pub mod i2s;
88#[cfg(stm32wb)] 88#[cfg(stm32wb)]
89pub mod ipcc; 89pub mod ipcc;
@@ -194,7 +194,6 @@ pub(crate) use stm32_metapac as pac;
194use crate::interrupt::Priority; 194use crate::interrupt::Priority;
195#[cfg(feature = "rt")] 195#[cfg(feature = "rt")]
196pub use crate::pac::NVIC_PRIO_BITS; 196pub use crate::pac::NVIC_PRIO_BITS;
197use crate::rcc::SealedRccPeripheral;
198 197
199/// `embassy-stm32` global configuration. 198/// `embassy-stm32` global configuration.
200#[non_exhaustive] 199#[non_exhaustive]
@@ -310,11 +309,11 @@ pub fn init(config: Config) -> Peripherals {
310 }); 309 });
311 310
312 #[cfg(not(any(stm32f1, stm32wb, stm32wl)))] 311 #[cfg(not(any(stm32f1, stm32wb, stm32wl)))]
313 peripherals::SYSCFG::enable_and_reset_with_cs(cs); 312 rcc::enable_and_reset_with_cs::<peripherals::SYSCFG>(cs);
314 #[cfg(not(any(stm32h5, stm32h7, stm32h7rs, stm32wb, stm32wl)))] 313 #[cfg(not(any(stm32h5, stm32h7, stm32h7rs, stm32wb, stm32wl)))]
315 peripherals::PWR::enable_and_reset_with_cs(cs); 314 rcc::enable_and_reset_with_cs::<peripherals::PWR>(cs);
316 #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7, stm32h7rs)))] 315 #[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7, stm32h7rs)))]
317 peripherals::FLASH::enable_and_reset_with_cs(cs); 316 rcc::enable_and_reset_with_cs::<peripherals::FLASH>(cs);
318 317
319 // Enable the VDDIO2 power supply on chips that have it. 318 // Enable the VDDIO2 power supply on chips that have it.
320 // Note that this requires the PWR peripheral to be enabled first. 319 // Note that this requires the PWR peripheral to be enabled first.
diff --git a/embassy-stm32/src/ltdc.rs b/embassy-stm32/src/ltdc.rs
index 0cc8a0557..c262e7a0c 100644
--- a/embassy-stm32/src/ltdc.rs
+++ b/embassy-stm32/src/ltdc.rs
@@ -1,7 +1,7 @@
1//! LTDC 1//! LTDC
2use core::marker::PhantomData; 2use core::marker::PhantomData;
3 3
4use crate::rcc::RccPeripheral; 4use crate::rcc::{self, RccPeripheral};
5use crate::{peripherals, Peripheral}; 5use crate::{peripherals, Peripheral};
6 6
7/// LTDC driver. 7/// LTDC driver.
@@ -60,7 +60,7 @@ impl<'d, T: Instance> Ltdc<'d, T> {
60 .modify(|w| w.set_pllsaidivr(stm32_metapac::rcc::vals::Pllsaidivr::DIV2)); 60 .modify(|w| w.set_pllsaidivr(stm32_metapac::rcc::vals::Pllsaidivr::DIV2));
61 }); 61 });
62 62
63 T::enable_and_reset(); 63 rcc::enable_and_reset::<T>();
64 64
65 //new_pin!(clk, AFType::OutputPushPull, Speed::VeryHigh, Pull::None); 65 //new_pin!(clk, AFType::OutputPushPull, Speed::VeryHigh, Pull::None);
66 66
@@ -93,7 +93,7 @@ impl<'d, T: Instance> Drop for Ltdc<'d, T> {
93} 93}
94 94
95trait SealedInstance: crate::rcc::SealedRccPeripheral { 95trait SealedInstance: crate::rcc::SealedRccPeripheral {
96 fn regs() -> &'static crate::pac::ltdc::Ltdc; 96 fn regs() -> crate::pac::ltdc::Ltdc;
97} 97}
98 98
99/// DSI instance trait. 99/// DSI instance trait.
@@ -132,8 +132,8 @@ pin_trait!(B7Pin, Instance);
132foreach_peripheral!( 132foreach_peripheral!(
133 (ltdc, $inst:ident) => { 133 (ltdc, $inst:ident) => {
134 impl crate::ltdc::SealedInstance for peripherals::$inst { 134 impl crate::ltdc::SealedInstance for peripherals::$inst {
135 fn regs() -> &'static crate::pac::ltdc::Ltdc { 135 fn regs() -> crate::pac::ltdc::Ltdc {
136 &crate::pac::$inst 136 crate::pac::$inst
137 } 137 }
138 } 138 }
139 139
diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs
index 487902959..ca94a573d 100644
--- a/embassy-stm32/src/opamp.rs
+++ b/embassy-stm32/src/opamp.rs
@@ -110,6 +110,32 @@ impl<'d, T: Instance> OpAmp<'d, T> {
110 110
111 OpAmpOutput { _inner: self } 111 OpAmpOutput { _inner: self }
112 } 112 }
113 /// Configure the OpAmp as a buffer for the DAC it is connected to,
114 /// outputting to the provided output pin, and enable the opamp.
115 ///
116 /// The output pin is held within the returned [`OpAmpOutput`] struct,
117 /// preventing it being used elsewhere. The `OpAmpOutput` can then be
118 /// directly used as an ADC input. The opamp will be disabled when the
119 /// [`OpAmpOutput`] is dropped.
120 #[cfg(opamp_g4)]
121 pub fn buffer_dac(
122 &'d mut self,
123 out_pin: impl Peripheral<P = impl OutputPin<T> + crate::gpio::Pin> + 'd,
124 ) -> OpAmpOutput<'d, T> {
125 into_ref!(out_pin);
126 out_pin.set_as_analog();
127
128 T::regs().csr().modify(|w| {
129 use crate::pac::opamp::vals::*;
130
131 w.set_vm_sel(VmSel::OUTPUT);
132 w.set_vp_sel(VpSel::DAC3_CH1);
133 w.set_opaintoen(Opaintoen::OUTPUTPIN);
134 w.set_opampen(true);
135 });
136
137 OpAmpOutput { _inner: self }
138 }
113 139
114 /// Configure the OpAmp as a buffer for the provided input pin, 140 /// Configure the OpAmp as a buffer for the provided input pin,
115 /// with the output only used internally, and enable the opamp. 141 /// with the output only used internally, and enable the opamp.
diff --git a/embassy-stm32/src/ospi/mod.rs b/embassy-stm32/src/ospi/mod.rs
index 536da4ca0..882781cce 100644
--- a/embassy-stm32/src/ospi/mod.rs
+++ b/embassy-stm32/src/ospi/mod.rs
@@ -16,7 +16,7 @@ use crate::dma::{word, ChannelAndRequest};
16use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed}; 16use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed};
17use crate::mode::{Async, Blocking, Mode as PeriMode}; 17use crate::mode::{Async, Blocking, Mode as PeriMode};
18use crate::pac::octospi::{vals, Octospi as Regs}; 18use crate::pac::octospi::{vals, Octospi as Regs};
19use crate::rcc::RccPeripheral; 19use crate::rcc::{self, RccPeripheral};
20use crate::{peripherals, Peripheral}; 20use crate::{peripherals, Peripheral};
21 21
22/// OPSI driver config. 22/// OPSI driver config.
@@ -198,7 +198,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
198 into_ref!(peri); 198 into_ref!(peri);
199 199
200 // System configuration 200 // System configuration
201 T::enable_and_reset(); 201 rcc::enable_and_reset::<T>();
202 while T::REGS.sr().read().busy() {} 202 while T::REGS.sr().read().busy() {}
203 203
204 // Device configuration 204 // Device configuration
@@ -1013,7 +1013,7 @@ impl<'d, T: Instance, M: PeriMode> Drop for Ospi<'d, T, M> {
1013 self.nss.as_ref().map(|x| x.set_as_disconnected()); 1013 self.nss.as_ref().map(|x| x.set_as_disconnected());
1014 self.dqs.as_ref().map(|x| x.set_as_disconnected()); 1014 self.dqs.as_ref().map(|x| x.set_as_disconnected());
1015 1015
1016 T::disable(); 1016 rcc::disable::<T>();
1017 } 1017 }
1018} 1018}
1019 1019
diff --git a/embassy-stm32/src/qspi/mod.rs b/embassy-stm32/src/qspi/mod.rs
index a82e93b5b..06c8f4812 100644
--- a/embassy-stm32/src/qspi/mod.rs
+++ b/embassy-stm32/src/qspi/mod.rs
@@ -13,7 +13,7 @@ use crate::dma::ChannelAndRequest;
13use crate::gpio::{AFType, AnyPin, Pull, Speed}; 13use crate::gpio::{AFType, AnyPin, Pull, Speed};
14use crate::mode::{Async, Blocking, Mode as PeriMode}; 14use crate::mode::{Async, Blocking, Mode as PeriMode};
15use crate::pac::quadspi::Quadspi as Regs; 15use crate::pac::quadspi::Quadspi as Regs;
16use crate::rcc::RccPeripheral; 16use crate::rcc::{self, RccPeripheral};
17use crate::{peripherals, Peripheral}; 17use crate::{peripherals, Peripheral};
18 18
19/// QSPI transfer configuration. 19/// QSPI transfer configuration.
@@ -102,7 +102,7 @@ impl<'d, T: Instance, M: PeriMode> Qspi<'d, T, M> {
102 ) -> Self { 102 ) -> Self {
103 into_ref!(peri); 103 into_ref!(peri);
104 104
105 T::enable_and_reset(); 105 rcc::enable_and_reset::<T>();
106 106
107 while T::REGS.sr().read().busy() {} 107 while T::REGS.sr().read().busy() {}
108 108
diff --git a/embassy-stm32/src/rcc/bd.rs b/embassy-stm32/src/rcc/bd.rs
index f3ac4fdbe..4e9c18594 100644
--- a/embassy-stm32/src/rcc/bd.rs
+++ b/embassy-stm32/src/rcc/bd.rs
@@ -33,7 +33,7 @@ pub enum LseDrive {
33} 33}
34 34
35// All families but these have the LSEDRV register 35// All families but these have the LSEDRV register
36#[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f400, rcc_f410, rcc_l1)))] 36#[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1)))]
37impl From<LseDrive> for crate::pac::rcc::vals::Lsedrv { 37impl From<LseDrive> for crate::pac::rcc::vals::Lsedrv {
38 fn from(value: LseDrive) -> Self { 38 fn from(value: LseDrive) -> Self {
39 use crate::pac::rcc::vals::Lsedrv; 39 use crate::pac::rcc::vals::Lsedrv;
@@ -186,7 +186,7 @@ impl LsConfig {
186 } 186 }
187 ok &= reg.lseon() == lse_en; 187 ok &= reg.lseon() == lse_en;
188 ok &= reg.lsebyp() == lse_byp; 188 ok &= reg.lsebyp() == lse_byp;
189 #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f400, rcc_f410, rcc_l1)))] 189 #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1)))]
190 if let Some(lse_drv) = lse_drv { 190 if let Some(lse_drv) = lse_drv {
191 ok &= reg.lsedrv() == lse_drv.into(); 191 ok &= reg.lsedrv() == lse_drv.into();
192 } 192 }
@@ -224,7 +224,7 @@ impl LsConfig {
224 224
225 if lse_en { 225 if lse_en {
226 bdcr().modify(|w| { 226 bdcr().modify(|w| {
227 #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f400, rcc_f410, rcc_l1)))] 227 #[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1)))]
228 if let Some(lse_drv) = lse_drv { 228 if let Some(lse_drv) = lse_drv {
229 w.set_lsedrv(lse_drv.into()); 229 w.set_lsedrv(lse_drv.into());
230 } 230 }
diff --git a/embassy-stm32/src/rcc/f013.rs b/embassy-stm32/src/rcc/f013.rs
index 0946287ea..63dc27bdd 100644
--- a/embassy-stm32/src/rcc/f013.rs
+++ b/embassy-stm32/src/rcc/f013.rs
@@ -95,7 +95,7 @@ pub struct Config {
95 95
96 #[cfg(all(stm32f3, not(rcc_f37)))] 96 #[cfg(all(stm32f3, not(rcc_f37)))]
97 pub adc: AdcClockSource, 97 pub adc: AdcClockSource,
98 #[cfg(all(stm32f3, not(rcc_f37), adc3_common))] 98 #[cfg(all(stm32f3, not(rcc_f37), any(peri_adc3_common, peri_adc34_common)))]
99 pub adc34: AdcClockSource, 99 pub adc34: AdcClockSource,
100 100
101 /// Per-peripheral kernel clock selection muxes 101 /// Per-peripheral kernel clock selection muxes
@@ -125,7 +125,7 @@ impl Default for Config {
125 125
126 #[cfg(all(stm32f3, not(rcc_f37)))] 126 #[cfg(all(stm32f3, not(rcc_f37)))]
127 adc: AdcClockSource::Hclk(AdcHclkPrescaler::Div1), 127 adc: AdcClockSource::Hclk(AdcHclkPrescaler::Div1),
128 #[cfg(all(stm32f3, not(rcc_f37), adc3_common))] 128 #[cfg(all(stm32f3, not(rcc_f37), any(peri_adc3_common, peri_adc34_common)))]
129 adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1), 129 adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1),
130 130
131 mux: Default::default(), 131 mux: Default::default(),
@@ -276,7 +276,7 @@ pub(crate) unsafe fn init(config: Config) {
276 276
277 // Set prescalers 277 // Set prescalers
278 // CFGR has been written before (PLL, PLL48) don't overwrite these settings 278 // CFGR has been written before (PLL, PLL48) don't overwrite these settings
279 RCC.cfgr().modify(|w: &mut stm32_metapac::rcc::regs::Cfgr| { 279 RCC.cfgr().modify(|w| {
280 #[cfg(not(stm32f0))] 280 #[cfg(not(stm32f0))]
281 { 281 {
282 w.set_ppre1(config.apb1_pre); 282 w.set_ppre1(config.apb1_pre);
@@ -339,7 +339,7 @@ pub(crate) unsafe fn init(config: Config) {
339 } 339 }
340 }; 340 };
341 341
342 #[cfg(all(stm32f3, not(rcc_f37), adc3_common))] 342 #[cfg(all(stm32f3, not(rcc_f37), any(peri_adc3_common, peri_adc34_common)))]
343 let adc34 = { 343 let adc34 = {
344 #[cfg(peri_adc3_common)] 344 #[cfg(peri_adc3_common)]
345 let common = crate::pac::ADC3_COMMON; 345 let common = crate::pac::ADC3_COMMON;
@@ -404,7 +404,7 @@ pub(crate) unsafe fn init(config: Config) {
404 hclk1: Some(hclk), 404 hclk1: Some(hclk),
405 #[cfg(all(stm32f3, not(rcc_f37)))] 405 #[cfg(all(stm32f3, not(rcc_f37)))]
406 adc: Some(adc), 406 adc: Some(adc),
407 #[cfg(all(stm32f3, not(rcc_f37), adc3_common))] 407 #[cfg(all(stm32f3, not(rcc_f37), any(peri_adc3_common, peri_adc34_common)))]
408 adc34: Some(adc34), 408 adc34: Some(adc34),
409 rtc: rtc, 409 rtc: rtc,
410 hsi48: hsi48, 410 hsi48: hsi48,
diff --git a/embassy-stm32/src/rcc/hsi48.rs b/embassy-stm32/src/rcc/hsi48.rs
index da81abc34..efabd059f 100644
--- a/embassy-stm32/src/rcc/hsi48.rs
+++ b/embassy-stm32/src/rcc/hsi48.rs
@@ -2,7 +2,7 @@
2 2
3use crate::pac::crs::vals::Syncsrc; 3use crate::pac::crs::vals::Syncsrc;
4use crate::pac::{CRS, RCC}; 4use crate::pac::{CRS, RCC};
5use crate::rcc::SealedRccPeripheral; 5use crate::rcc::{self, SealedRccPeripheral};
6use crate::time::Hertz; 6use crate::time::Hertz;
7 7
8/// HSI48 speed 8/// HSI48 speed
@@ -44,7 +44,7 @@ pub(crate) fn init_hsi48(config: Hsi48Config) -> Hertz {
44 while r.read().hsi48rdy() == false {} 44 while r.read().hsi48rdy() == false {}
45 45
46 if config.sync_from_usb { 46 if config.sync_from_usb {
47 crate::peripherals::CRS::enable_and_reset(); 47 rcc::enable_and_reset::<crate::peripherals::CRS>();
48 48
49 CRS.cfgr().modify(|w| { 49 CRS.cfgr().modify(|w| {
50 w.set_syncsrc(Syncsrc::USB); 50 w.set_syncsrc(Syncsrc::USB);
diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs
index 28816256c..0bf344c40 100644
--- a/embassy-stm32/src/rcc/mod.rs
+++ b/embassy-stm32/src/rcc/mod.rs
@@ -67,23 +67,185 @@ pub(crate) unsafe fn get_freqs() -> &'static Clocks {
67} 67}
68 68
69pub(crate) trait SealedRccPeripheral { 69pub(crate) trait SealedRccPeripheral {
70 const ENABLE_BIT: ClockEnableBit;
71
72 fn frequency() -> Hertz; 70 fn frequency() -> Hertz;
73 fn enable_and_reset_with_cs(cs: CriticalSection); 71 const RCC_INFO: RccInfo;
74 fn disable_with_cs(cs: CriticalSection);
75
76 fn enable_and_reset() {
77 critical_section::with(|cs| Self::enable_and_reset_with_cs(cs))
78 }
79 fn disable() {
80 critical_section::with(|cs| Self::disable_with_cs(cs))
81 }
82} 72}
83 73
84#[allow(private_bounds)] 74#[allow(private_bounds)]
85pub trait RccPeripheral: SealedRccPeripheral + 'static {} 75pub trait RccPeripheral: SealedRccPeripheral + 'static {}
86 76
77/// Runtime information necessary to reset, enable and disable a peripheral.
78pub(crate) struct RccInfo {
79 /// Offset in 32-bit words of the xxxRSTR register into the RCC register block, or 0xff if the
80 /// peripheral has no reset bit (we don't use an `Option` to save one byte of storage).
81 reset_offset_or_0xff: u8,
82 /// Position of the xxxRST bit within the xxxRSTR register (0..=31).
83 reset_bit: u8,
84 /// Offset in 32-bit words of the xxxENR register into the RCC register block.
85 enable_offset: u8,
86 /// Position of the xxxEN bit within the xxxENR register (0..=31).
87 enable_bit: u8,
88 /// If this peripheral shares the same xxxRSTR bit and xxxEN bit with other peripherals, we
89 /// maintain a refcount in `crate::_generated::REFCOUNTS` at this index. If the bit is not
90 /// shared, this is 0xff (we don't use an `Option` to save one byte of storage).
91 refcount_idx_or_0xff: u8,
92 /// Stop mode of the peripheral, used to maintain `REFCOUNT_STOP1` and `REFCOUNT_STOP2`.
93 #[cfg(feature = "low-power")]
94 stop_mode: StopMode,
95}
96
97#[cfg(feature = "low-power")]
98#[allow(dead_code)]
99pub(crate) enum StopMode {
100 Standby,
101 Stop2,
102 Stop1,
103}
104
105impl RccInfo {
106 /// Safety:
107 /// - `reset_offset_and_bit`, if set, must correspond to valid xxxRST bit
108 /// - `enable_offset_and_bit` must correspond to valid xxxEN bit
109 /// - `refcount_idx`, if set, must correspond to valid refcount in `_generated::REFCOUNTS`
110 /// - `stop_mode` must be valid
111 pub(crate) const unsafe fn new(
112 reset_offset_and_bit: Option<(u8, u8)>,
113 enable_offset_and_bit: (u8, u8),
114 refcount_idx: Option<u8>,
115 #[cfg(feature = "low-power")] stop_mode: StopMode,
116 ) -> Self {
117 let (reset_offset_or_0xff, reset_bit) = match reset_offset_and_bit {
118 Some((offset, bit)) => (offset, bit),
119 None => (0xff, 0xff),
120 };
121 let (enable_offset, enable_bit) = enable_offset_and_bit;
122 let refcount_idx_or_0xff = match refcount_idx {
123 Some(idx) => idx,
124 None => 0xff,
125 };
126 Self {
127 reset_offset_or_0xff,
128 reset_bit,
129 enable_offset,
130 enable_bit,
131 refcount_idx_or_0xff,
132 #[cfg(feature = "low-power")]
133 stop_mode,
134 }
135 }
136
137 // TODO: should this be `unsafe`?
138 pub(crate) fn enable_and_reset_with_cs(&self, _cs: CriticalSection) {
139 if self.refcount_idx_or_0xff != 0xff {
140 let refcount_idx = self.refcount_idx_or_0xff as usize;
141 unsafe {
142 crate::_generated::REFCOUNTS[refcount_idx] += 1;
143 }
144 if unsafe { crate::_generated::REFCOUNTS[refcount_idx] } > 1 {
145 return;
146 }
147 }
148
149 #[cfg(feature = "low-power")]
150 match self.stop_mode {
151 StopMode::Standby => {}
152 StopMode::Stop2 => unsafe {
153 REFCOUNT_STOP2 += 1;
154 },
155 StopMode::Stop1 => unsafe {
156 REFCOUNT_STOP1 += 1;
157 },
158 }
159
160 // set the xxxRST bit
161 let reset_ptr = self.reset_ptr();
162 if let Some(reset_ptr) = reset_ptr {
163 unsafe {
164 let val = reset_ptr.read_volatile();
165 reset_ptr.write_volatile(val | 1u32 << self.reset_bit);
166 }
167 }
168
169 // set the xxxEN bit
170 let enable_ptr = self.enable_ptr();
171 unsafe {
172 let val = enable_ptr.read_volatile();
173 enable_ptr.write_volatile(val | 1u32 << self.enable_bit);
174 }
175
176 // we must wait two peripheral clock cycles before the clock is active
177 // this seems to work, but might be incorrect
178 // see http://efton.sk/STM32/gotcha/g183.html
179
180 // dummy read (like in the ST HALs)
181 let _ = unsafe { enable_ptr.read_volatile() };
182
183 // DSB for good measure
184 cortex_m::asm::dsb();
185
186 // clear the xxxRST bit
187 if let Some(reset_ptr) = reset_ptr {
188 unsafe {
189 let val = reset_ptr.read_volatile();
190 reset_ptr.write_volatile(val & !(1u32 << self.reset_bit));
191 }
192 }
193 }
194
195 // TODO: should this be `unsafe`?
196 pub(crate) fn disable_with_cs(&self, _cs: CriticalSection) {
197 if self.refcount_idx_or_0xff != 0xff {
198 let refcount_idx = self.refcount_idx_or_0xff as usize;
199 unsafe {
200 crate::_generated::REFCOUNTS[refcount_idx] -= 1;
201 }
202 if unsafe { crate::_generated::REFCOUNTS[refcount_idx] } > 0 {
203 return;
204 }
205 }
206
207 #[cfg(feature = "low-power")]
208 match self.stop_mode {
209 StopMode::Standby => {}
210 StopMode::Stop2 => unsafe {
211 REFCOUNT_STOP2 -= 1;
212 },
213 StopMode::Stop1 => unsafe {
214 REFCOUNT_STOP1 -= 1;
215 },
216 }
217
218 // clear the xxxEN bit
219 let enable_ptr = self.enable_ptr();
220 unsafe {
221 let val = enable_ptr.read_volatile();
222 enable_ptr.write_volatile(val & !(1u32 << self.enable_bit));
223 }
224 }
225
226 // TODO: should this be `unsafe`?
227 pub(crate) fn enable_and_reset(&self) {
228 critical_section::with(|cs| self.enable_and_reset_with_cs(cs))
229 }
230
231 // TODO: should this be `unsafe`?
232 pub(crate) fn disable(&self) {
233 critical_section::with(|cs| self.disable_with_cs(cs))
234 }
235
236 fn reset_ptr(&self) -> Option<*mut u32> {
237 if self.reset_offset_or_0xff != 0xff {
238 Some(unsafe { (RCC.as_ptr() as *mut u32).add(self.reset_offset_or_0xff as _) })
239 } else {
240 None
241 }
242 }
243
244 fn enable_ptr(&self) -> *mut u32 {
245 unsafe { (RCC.as_ptr() as *mut u32).add(self.enable_offset as _) }
246 }
247}
248
87#[allow(unused)] 249#[allow(unused)]
88mod util { 250mod util {
89 use crate::time::Hertz; 251 use crate::time::Hertz;
@@ -128,8 +290,9 @@ pub fn frequency<T: RccPeripheral>() -> Hertz {
128/// # Safety 290/// # Safety
129/// 291///
130/// Peripheral must not be in use. 292/// Peripheral must not be in use.
131pub unsafe fn enable_and_reset<T: RccPeripheral>() { 293// TODO: should this be `unsafe`?
132 T::enable_and_reset(); 294pub fn enable_and_reset_with_cs<T: RccPeripheral>(cs: CriticalSection) {
295 T::RCC_INFO.enable_and_reset_with_cs(cs);
133} 296}
134 297
135/// Disables peripheral `T`. 298/// Disables peripheral `T`.
@@ -137,52 +300,27 @@ pub unsafe fn enable_and_reset<T: RccPeripheral>() {
137/// # Safety 300/// # Safety
138/// 301///
139/// Peripheral must not be in use. 302/// Peripheral must not be in use.
140pub unsafe fn disable<T: RccPeripheral>() { 303// TODO: should this be `unsafe`?
141 T::disable(); 304pub fn disable_with_cs<T: RccPeripheral>(cs: CriticalSection) {
305 T::RCC_INFO.disable_with_cs(cs);
142} 306}
143 307
144/// Struct representing some clock enable bit (xxxENR.xxEN), only known at runtime. 308/// Enables and resets peripheral `T`.
145#[derive(Clone, Copy)] 309///
146pub(crate) struct ClockEnableBit { 310/// # Safety
147 /// offset in 32bit words of the xxxENR register into the RCC register block. 311///
148 offset: u8, 312/// Peripheral must not be in use.
149 /// bit within the register (0..=31) 313// TODO: should this be `unsafe`?
150 bit: u8, 314pub fn enable_and_reset<T: RccPeripheral>() {
315 T::RCC_INFO.enable_and_reset();
151} 316}
152 317
153impl ClockEnableBit { 318/// Disables peripheral `T`.
154 /// Safety: offset+bit must correspond to a valid xxxEN bit. 319///
155 pub(crate) const unsafe fn new(offset: u8, bit: u8) -> Self { 320/// # Safety
156 Self { offset, bit } 321///
157 } 322/// Peripheral must not be in use.
158 323// TODO: should this be `unsafe`?
159 fn ptr(self) -> *mut u32 { 324pub fn disable<T: RccPeripheral>() {
160 unsafe { (RCC.as_ptr() as *mut u32).add(self.offset as _) } 325 T::RCC_INFO.disable();
161 }
162
163 #[allow(unused)]
164 pub(crate) fn enable_with_cs(self, _cs: CriticalSection) {
165 let p = self.ptr();
166 unsafe {
167 let val = p.read_volatile();
168 p.write_volatile(val | 1u32 << self.bit);
169 }
170 }
171
172 pub(crate) fn disable_with_cs(self, _cs: CriticalSection) {
173 let p = self.ptr();
174 unsafe {
175 let val = p.read_volatile();
176 p.write_volatile(val & !(1u32 << self.bit));
177 }
178 }
179
180 #[allow(unused)]
181 pub(crate) fn enable(self) {
182 critical_section::with(|cs| self.enable_with_cs(cs))
183 }
184
185 pub(crate) fn disable(self) {
186 critical_section::with(|cs| self.disable_with_cs(cs))
187 }
188} 326}
diff --git a/embassy-stm32/src/rng.rs b/embassy-stm32/src/rng.rs
index 7a228e4a4..94491c32f 100644
--- a/embassy-stm32/src/rng.rs
+++ b/embassy-stm32/src/rng.rs
@@ -10,7 +10,7 @@ use embassy_sync::waitqueue::AtomicWaker;
10use rand_core::{CryptoRng, RngCore}; 10use rand_core::{CryptoRng, RngCore};
11 11
12use crate::interrupt::typelevel::Interrupt; 12use crate::interrupt::typelevel::Interrupt;
13use crate::{interrupt, pac, peripherals, Peripheral}; 13use crate::{interrupt, pac, peripherals, rcc, Peripheral};
14 14
15static RNG_WAKER: AtomicWaker = AtomicWaker::new(); 15static RNG_WAKER: AtomicWaker = AtomicWaker::new();
16 16
@@ -52,7 +52,7 @@ impl<'d, T: Instance> Rng<'d, T> {
52 inner: impl Peripheral<P = T> + 'd, 52 inner: impl Peripheral<P = T> + 'd,
53 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, 53 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
54 ) -> Self { 54 ) -> Self {
55 T::enable_and_reset(); 55 rcc::enable_and_reset::<T>();
56 into_ref!(inner); 56 into_ref!(inner);
57 let mut random = Self { _inner: inner }; 57 let mut random = Self { _inner: inner };
58 random.reset(); 58 random.reset();
diff --git a/embassy-stm32/src/rtc/datetime.rs b/embassy-stm32/src/rtc/datetime.rs
index 77d89293d..32732e96e 100644
--- a/embassy-stm32/src/rtc/datetime.rs
+++ b/embassy-stm32/src/rtc/datetime.rs
@@ -1,65 +1,6 @@
1#[cfg(feature = "chrono")] 1#[cfg(feature = "chrono")]
2use chrono::{Datelike, NaiveDate, Timelike, Weekday}; 2use chrono::{Datelike, NaiveDate, Timelike, Weekday};
3 3
4#[cfg(any(feature = "defmt", feature = "time"))]
5use crate::peripherals::RTC;
6#[cfg(any(feature = "defmt", feature = "time"))]
7use crate::rtc::SealedInstance;
8
9/// Represents an instant in time that can be substracted to compute a duration
10pub struct RtcInstant {
11 /// 0..59
12 pub second: u8,
13 /// 0..256
14 pub subsecond: u16,
15}
16
17impl RtcInstant {
18 #[cfg(not(rtc_v2f2))]
19 pub(super) const fn from(second: u8, subsecond: u16) -> Result<Self, Error> {
20 if second > 59 {
21 Err(Error::InvalidSecond)
22 } else {
23 Ok(Self { second, subsecond })
24 }
25 }
26}
27
28#[cfg(feature = "defmt")]
29impl defmt::Format for RtcInstant {
30 fn format(&self, fmt: defmt::Formatter) {
31 defmt::write!(
32 fmt,
33 "{}:{}",
34 self.second,
35 RTC::regs().prer().read().prediv_s() - self.subsecond,
36 )
37 }
38}
39
40#[cfg(feature = "time")]
41impl core::ops::Sub for RtcInstant {
42 type Output = embassy_time::Duration;
43
44 fn sub(self, rhs: Self) -> Self::Output {
45 use embassy_time::{Duration, TICK_HZ};
46
47 let second = if self.second < rhs.second {
48 self.second + 60
49 } else {
50 self.second
51 };
52
53 let psc = RTC::regs().prer().read().prediv_s() as u32;
54
55 let self_ticks = second as u32 * (psc + 1) + (psc - self.subsecond as u32);
56 let other_ticks = rhs.second as u32 * (psc + 1) + (psc - rhs.subsecond as u32);
57 let rtc_ticks = self_ticks - other_ticks;
58
59 Duration::from_ticks(((rtc_ticks * TICK_HZ as u32) / (psc + 1)) as u64)
60 }
61}
62
63/// Errors regarding the [`DateTime`] struct. 4/// Errors regarding the [`DateTime`] struct.
64#[derive(Clone, Debug, PartialEq, Eq)] 5#[derive(Clone, Debug, PartialEq, Eq)]
65pub enum Error { 6pub enum Error {
diff --git a/embassy-stm32/src/rtc/low_power.rs b/embassy-stm32/src/rtc/low_power.rs
new file mode 100644
index 000000000..a4ff1acbc
--- /dev/null
+++ b/embassy-stm32/src/rtc/low_power.rs
@@ -0,0 +1,230 @@
1use super::{bcd2_to_byte, DateTimeError, Rtc, RtcError};
2use crate::peripherals::RTC;
3use crate::rtc::SealedInstance;
4
5/// Represents an instant in time that can be substracted to compute a duration
6pub(super) struct RtcInstant {
7 /// 0..59
8 second: u8,
9 /// 0..256
10 subsecond: u16,
11}
12
13impl RtcInstant {
14 #[cfg(not(rtc_v2f2))]
15 const fn from(second: u8, subsecond: u16) -> Result<Self, DateTimeError> {
16 if second > 59 {
17 Err(DateTimeError::InvalidSecond)
18 } else {
19 Ok(Self { second, subsecond })
20 }
21 }
22}
23
24#[cfg(feature = "defmt")]
25impl defmt::Format for RtcInstant {
26 fn format(&self, fmt: defmt::Formatter) {
27 defmt::write!(
28 fmt,
29 "{}:{}",
30 self.second,
31 RTC::regs().prer().read().prediv_s() - self.subsecond,
32 )
33 }
34}
35
36#[cfg(feature = "time")]
37impl core::ops::Sub for RtcInstant {
38 type Output = embassy_time::Duration;
39
40 fn sub(self, rhs: Self) -> Self::Output {
41 use embassy_time::{Duration, TICK_HZ};
42
43 let second = if self.second < rhs.second {
44 self.second + 60
45 } else {
46 self.second
47 };
48
49 let psc = RTC::regs().prer().read().prediv_s() as u32;
50
51 let self_ticks = second as u32 * (psc + 1) + (psc - self.subsecond as u32);
52 let other_ticks = rhs.second as u32 * (psc + 1) + (psc - rhs.subsecond as u32);
53 let rtc_ticks = self_ticks - other_ticks;
54
55 Duration::from_ticks(((rtc_ticks * TICK_HZ as u32) / (psc + 1)) as u64)
56 }
57}
58
59#[repr(u8)]
60#[derive(Clone, Copy, Debug)]
61pub(crate) enum WakeupPrescaler {
62 Div2 = 2,
63 Div4 = 4,
64 Div8 = 8,
65 Div16 = 16,
66}
67
68#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l5, stm32wb, stm32h5, stm32g0))]
69impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
70 fn from(val: WakeupPrescaler) -> Self {
71 use crate::pac::rtc::vals::Wucksel;
72
73 match val {
74 WakeupPrescaler::Div2 => Wucksel::DIV2,
75 WakeupPrescaler::Div4 => Wucksel::DIV4,
76 WakeupPrescaler::Div8 => Wucksel::DIV8,
77 WakeupPrescaler::Div16 => Wucksel::DIV16,
78 }
79 }
80}
81
82#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l5, stm32wb, stm32h5, stm32g0))]
83impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler {
84 fn from(val: crate::pac::rtc::vals::Wucksel) -> Self {
85 use crate::pac::rtc::vals::Wucksel;
86
87 match val {
88 Wucksel::DIV2 => WakeupPrescaler::Div2,
89 Wucksel::DIV4 => WakeupPrescaler::Div4,
90 Wucksel::DIV8 => WakeupPrescaler::Div8,
91 Wucksel::DIV16 => WakeupPrescaler::Div16,
92 _ => unreachable!(),
93 }
94 }
95}
96
97impl WakeupPrescaler {
98 pub fn compute_min(val: u32) -> Self {
99 *[
100 WakeupPrescaler::Div2,
101 WakeupPrescaler::Div4,
102 WakeupPrescaler::Div8,
103 WakeupPrescaler::Div16,
104 ]
105 .iter()
106 .find(|psc| **psc as u32 > val)
107 .unwrap_or(&WakeupPrescaler::Div16)
108 }
109}
110
111impl Rtc {
112 /// Return the current instant.
113 fn instant(&self) -> Result<RtcInstant, RtcError> {
114 self.time_provider().read(|_, tr, ss| {
115 let second = bcd2_to_byte((tr.st(), tr.su()));
116
117 RtcInstant::from(second, ss).map_err(RtcError::InvalidDateTime)
118 })
119 }
120
121 /// start the wakeup alarm and with a duration that is as close to but less than
122 /// the requested duration, and record the instant the wakeup alarm was started
123 pub(crate) fn start_wakeup_alarm(
124 &self,
125 requested_duration: embassy_time::Duration,
126 cs: critical_section::CriticalSection,
127 ) {
128 use embassy_time::{Duration, TICK_HZ};
129
130 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
131 use crate::pac::rtc::vals::Calrf;
132
133 // Panic if the rcc mod knows we're not using low-power rtc
134 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
135 unsafe { crate::rcc::get_freqs() }.rtc.unwrap();
136
137 let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64);
138 let rtc_hz = Self::frequency().0 as u64;
139 let rtc_ticks = requested_duration * rtc_hz / TICK_HZ;
140 let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32);
141
142 // adjust the rtc ticks to the prescaler and subtract one rtc tick
143 let rtc_ticks = rtc_ticks / prescaler as u64;
144 let rtc_ticks = rtc_ticks.clamp(0, (u16::MAX - 1) as u64).saturating_sub(1) as u16;
145
146 self.write(false, |regs| {
147 regs.cr().modify(|w| w.set_wute(false));
148
149 #[cfg(any(
150 rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb
151 ))]
152 {
153 regs.isr().modify(|w| w.set_wutf(false));
154 while !regs.isr().read().wutwf() {}
155 }
156
157 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
158 {
159 regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR));
160 while !regs.icsr().read().wutwf() {}
161 }
162
163 regs.cr().modify(|w| w.set_wucksel(prescaler.into()));
164 regs.wutr().write(|w| w.set_wut(rtc_ticks));
165 regs.cr().modify(|w| w.set_wute(true));
166 regs.cr().modify(|w| w.set_wutie(true));
167 });
168
169 let instant = self.instant().unwrap();
170 trace!(
171 "rtc: start wakeup alarm for {} ms (psc: {}, ticks: {}) at {}",
172 Duration::from_ticks(rtc_ticks as u64 * TICK_HZ * prescaler as u64 / rtc_hz).as_millis(),
173 prescaler as u32,
174 rtc_ticks,
175 instant,
176 );
177
178 assert!(self.stop_time.borrow(cs).replace(Some(instant)).is_none())
179 }
180
181 /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm`
182 /// was called, otherwise none
183 pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> {
184 use crate::interrupt::typelevel::Interrupt;
185 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
186 use crate::pac::rtc::vals::Calrf;
187
188 let instant = self.instant().unwrap();
189 if RTC::regs().cr().read().wute() {
190 trace!("rtc: stop wakeup alarm at {}", instant);
191
192 self.write(false, |regs| {
193 regs.cr().modify(|w| w.set_wutie(false));
194 regs.cr().modify(|w| w.set_wute(false));
195
196 #[cfg(any(
197 rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb
198 ))]
199 regs.isr().modify(|w| w.set_wutf(false));
200
201 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
202 regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR));
203
204 // Check RM for EXTI and/or NVIC section, "Event event input mapping" or "EXTI interrupt/event mapping" or something similar,
205 // there is a table for every "Event input" / "EXTI Line".
206 // If you find the EXTI line related to "RTC wakeup" marks as "Configurable" (not "Direct"),
207 // then write 1 to related field of Pending Register, to clean it's pending state.
208 #[cfg(any(exti_v1, stm32h7, stm32wb))]
209 crate::pac::EXTI
210 .pr(0)
211 .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
212
213 <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend();
214 });
215 }
216
217 self.stop_time.borrow(cs).take().map(|stop_time| instant - stop_time)
218 }
219
220 pub(crate) fn enable_wakeup_line(&self) {
221 use crate::interrupt::typelevel::Interrupt;
222 use crate::pac::EXTI;
223
224 <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend();
225 unsafe { <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::enable() };
226
227 EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
228 EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
229 }
230}
diff --git a/embassy-stm32/src/rtc/mod.rs b/embassy-stm32/src/rtc/mod.rs
index b12a0db66..a7f70b153 100644
--- a/embassy-stm32/src/rtc/mod.rs
+++ b/embassy-stm32/src/rtc/mod.rs
@@ -2,6 +2,9 @@
2mod datetime; 2mod datetime;
3 3
4#[cfg(feature = "low-power")] 4#[cfg(feature = "low-power")]
5mod low_power;
6
7#[cfg(feature = "low-power")]
5use core::cell::Cell; 8use core::cell::Cell;
6 9
7#[cfg(feature = "low-power")] 10#[cfg(feature = "low-power")]
@@ -9,8 +12,6 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
9#[cfg(feature = "low-power")] 12#[cfg(feature = "low-power")]
10use embassy_sync::blocking_mutex::Mutex; 13use embassy_sync::blocking_mutex::Mutex;
11 14
12#[cfg(not(rtc_v2f2))]
13use self::datetime::RtcInstant;
14use self::datetime::{day_of_week_from_u8, day_of_week_to_u8}; 15use self::datetime::{day_of_week_from_u8, day_of_week_to_u8};
15pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; 16pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError};
16use crate::pac::rtc::regs::{Dr, Tr}; 17use crate::pac::rtc::regs::{Dr, Tr};
@@ -32,60 +33,6 @@ use embassy_hal_internal::Peripheral;
32 33
33use crate::peripherals::RTC; 34use crate::peripherals::RTC;
34 35
35#[allow(dead_code)]
36#[repr(u8)]
37#[derive(Clone, Copy, Debug)]
38pub(crate) enum WakeupPrescaler {
39 Div2 = 2,
40 Div4 = 4,
41 Div8 = 8,
42 Div16 = 16,
43}
44
45#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l5, stm32wb, stm32h5, stm32g0))]
46impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
47 fn from(val: WakeupPrescaler) -> Self {
48 use crate::pac::rtc::vals::Wucksel;
49
50 match val {
51 WakeupPrescaler::Div2 => Wucksel::DIV2,
52 WakeupPrescaler::Div4 => Wucksel::DIV4,
53 WakeupPrescaler::Div8 => Wucksel::DIV8,
54 WakeupPrescaler::Div16 => Wucksel::DIV16,
55 }
56 }
57}
58
59#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l5, stm32wb, stm32h5, stm32g0))]
60impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler {
61 fn from(val: crate::pac::rtc::vals::Wucksel) -> Self {
62 use crate::pac::rtc::vals::Wucksel;
63
64 match val {
65 Wucksel::DIV2 => WakeupPrescaler::Div2,
66 Wucksel::DIV4 => WakeupPrescaler::Div4,
67 Wucksel::DIV8 => WakeupPrescaler::Div8,
68 Wucksel::DIV16 => WakeupPrescaler::Div16,
69 _ => unreachable!(),
70 }
71 }
72}
73
74#[cfg(feature = "low-power")]
75impl WakeupPrescaler {
76 pub fn compute_min(val: u32) -> Self {
77 *[
78 WakeupPrescaler::Div2,
79 WakeupPrescaler::Div4,
80 WakeupPrescaler::Div8,
81 WakeupPrescaler::Div16,
82 ]
83 .iter()
84 .find(|psc| **psc as u32 > val)
85 .unwrap_or(&WakeupPrescaler::Div16)
86 }
87}
88
89/// Errors that can occur on methods on [RtcClock] 36/// Errors that can occur on methods on [RtcClock]
90#[non_exhaustive] 37#[non_exhaustive]
91#[derive(Clone, Debug, PartialEq, Eq)] 38#[derive(Clone, Debug, PartialEq, Eq)]
@@ -106,15 +53,6 @@ pub struct RtcTimeProvider {
106} 53}
107 54
108impl RtcTimeProvider { 55impl RtcTimeProvider {
109 #[cfg(not(rtc_v2f2))]
110 pub(crate) fn instant(&self) -> Result<RtcInstant, RtcError> {
111 self.read(|_, tr, ss| {
112 let second = bcd2_to_byte((tr.st(), tr.su()));
113
114 RtcInstant::from(second, ss).map_err(RtcError::InvalidDateTime)
115 })
116 }
117
118 /// Return the current datetime. 56 /// Return the current datetime.
119 /// 57 ///
120 /// # Errors 58 /// # Errors
@@ -165,8 +103,7 @@ impl RtcTimeProvider {
165/// RTC driver. 103/// RTC driver.
166pub struct Rtc { 104pub struct Rtc {
167 #[cfg(feature = "low-power")] 105 #[cfg(feature = "low-power")]
168 stop_time: Mutex<CriticalSectionRawMutex, Cell<Option<RtcInstant>>>, 106 stop_time: Mutex<CriticalSectionRawMutex, Cell<Option<low_power::RtcInstant>>>,
169 #[cfg(not(feature = "low-power"))]
170 _private: (), 107 _private: (),
171} 108}
172 109
@@ -205,12 +142,11 @@ impl Rtc {
205 /// Create a new RTC instance. 142 /// Create a new RTC instance.
206 pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self { 143 pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self {
207 #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))] 144 #[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))]
208 <RTC as crate::rcc::SealedRccPeripheral>::enable_and_reset(); 145 crate::rcc::enable_and_reset::<RTC>();
209 146
210 let mut this = Self { 147 let mut this = Self {
211 #[cfg(feature = "low-power")] 148 #[cfg(feature = "low-power")]
212 stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)), 149 stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)),
213 #[cfg(not(feature = "low-power"))]
214 _private: (), 150 _private: (),
215 }; 151 };
216 152
@@ -223,9 +159,8 @@ impl Rtc {
223 // Wait for the clock to update after initialization 159 // Wait for the clock to update after initialization
224 #[cfg(not(rtc_v2f2))] 160 #[cfg(not(rtc_v2f2))]
225 { 161 {
226 let now = this.instant().unwrap(); 162 let now = this.time_provider().read(|_, _, ss| Ok(ss)).unwrap();
227 163 while now == this.time_provider().read(|_, _, ss| Ok(ss)).unwrap() {}
228 while this.instant().unwrap().subsecond == now.subsecond {}
229 } 164 }
230 165
231 this 166 this
@@ -284,12 +219,6 @@ impl Rtc {
284 Ok(()) 219 Ok(())
285 } 220 }
286 221
287 #[cfg(not(rtc_v2f2))]
288 /// Return the current instant.
289 fn instant(&self) -> Result<RtcInstant, RtcError> {
290 self.time_provider().instant()
291 }
292
293 /// Return the current datetime. 222 /// Return the current datetime.
294 /// 223 ///
295 /// # Errors 224 /// # Errors
@@ -320,7 +249,7 @@ impl Rtc {
320 /// The registers retain their values during wakes from standby mode or system resets. They also 249 /// The registers retain their values during wakes from standby mode or system resets. They also
321 /// retain their value when Vdd is switched off as long as V_BAT is powered. 250 /// retain their value when Vdd is switched off as long as V_BAT is powered.
322 pub fn read_backup_register(&self, register: usize) -> Option<u32> { 251 pub fn read_backup_register(&self, register: usize) -> Option<u32> {
323 RTC::read_backup_register(&RTC::regs(), register) 252 RTC::read_backup_register(RTC::regs(), register)
324 } 253 }
325 254
326 /// Set content of the backup register. 255 /// Set content of the backup register.
@@ -328,120 +257,7 @@ impl Rtc {
328 /// The registers retain their values during wakes from standby mode or system resets. They also 257 /// The registers retain their values during wakes from standby mode or system resets. They also
329 /// retain their value when Vdd is switched off as long as V_BAT is powered. 258 /// retain their value when Vdd is switched off as long as V_BAT is powered.
330 pub fn write_backup_register(&self, register: usize, value: u32) { 259 pub fn write_backup_register(&self, register: usize, value: u32) {
331 RTC::write_backup_register(&RTC::regs(), register, value) 260 RTC::write_backup_register(RTC::regs(), register, value)
332 }
333
334 #[cfg(feature = "low-power")]
335 /// start the wakeup alarm and with a duration that is as close to but less than
336 /// the requested duration, and record the instant the wakeup alarm was started
337 pub(crate) fn start_wakeup_alarm(
338 &self,
339 requested_duration: embassy_time::Duration,
340 cs: critical_section::CriticalSection,
341 ) {
342 use embassy_time::{Duration, TICK_HZ};
343
344 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
345 use crate::pac::rtc::vals::Calrf;
346
347 // Panic if the rcc mod knows we're not using low-power rtc
348 #[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
349 unsafe { crate::rcc::get_freqs() }.rtc.unwrap();
350
351 let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64);
352 let rtc_hz = Self::frequency().0 as u64;
353 let rtc_ticks = requested_duration * rtc_hz / TICK_HZ;
354 let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32);
355
356 // adjust the rtc ticks to the prescaler and subtract one rtc tick
357 let rtc_ticks = rtc_ticks / prescaler as u64;
358 let rtc_ticks = rtc_ticks.clamp(0, (u16::MAX - 1) as u64).saturating_sub(1) as u16;
359
360 self.write(false, |regs| {
361 regs.cr().modify(|w| w.set_wute(false));
362
363 #[cfg(any(
364 rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb
365 ))]
366 {
367 regs.isr().modify(|w| w.set_wutf(false));
368 while !regs.isr().read().wutwf() {}
369 }
370
371 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
372 {
373 regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR));
374 while !regs.icsr().read().wutwf() {}
375 }
376
377 regs.cr().modify(|w| w.set_wucksel(prescaler.into()));
378 regs.wutr().write(|w| w.set_wut(rtc_ticks));
379 regs.cr().modify(|w| w.set_wute(true));
380 regs.cr().modify(|w| w.set_wutie(true));
381 });
382
383 let instant = self.instant().unwrap();
384 trace!(
385 "rtc: start wakeup alarm for {} ms (psc: {}, ticks: {}) at {}",
386 Duration::from_ticks(rtc_ticks as u64 * TICK_HZ * prescaler as u64 / rtc_hz).as_millis(),
387 prescaler as u32,
388 rtc_ticks,
389 instant,
390 );
391
392 assert!(self.stop_time.borrow(cs).replace(Some(instant)).is_none())
393 }
394
395 #[cfg(feature = "low-power")]
396 /// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm`
397 /// was called, otherwise none
398 pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> {
399 use crate::interrupt::typelevel::Interrupt;
400 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
401 use crate::pac::rtc::vals::Calrf;
402
403 let instant = self.instant().unwrap();
404 if RTC::regs().cr().read().wute() {
405 trace!("rtc: stop wakeup alarm at {}", instant);
406
407 self.write(false, |regs| {
408 regs.cr().modify(|w| w.set_wutie(false));
409 regs.cr().modify(|w| w.set_wute(false));
410
411 #[cfg(any(
412 rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb
413 ))]
414 regs.isr().modify(|w| w.set_wutf(false));
415
416 #[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
417 regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR));
418
419 // Check RM for EXTI and/or NVIC section, "Event event input mapping" or "EXTI interrupt/event mapping" or something similar,
420 // there is a table for every "Event input" / "EXTI Line".
421 // If you find the EXTI line related to "RTC wakeup" marks as "Configurable" (not "Direct"),
422 // then write 1 to related field of Pending Register, to clean it's pending state.
423 #[cfg(any(exti_v1, stm32h7, stm32wb))]
424 crate::pac::EXTI
425 .pr(0)
426 .modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
427
428 <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend();
429 });
430 }
431
432 self.stop_time.borrow(cs).take().map(|stop_time| instant - stop_time)
433 }
434
435 #[cfg(feature = "low-power")]
436 pub(crate) fn enable_wakeup_line(&self) {
437 use crate::interrupt::typelevel::Interrupt;
438 use crate::pac::EXTI;
439
440 <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend();
441 unsafe { <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::enable() };
442
443 EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
444 EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
445 } 261 }
446} 262}
447 263
@@ -482,13 +298,13 @@ trait SealedInstance {
482 /// 298 ///
483 /// The registers retain their values during wakes from standby mode or system resets. They also 299 /// The registers retain their values during wakes from standby mode or system resets. They also
484 /// retain their value when Vdd is switched off as long as V_BAT is powered. 300 /// retain their value when Vdd is switched off as long as V_BAT is powered.
485 fn read_backup_register(rtc: &crate::pac::rtc::Rtc, register: usize) -> Option<u32>; 301 fn read_backup_register(rtc: crate::pac::rtc::Rtc, register: usize) -> Option<u32>;
486 302
487 /// Set content of the backup register. 303 /// Set content of the backup register.
488 /// 304 ///
489 /// The registers retain their values during wakes from standby mode or system resets. They also 305 /// The registers retain their values during wakes from standby mode or system resets. They also
490 /// retain their value when Vdd is switched off as long as V_BAT is powered. 306 /// retain their value when Vdd is switched off as long as V_BAT is powered.
491 fn write_backup_register(rtc: &crate::pac::rtc::Rtc, register: usize, value: u32); 307 fn write_backup_register(rtc: crate::pac::rtc::Rtc, register: usize, value: u32);
492 308
493 // fn apply_config(&mut self, rtc_config: RtcConfig); 309 // fn apply_config(&mut self, rtc_config: RtcConfig);
494} 310}
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs
index 92f9de846..cdc1cb299 100644
--- a/embassy-stm32/src/rtc/v2.rs
+++ b/embassy-stm32/src/rtc/v2.rs
@@ -95,7 +95,7 @@ impl super::Rtc {
95 95
96 pub(super) fn write<F, R>(&self, init_mode: bool, f: F) -> R 96 pub(super) fn write<F, R>(&self, init_mode: bool, f: F) -> R
97 where 97 where
98 F: FnOnce(&crate::pac::rtc::Rtc) -> R, 98 F: FnOnce(crate::pac::rtc::Rtc) -> R,
99 { 99 {
100 let r = RTC::regs(); 100 let r = RTC::regs();
101 // Disable write protection. 101 // Disable write protection.
@@ -112,7 +112,7 @@ impl super::Rtc {
112 while !r.isr().read().initf() {} 112 while !r.isr().read().initf() {}
113 } 113 }
114 114
115 let result = f(&r); 115 let result = f(r);
116 116
117 if init_mode { 117 if init_mode {
118 r.isr().modify(|w| w.set_init(false)); // Exits init mode 118 r.isr().modify(|w| w.set_init(false)); // Exits init mode
@@ -140,7 +140,7 @@ impl SealedInstance for crate::peripherals::RTC {
140 #[cfg(all(feature = "low-power", stm32l0))] 140 #[cfg(all(feature = "low-power", stm32l0))]
141 type WakeupInterrupt = crate::interrupt::typelevel::RTC; 141 type WakeupInterrupt = crate::interrupt::typelevel::RTC;
142 142
143 fn read_backup_register(rtc: &Rtc, register: usize) -> Option<u32> { 143 fn read_backup_register(rtc: Rtc, register: usize) -> Option<u32> {
144 if register < Self::BACKUP_REGISTER_COUNT { 144 if register < Self::BACKUP_REGISTER_COUNT {
145 Some(rtc.bkpr(register).read().bkp()) 145 Some(rtc.bkpr(register).read().bkp())
146 } else { 146 } else {
@@ -148,7 +148,7 @@ impl SealedInstance for crate::peripherals::RTC {
148 } 148 }
149 } 149 }
150 150
151 fn write_backup_register(rtc: &Rtc, register: usize, value: u32) { 151 fn write_backup_register(rtc: Rtc, register: usize, value: u32) {
152 if register < Self::BACKUP_REGISTER_COUNT { 152 if register < Self::BACKUP_REGISTER_COUNT {
153 rtc.bkpr(register).write(|w| w.set_bkp(value)); 153 rtc.bkpr(register).write(|w| w.set_bkp(value));
154 } 154 }
diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs
index e51e09e7c..02fd5272e 100644
--- a/embassy-stm32/src/rtc/v3.rs
+++ b/embassy-stm32/src/rtc/v3.rs
@@ -97,7 +97,7 @@ impl super::Rtc {
97 97
98 pub(super) fn write<F, R>(&self, init_mode: bool, f: F) -> R 98 pub(super) fn write<F, R>(&self, init_mode: bool, f: F) -> R
99 where 99 where
100 F: FnOnce(&crate::pac::rtc::Rtc) -> R, 100 F: FnOnce(crate::pac::rtc::Rtc) -> R,
101 { 101 {
102 let r = RTC::regs(); 102 let r = RTC::regs();
103 // Disable write protection. 103 // Disable write protection.
@@ -112,7 +112,7 @@ impl super::Rtc {
112 while !r.icsr().read().initf() {} 112 while !r.icsr().read().initf() {}
113 } 113 }
114 114
115 let result = f(&r); 115 let result = f(r);
116 116
117 if init_mode { 117 if init_mode {
118 r.icsr().modify(|w| w.set_init(false)); // Exits init mode 118 r.icsr().modify(|w| w.set_init(false)); // Exits init mode
@@ -143,7 +143,7 @@ impl SealedInstance for crate::peripherals::RTC {
143 } 143 }
144 ); 144 );
145 145
146 fn read_backup_register(_rtc: &Rtc, register: usize) -> Option<u32> { 146 fn read_backup_register(_rtc: Rtc, register: usize) -> Option<u32> {
147 #[allow(clippy::if_same_then_else)] 147 #[allow(clippy::if_same_then_else)]
148 if register < Self::BACKUP_REGISTER_COUNT { 148 if register < Self::BACKUP_REGISTER_COUNT {
149 //Some(rtc.bkpr()[register].read().bits()) 149 //Some(rtc.bkpr()[register].read().bits())
@@ -153,7 +153,7 @@ impl SealedInstance for crate::peripherals::RTC {
153 } 153 }
154 } 154 }
155 155
156 fn write_backup_register(_rtc: &Rtc, register: usize, _value: u32) { 156 fn write_backup_register(_rtc: Rtc, register: usize, _value: u32) {
157 if register < Self::BACKUP_REGISTER_COUNT { 157 if register < Self::BACKUP_REGISTER_COUNT {
158 // RTC3 backup registers come from the TAMP peripheral, not RTC. Not() even in the L412 PAC 158 // RTC3 backup registers come from the TAMP peripheral, not RTC. Not() even in the L412 PAC
159 //self.rtc.bkpr()[register].write(|w| w.bits(value)) 159 //self.rtc.bkpr()[register].write(|w| w.bits(value))
diff --git a/embassy-stm32/src/sai/mod.rs b/embassy-stm32/src/sai/mod.rs
index 54dd81524..3faecdc33 100644
--- a/embassy-stm32/src/sai/mod.rs
+++ b/embassy-stm32/src/sai/mod.rs
@@ -11,7 +11,7 @@ pub use crate::dma::word;
11use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; 11use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer};
12use crate::gpio::{AFType, AnyPin, SealedPin as _}; 12use crate::gpio::{AFType, AnyPin, SealedPin as _};
13use crate::pac::sai::{vals, Sai as Regs}; 13use crate::pac::sai::{vals, Sai as Regs};
14use crate::rcc::RccPeripheral; 14use crate::rcc::{self, RccPeripheral};
15use crate::{peripherals, Peripheral}; 15use crate::{peripherals, Peripheral};
16 16
17/// SAI error 17/// SAI error
@@ -722,7 +722,7 @@ pub struct SubBlock<'d, T, S: SubBlockInstance> {
722/// You can then create a [`Sai`] driver for each each half. 722/// You can then create a [`Sai`] driver for each each half.
723pub fn split_subblocks<'d, T: Instance>(peri: impl Peripheral<P = T> + 'd) -> (SubBlock<'d, T, A>, SubBlock<'d, T, B>) { 723pub fn split_subblocks<'d, T: Instance>(peri: impl Peripheral<P = T> + 'd) -> (SubBlock<'d, T, A>, SubBlock<'d, T, B>) {
724 into_ref!(peri); 724 into_ref!(peri);
725 T::enable_and_reset(); 725 rcc::enable_and_reset::<T>();
726 726
727 ( 727 (
728 SubBlock { 728 SubBlock {
@@ -978,7 +978,7 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
978 978
979 /// Reset SAI operation. 979 /// Reset SAI operation.
980 pub fn reset() { 980 pub fn reset() {
981 T::enable_and_reset(); 981 rcc::enable_and_reset::<T>();
982 } 982 }
983 983
984 /// Flush. 984 /// Flush.
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index f79a11606..9c14837e1 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -16,7 +16,7 @@ use crate::dma::NoDma;
16use crate::gpio::{AFType, AnyPin, Pull, SealedPin, Speed}; 16use crate::gpio::{AFType, AnyPin, Pull, SealedPin, Speed};
17use crate::interrupt::typelevel::Interrupt; 17use crate::interrupt::typelevel::Interrupt;
18use crate::pac::sdmmc::Sdmmc as RegBlock; 18use crate::pac::sdmmc::Sdmmc as RegBlock;
19use crate::rcc::RccPeripheral; 19use crate::rcc::{self, RccPeripheral};
20use crate::time::Hertz; 20use crate::time::Hertz;
21use crate::{interrupt, peripherals, Peripheral}; 21use crate::{interrupt, peripherals, Peripheral};
22 22
@@ -468,7 +468,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
468 ) -> Self { 468 ) -> Self {
469 into_ref!(sdmmc, dma); 469 into_ref!(sdmmc, dma);
470 470
471 T::enable_and_reset(); 471 rcc::enable_and_reset::<T>();
472 472
473 T::Interrupt::unpend(); 473 T::Interrupt::unpend();
474 unsafe { T::Interrupt::enable() }; 474 unsafe { T::Interrupt::enable() };
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 5fc8691ac..4eaf7777f 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -13,7 +13,7 @@ use crate::dma::{slice_ptr_parts, word, ChannelAndRequest};
13use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed}; 13use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed};
14use crate::mode::{Async, Blocking, Mode as PeriMode}; 14use crate::mode::{Async, Blocking, Mode as PeriMode};
15use crate::pac::spi::{regs, vals, Spi as Regs}; 15use crate::pac::spi::{regs, vals, Spi as Regs};
16use crate::rcc::{ClockEnableBit, SealedRccPeripheral}; 16use crate::rcc::{RccInfo, SealedRccPeripheral};
17use crate::time::Hertz; 17use crate::time::Hertz;
18use crate::Peripheral; 18use crate::Peripheral;
19 19
@@ -120,17 +120,30 @@ impl<'d, M: PeriMode> Spi<'d, M> {
120 rx_dma: Option<ChannelAndRequest<'d>>, 120 rx_dma: Option<ChannelAndRequest<'d>>,
121 config: Config, 121 config: Config,
122 ) -> Self { 122 ) -> Self {
123 let regs = T::info().regs; 123 let mut this = Self {
124 let kernel_clock = T::frequency(); 124 info: T::info(),
125 let br = compute_baud_rate(kernel_clock, config.frequency); 125 kernel_clock: T::frequency(),
126 sck,
127 mosi,
128 miso,
129 tx_dma,
130 rx_dma,
131 current_word_size: <u8 as SealedWord>::CONFIG,
132 _phantom: PhantomData,
133 };
134 this.enable_and_init(config);
135 this
136 }
126 137
138 fn enable_and_init(&mut self, config: Config) {
139 let br = compute_baud_rate(self.kernel_clock, config.frequency);
127 let cpha = config.raw_phase(); 140 let cpha = config.raw_phase();
128 let cpol = config.raw_polarity(); 141 let cpol = config.raw_polarity();
129
130 let lsbfirst = config.raw_byte_order(); 142 let lsbfirst = config.raw_byte_order();
131 143
132 T::enable_and_reset(); 144 self.info.rcc.enable_and_reset();
133 145
146 let regs = self.info.regs;
134 #[cfg(any(spi_v1, spi_f1))] 147 #[cfg(any(spi_v1, spi_f1))]
135 { 148 {
136 regs.cr2().modify(|w| { 149 regs.cr2().modify(|w| {
@@ -148,9 +161,10 @@ impl<'d, M: PeriMode> Spi<'d, M> {
148 w.set_ssm(true); 161 w.set_ssm(true);
149 w.set_crcen(false); 162 w.set_crcen(false);
150 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL); 163 w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL);
151 if mosi.is_none() { 164 // we're doing "fake rxonly", by actually writing one
152 w.set_rxonly(vals::Rxonly::OUTPUTDISABLED); 165 // byte to TXDR for each byte we want to receive. if we
153 } 166 // set OUTPUTDISABLED here, this hangs.
167 w.set_rxonly(vals::Rxonly::FULLDUPLEX);
154 w.set_dff(<u8 as SealedWord>::CONFIG) 168 w.set_dff(<u8 as SealedWord>::CONFIG)
155 }); 169 });
156 } 170 }
@@ -208,18 +222,6 @@ impl<'d, M: PeriMode> Spi<'d, M> {
208 w.set_spe(true); 222 w.set_spe(true);
209 }); 223 });
210 } 224 }
211
212 Self {
213 info: T::info(),
214 kernel_clock,
215 sck,
216 mosi,
217 miso,
218 tx_dma,
219 rx_dma,
220 current_word_size: <u8 as SealedWord>::CONFIG,
221 _phantom: PhantomData,
222 }
223 } 225 }
224 226
225 /// Reconfigures it with the supplied config. 227 /// Reconfigures it with the supplied config.
@@ -350,17 +352,46 @@ impl<'d, M: PeriMode> Spi<'d, M> {
350 352
351 /// Blocking write. 353 /// Blocking write.
352 pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> { 354 pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
355 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...?
356 #[cfg(any(spi_v3, spi_v4, spi_v5))]
357 self.info.regs.cr1().modify(|w| w.set_spe(false));
353 self.info.regs.cr1().modify(|w| w.set_spe(true)); 358 self.info.regs.cr1().modify(|w| w.set_spe(true));
354 flush_rx_fifo(self.info.regs); 359 flush_rx_fifo(self.info.regs);
355 self.set_word_size(W::CONFIG); 360 self.set_word_size(W::CONFIG);
356 for word in words.iter() { 361 for word in words.iter() {
357 let _ = transfer_word(self.info.regs, *word)?; 362 // this cannot use `transfer_word` because on SPIv2 and higher,
363 // the SPI RX state machine hangs if no physical pin is connected to the SCK AF.
364 // This is the case when the SPI has been created with `new_(blocking_?)txonly_nosck`.
365 // See https://github.com/embassy-rs/embassy/issues/2902
366 // This is not documented as an errata by ST, and I've been unable to find anything online...
367 #[cfg(not(any(spi_v1, spi_f1)))]
368 write_word(self.info.regs, *word)?;
369
370 // if we're doing tx only, after writing the last byte to FIFO we have to wait
371 // until it's actually sent. On SPIv1 you're supposed to use the BSY flag for this
372 // but apparently it's broken, it clears too soon. Workaround is to wait for RXNE:
373 // when it gets set you know the transfer is done, even if you don't care about rx.
374 // Luckily this doesn't affect SPIv2+.
375 // See http://efton.sk/STM32/gotcha/g68.html
376 // ST doesn't seem to document this in errata sheets (?)
377 #[cfg(any(spi_v1, spi_f1))]
378 transfer_word(self.info.regs, *word)?;
358 } 379 }
380
381 // wait until last word is transmitted. (except on v1, see above)
382 #[cfg(not(any(spi_v1, spi_f1, spi_v2)))]
383 while !self.info.regs.sr().read().txc() {}
384 #[cfg(spi_v2)]
385 while self.info.regs.sr().read().bsy() {}
386
359 Ok(()) 387 Ok(())
360 } 388 }
361 389
362 /// Blocking read. 390 /// Blocking read.
363 pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { 391 pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
392 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...?
393 #[cfg(any(spi_v3, spi_v4, spi_v5))]
394 self.info.regs.cr1().modify(|w| w.set_spe(false));
364 self.info.regs.cr1().modify(|w| w.set_spe(true)); 395 self.info.regs.cr1().modify(|w| w.set_spe(true));
365 flush_rx_fifo(self.info.regs); 396 flush_rx_fifo(self.info.regs);
366 self.set_word_size(W::CONFIG); 397 self.set_word_size(W::CONFIG);
@@ -374,6 +405,9 @@ impl<'d, M: PeriMode> Spi<'d, M> {
374 /// 405 ///
375 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time. 406 /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
376 pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { 407 pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
408 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...?
409 #[cfg(any(spi_v3, spi_v4, spi_v5))]
410 self.info.regs.cr1().modify(|w| w.set_spe(false));
377 self.info.regs.cr1().modify(|w| w.set_spe(true)); 411 self.info.regs.cr1().modify(|w| w.set_spe(true));
378 flush_rx_fifo(self.info.regs); 412 flush_rx_fifo(self.info.regs);
379 self.set_word_size(W::CONFIG); 413 self.set_word_size(W::CONFIG);
@@ -390,6 +424,9 @@ impl<'d, M: PeriMode> Spi<'d, M> {
390 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored. 424 /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
391 /// If `write` is shorter it is padded with zero bytes. 425 /// If `write` is shorter it is padded with zero bytes.
392 pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { 426 pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
427 // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...?
428 #[cfg(any(spi_v3, spi_v4, spi_v5))]
429 self.info.regs.cr1().modify(|w| w.set_spe(false));
393 self.info.regs.cr1().modify(|w| w.set_spe(true)); 430 self.info.regs.cr1().modify(|w| w.set_spe(true));
394 flush_rx_fifo(self.info.regs); 431 flush_rx_fifo(self.info.regs);
395 self.set_word_size(W::CONFIG); 432 self.set_word_size(W::CONFIG);
@@ -508,6 +545,7 @@ impl<'d> Spi<'d, Async> {
508 peri: impl Peripheral<P = T> + 'd, 545 peri: impl Peripheral<P = T> + 'd,
509 sck: impl Peripheral<P = impl SckPin<T>> + 'd, 546 sck: impl Peripheral<P = impl SckPin<T>> + 'd,
510 miso: impl Peripheral<P = impl MisoPin<T>> + 'd, 547 miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
548 #[cfg(any(spi_v1, spi_f1, spi_v2))] tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
511 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, 549 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
512 config: Config, 550 config: Config,
513 ) -> Self { 551 ) -> Self {
@@ -516,6 +554,9 @@ impl<'d> Spi<'d, Async> {
516 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()), 554 new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
517 None, 555 None,
518 new_pin!(miso, AFType::Input, Speed::VeryHigh), 556 new_pin!(miso, AFType::Input, Speed::VeryHigh),
557 #[cfg(any(spi_v1, spi_f1, spi_v2))]
558 new_dma!(tx_dma),
559 #[cfg(any(spi_v3, spi_v4, spi_v5))]
519 None, 560 None,
520 new_dma!(rx_dma), 561 new_dma!(rx_dma),
521 config, 562 config,
@@ -571,7 +612,7 @@ impl<'d> Spi<'d, Async> {
571 // see RM0453 rev 1 section 7.2.13 page 291 612 // see RM0453 rev 1 section 7.2.13 page 291
572 // The SUBGHZSPI_SCK frequency is obtained by PCLK3 divided by two. 613 // The SUBGHZSPI_SCK frequency is obtained by PCLK3 divided by two.
573 // The SUBGHZSPI_SCK clock maximum speed must not exceed 16 MHz. 614 // The SUBGHZSPI_SCK clock maximum speed must not exceed 16 MHz.
574 let pclk3_freq = <crate::peripherals::SUBGHZSPI as crate::rcc::SealedRccPeripheral>::frequency().0; 615 let pclk3_freq = <crate::peripherals::SUBGHZSPI as SealedRccPeripheral>::frequency().0;
575 let freq = Hertz(core::cmp::min(pclk3_freq / 2, 16_000_000)); 616 let freq = Hertz(core::cmp::min(pclk3_freq / 2, 16_000_000));
576 let mut config = Config::default(); 617 let mut config = Config::default();
577 config.mode = MODE_0; 618 config.mode = MODE_0;
@@ -584,11 +625,11 @@ impl<'d> Spi<'d, Async> {
584 #[allow(dead_code)] 625 #[allow(dead_code)]
585 pub(crate) fn new_internal<T: Instance>( 626 pub(crate) fn new_internal<T: Instance>(
586 peri: impl Peripheral<P = T> + 'd, 627 peri: impl Peripheral<P = T> + 'd,
587 tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd, 628 tx_dma: Option<ChannelAndRequest<'d>>,
588 rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd, 629 rx_dma: Option<ChannelAndRequest<'d>>,
589 config: Config, 630 config: Config,
590 ) -> Self { 631 ) -> Self {
591 Self::new_inner(peri, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config) 632 Self::new_inner(peri, None, None, None, tx_dma, rx_dma, config)
592 } 633 }
593 634
594 /// SPI write, using DMA. 635 /// SPI write, using DMA.
@@ -622,12 +663,100 @@ impl<'d> Spi<'d, Async> {
622 } 663 }
623 664
624 /// SPI read, using DMA. 665 /// SPI read, using DMA.
666 #[cfg(any(spi_v3, spi_v4, spi_v5))]
667 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
668 if data.is_empty() {
669 return Ok(());
670 }
671
672 let regs = self.info.regs;
673
674 regs.cr1().modify(|w| {
675 w.set_spe(false);
676 });
677
678 let comm = regs.cfg2().modify(|w| {
679 let prev = w.comm();
680 w.set_comm(vals::Comm::RECEIVER);
681 prev
682 });
683
684 #[cfg(spi_v3)]
685 let i2scfg = regs.i2scfgr().modify(|w| {
686 w.i2smod().then(|| {
687 let prev = w.i2scfg();
688 w.set_i2scfg(match prev {
689 vals::I2scfg::SLAVERX | vals::I2scfg::SLAVEFULLDUPLEX => vals::I2scfg::SLAVERX,
690 vals::I2scfg::MASTERRX | vals::I2scfg::MASTERFULLDUPLEX => vals::I2scfg::MASTERRX,
691 _ => panic!("unsupported configuration"),
692 });
693 prev
694 })
695 });
696
697 let rx_src = regs.rx_ptr();
698
699 for mut chunk in data.chunks_mut(u16::max_value().into()) {
700 self.set_word_size(W::CONFIG);
701 set_rxdmaen(regs, true);
702
703 let tsize = chunk.len();
704
705 let transfer = unsafe {
706 self.rx_dma
707 .as_mut()
708 .unwrap()
709 .read(rx_src, &mut chunk, Default::default())
710 };
711
712 regs.cr2().modify(|w| {
713 w.set_tsize(tsize as u16);
714 });
715
716 regs.cr1().modify(|w| {
717 w.set_spe(true);
718 });
719
720 regs.cr1().modify(|w| {
721 w.set_cstart(true);
722 });
723
724 transfer.await;
725
726 finish_dma(regs);
727 }
728
729 regs.cr1().modify(|w| {
730 w.set_spe(false);
731 });
732
733 regs.cfg2().modify(|w| {
734 w.set_comm(comm);
735 });
736
737 regs.cr2().modify(|w| {
738 w.set_tsize(0);
739 });
740
741 #[cfg(spi_v3)]
742 if let Some(i2scfg) = i2scfg {
743 regs.i2scfgr().modify(|w| {
744 w.set_i2scfg(i2scfg);
745 });
746 }
747
748 Ok(())
749 }
750
751 /// SPI read, using DMA.
752 #[cfg(any(spi_v1, spi_f1, spi_v2))]
625 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> { 753 pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
626 if data.is_empty() { 754 if data.is_empty() {
627 return Ok(()); 755 return Ok(());
628 } 756 }
629 757
630 self.set_word_size(W::CONFIG); 758 self.set_word_size(W::CONFIG);
759
631 self.info.regs.cr1().modify(|w| { 760 self.info.regs.cr1().modify(|w| {
632 w.set_spe(false); 761 w.set_spe(false);
633 }); 762 });
@@ -738,7 +867,7 @@ impl<'d, M: PeriMode> Drop for Spi<'d, M> {
738 self.mosi.as_ref().map(|x| x.set_as_disconnected()); 867 self.mosi.as_ref().map(|x| x.set_as_disconnected());
739 self.miso.as_ref().map(|x| x.set_as_disconnected()); 868 self.miso.as_ref().map(|x| x.set_as_disconnected());
740 869
741 self.info.enable_bit.disable(); 870 self.info.rcc.disable();
742 } 871 }
743} 872}
744 873
@@ -805,8 +934,8 @@ impl RegsExt for Regs {
805 } 934 }
806} 935}
807 936
808fn check_error_flags(sr: regs::Sr) -> Result<(), Error> { 937fn check_error_flags(sr: regs::Sr, ovr: bool) -> Result<(), Error> {
809 if sr.ovr() { 938 if sr.ovr() && ovr {
810 return Err(Error::Overrun); 939 return Err(Error::Overrun);
811 } 940 }
812 #[cfg(not(any(spi_f1, spi_v3, spi_v4, spi_v5)))] 941 #[cfg(not(any(spi_f1, spi_v3, spi_v4, spi_v5)))]
@@ -832,11 +961,11 @@ fn check_error_flags(sr: regs::Sr) -> Result<(), Error> {
832 Ok(()) 961 Ok(())
833} 962}
834 963
835fn spin_until_tx_ready(regs: Regs) -> Result<(), Error> { 964fn spin_until_tx_ready(regs: Regs, ovr: bool) -> Result<(), Error> {
836 loop { 965 loop {
837 let sr = regs.sr().read(); 966 let sr = regs.sr().read();
838 967
839 check_error_flags(sr)?; 968 check_error_flags(sr, ovr)?;
840 969
841 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 970 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
842 if sr.txe() { 971 if sr.txe() {
@@ -853,7 +982,7 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> {
853 loop { 982 loop {
854 let sr = regs.sr().read(); 983 let sr = regs.sr().read();
855 984
856 check_error_flags(sr)?; 985 check_error_flags(sr, true)?;
857 986
858 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 987 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
859 if sr.rxne() { 988 if sr.rxne() {
@@ -907,7 +1036,13 @@ fn finish_dma(regs: Regs) {
907 while regs.sr().read().ftlvl().to_bits() > 0 {} 1036 while regs.sr().read().ftlvl().to_bits() > 0 {}
908 1037
909 #[cfg(any(spi_v3, spi_v4, spi_v5))] 1038 #[cfg(any(spi_v3, spi_v4, spi_v5))]
910 while !regs.sr().read().txc() {} 1039 {
1040 if regs.cr2().read().tsize() == 0 {
1041 while !regs.sr().read().txc() {}
1042 } else {
1043 while !regs.sr().read().eot() {}
1044 }
1045 }
911 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] 1046 #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
912 while regs.sr().read().bsy() {} 1047 while regs.sr().read().bsy() {}
913 1048
@@ -931,7 +1066,7 @@ fn finish_dma(regs: Regs) {
931} 1066}
932 1067
933fn transfer_word<W: Word>(regs: Regs, tx_word: W) -> Result<W, Error> { 1068fn transfer_word<W: Word>(regs: Regs, tx_word: W) -> Result<W, Error> {
934 spin_until_tx_ready(regs)?; 1069 spin_until_tx_ready(regs, true)?;
935 1070
936 unsafe { 1071 unsafe {
937 ptr::write_volatile(regs.tx_ptr(), tx_word); 1072 ptr::write_volatile(regs.tx_ptr(), tx_word);
@@ -946,6 +1081,21 @@ fn transfer_word<W: Word>(regs: Regs, tx_word: W) -> Result<W, Error> {
946 Ok(rx_word) 1081 Ok(rx_word)
947} 1082}
948 1083
1084#[allow(unused)] // unused in SPIv1
1085fn write_word<W: Word>(regs: Regs, tx_word: W) -> Result<(), Error> {
1086 // for write, we intentionally ignore the rx fifo, which will cause
1087 // overrun errors that we have to ignore.
1088 spin_until_tx_ready(regs, false)?;
1089
1090 unsafe {
1091 ptr::write_volatile(regs.tx_ptr(), tx_word);
1092
1093 #[cfg(any(spi_v3, spi_v4, spi_v5))]
1094 regs.cr1().modify(|reg| reg.set_cstart(true));
1095 }
1096 Ok(())
1097}
1098
949// Note: It is not possible to impl these traits generically in embedded-hal 0.2 due to a conflict with 1099// Note: It is not possible to impl these traits generically in embedded-hal 0.2 due to a conflict with
950// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289 1100// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289
951macro_rules! impl_blocking { 1101macro_rules! impl_blocking {
@@ -1118,7 +1268,7 @@ mod word_impl {
1118 1268
1119pub(crate) struct Info { 1269pub(crate) struct Info {
1120 pub(crate) regs: Regs, 1270 pub(crate) regs: Regs,
1121 pub(crate) enable_bit: ClockEnableBit, 1271 pub(crate) rcc: RccInfo,
1122} 1272}
1123 1273
1124struct State {} 1274struct State {}
@@ -1145,7 +1295,7 @@ foreach_peripheral!(
1145 (spi, $inst:ident) => { 1295 (spi, $inst:ident) => {
1146 peri_trait_impl!($inst, Info { 1296 peri_trait_impl!($inst, Info {
1147 regs: crate::pac::$inst, 1297 regs: crate::pac::$inst,
1148 enable_bit: crate::peripherals::$inst::ENABLE_BIT, 1298 rcc: crate::peripherals::$inst::RCC_INFO,
1149 }); 1299 });
1150 }; 1300 };
1151); 1301);
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index e592fbf7d..f8041bf1e 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -12,7 +12,7 @@ use stm32_metapac::timer::{regs, TimGp16};
12 12
13use crate::interrupt::typelevel::Interrupt; 13use crate::interrupt::typelevel::Interrupt;
14use crate::pac::timer::vals; 14use crate::pac::timer::vals;
15use crate::rcc::SealedRccPeripheral; 15use crate::rcc::{self, SealedRccPeripheral};
16#[cfg(feature = "low-power")] 16#[cfg(feature = "low-power")]
17use crate::rtc::Rtc; 17use crate::rtc::Rtc;
18use crate::timer::{CoreInstance, GeneralInstance1Channel}; 18use crate::timer::{CoreInstance, GeneralInstance1Channel};
@@ -276,7 +276,7 @@ impl RtcDriver {
276 fn init(&'static self, cs: critical_section::CriticalSection) { 276 fn init(&'static self, cs: critical_section::CriticalSection) {
277 let r = regs_gp16(); 277 let r = regs_gp16();
278 278
279 <T as SealedRccPeripheral>::enable_and_reset_with_cs(cs); 279 rcc::enable_and_reset_with_cs::<T>(cs);
280 280
281 let timer_freq = T::frequency(); 281 let timer_freq = T::frequency();
282 282
diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs
index a1c1486f9..0258d4077 100644
--- a/embassy-stm32/src/timer/input_capture.rs
+++ b/embassy-stm32/src/timer/input_capture.rs
@@ -7,7 +7,7 @@ use core::task::{Context, Poll};
7 7
8use embassy_hal_internal::{into_ref, PeripheralRef}; 8use embassy_hal_internal::{into_ref, PeripheralRef};
9 9
10use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, Timer}; 10use super::low_level::{CountingMode, FilterValue, InputCaptureMode, InputTISelection, Timer};
11use super::{ 11use super::{
12 CaptureCompareInterruptHandler, Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, 12 CaptureCompareInterruptHandler, Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin,
13 GeneralInstance4Channel, 13 GeneralInstance4Channel,
@@ -40,11 +40,9 @@ macro_rules! channel_impl {
40 #[doc = concat!("Create a new ", stringify!($channel), " capture pin instance.")] 40 #[doc = concat!("Create a new ", stringify!($channel), " capture pin instance.")]
41 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, pull_type: Pull) -> Self { 41 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, pull_type: Pull) -> Self {
42 into_ref!(pin); 42 into_ref!(pin);
43 critical_section::with(|_| { 43
44 pin.set_as_af_pull(pin.af_num(), AFType::Input, pull_type); 44 pin.set_as_af_pull(pin.af_num(), AFType::Input, pull_type);
45 #[cfg(gpio_v2)] 45
46 pin.set_speed(crate::gpio::Speed::VeryHigh);
47 });
48 CapturePin { 46 CapturePin {
49 _pin: pin.map_into(), 47 _pin: pin.map_into(),
50 phantom: PhantomData, 48 phantom: PhantomData,
@@ -83,7 +81,7 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
83 let mut this = Self { inner: Timer::new(tim) }; 81 let mut this = Self { inner: Timer::new(tim) };
84 82
85 this.inner.set_counting_mode(counting_mode); 83 this.inner.set_counting_mode(counting_mode);
86 this.set_tick_freq(freq); 84 this.inner.set_tick_freq(freq);
87 this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details 85 this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details
88 this.inner.start(); 86 this.inner.start();
89 87
@@ -109,24 +107,6 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
109 self.inner.get_channel_enable_state(channel) 107 self.inner.get_channel_enable_state(channel)
110 } 108 }
111 109
112 /// Set tick frequency.
113 ///
114 /// Note: when you call this, the max period value changes
115 pub fn set_tick_freq(&mut self, freq: Hertz) {
116 let f = freq;
117 assert!(f.0 > 0);
118 let timer_f = self.inner.get_clock_frequency();
119
120 let pclk_ticks_per_timer_period = timer_f / f;
121 let psc: u16 = unwrap!((pclk_ticks_per_timer_period - 1).try_into());
122
123 let regs = self.inner.regs_core();
124 regs.psc().write_value(psc);
125
126 // Generate an Update Request
127 regs.egr().write(|r| r.set_ug(true));
128 }
129
130 /// Set the input capture mode for a given channel. 110 /// Set the input capture mode for a given channel.
131 pub fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { 111 pub fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) {
132 self.inner.set_input_capture_mode(channel, mode); 112 self.inner.set_input_capture_mode(channel, mode);
@@ -148,10 +128,13 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
148 } 128 }
149 129
150 fn new_future(&self, channel: Channel, mode: InputCaptureMode, tisel: InputTISelection) -> InputCaptureFuture<T> { 130 fn new_future(&self, channel: Channel, mode: InputCaptureMode, tisel: InputTISelection) -> InputCaptureFuture<T> {
151 self.inner.enable_channel(channel, true); 131 // Configuration steps from ST RM0390 (STM32F446) chapter 17.3.5
152 self.inner.set_input_capture_mode(channel, mode); 132 // or ST RM0008 (STM32F103) chapter 15.3.5 Input capture mode
153 self.inner.set_input_ti_selection(channel, tisel); 133 self.inner.set_input_ti_selection(channel, tisel);
154 self.inner.clear_input_interrupt(channel); 134 self.inner.set_input_capture_filter(channel, FilterValue::NOFILTER);
135 self.inner.set_input_capture_mode(channel, mode);
136 self.inner.set_input_capture_prescaler(channel, 0);
137 self.inner.enable_channel(channel, true);
155 self.inner.enable_input_interrupt(channel, true); 138 self.inner.enable_input_interrupt(channel, true);
156 139
157 InputCaptureFuture { 140 InputCaptureFuture {
diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs
index 7f533b75c..e643722aa 100644
--- a/embassy-stm32/src/timer/low_level.rs
+++ b/embassy-stm32/src/timer/low_level.rs
@@ -7,9 +7,12 @@
7//! The available functionality depends on the timer type. 7//! The available functionality depends on the timer type.
8 8
9use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; 9use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
10// Re-export useful enums
11pub use stm32_metapac::timer::vals::{FilterValue, Sms as SlaveMode, Ts as TriggerSource};
10 12
11use super::*; 13use super::*;
12use crate::pac::timer::vals; 14use crate::pac::timer::vals;
15use crate::rcc;
13use crate::time::Hertz; 16use crate::time::Hertz;
14 17
15/// Input capture mode. 18/// Input capture mode.
@@ -181,7 +184,7 @@ pub struct Timer<'d, T: CoreInstance> {
181 184
182impl<'d, T: CoreInstance> Drop for Timer<'d, T> { 185impl<'d, T: CoreInstance> Drop for Timer<'d, T> {
183 fn drop(&mut self) { 186 fn drop(&mut self) {
184 T::disable() 187 rcc::disable::<T>();
185 } 188 }
186} 189}
187 190
@@ -190,7 +193,7 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
190 pub fn new(tim: impl Peripheral<P = T> + 'd) -> Self { 193 pub fn new(tim: impl Peripheral<P = T> + 'd) -> Self {
191 into_ref!(tim); 194 into_ref!(tim);
192 195
193 T::enable_and_reset(); 196 rcc::enable_and_reset::<T>();
194 197
195 Self { tim } 198 Self { tim }
196 } 199 }
@@ -273,6 +276,22 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
273 } 276 }
274 } 277 }
275 278
279 /// Set tick frequency.
280 pub fn set_tick_freq(&mut self, freq: Hertz) {
281 let f = freq;
282 assert!(f.0 > 0);
283 let timer_f = self.get_clock_frequency();
284
285 let pclk_ticks_per_timer_period = timer_f / f;
286 let psc: u16 = unwrap!((pclk_ticks_per_timer_period - 1).try_into());
287
288 let regs = self.regs_core();
289 regs.psc().write_value(psc);
290
291 // Generate an Update Request
292 regs.egr().write(|r| r.set_ug(true));
293 }
294
276 /// Clear update interrupt. 295 /// Clear update interrupt.
277 /// 296 ///
278 /// Returns whether the update interrupt flag was set. 297 /// Returns whether the update interrupt flag was set.
@@ -572,6 +591,16 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
572 pub fn set_cc_dma_enable_state(&self, channel: Channel, ccde: bool) { 591 pub fn set_cc_dma_enable_state(&self, channel: Channel, ccde: bool) {
573 self.regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde)) 592 self.regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde))
574 } 593 }
594
595 /// Set Timer Slave Mode
596 pub fn set_slave_mode(&self, sms: SlaveMode) {
597 self.regs_gp16().smcr().modify(|r| r.set_sms(sms));
598 }
599
600 /// Set Timer Trigger Source
601 pub fn set_trigger_source(&self, ts: TriggerSource) {
602 self.regs_gp16().smcr().modify(|r| r.set_ts(ts));
603 }
575} 604}
576 605
577#[cfg(not(stm32l0))] 606#[cfg(not(stm32l0))]
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index 314b6006b..25782ee13 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -8,6 +8,7 @@ use embassy_sync::waitqueue::AtomicWaker;
8pub mod complementary_pwm; 8pub mod complementary_pwm;
9pub mod input_capture; 9pub mod input_capture;
10pub mod low_level; 10pub mod low_level;
11pub mod pwm_input;
11pub mod qei; 12pub mod qei;
12pub mod simple_pwm; 13pub mod simple_pwm;
13 14
diff --git a/embassy-stm32/src/timer/pwm_input.rs b/embassy-stm32/src/timer/pwm_input.rs
new file mode 100644
index 000000000..dcf098a78
--- /dev/null
+++ b/embassy-stm32/src/timer/pwm_input.rs
@@ -0,0 +1,114 @@
1//! PWM Input driver.
2
3use embassy_hal_internal::into_ref;
4
5use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource};
6use super::{Channel, Channel1Pin, Channel2Pin, GeneralInstance4Channel};
7use crate::gpio::{AFType, Pull};
8use crate::time::Hertz;
9use crate::Peripheral;
10
11/// PWM Input driver.
12pub struct PwmInput<'d, T: GeneralInstance4Channel> {
13 channel: Channel,
14 inner: Timer<'d, T>,
15}
16
17impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> {
18 /// Create a new PWM input driver.
19 pub fn new(
20 tim: impl Peripheral<P = T> + 'd,
21 pin: impl Peripheral<P = impl Channel1Pin<T>> + 'd,
22 pull_type: Pull,
23 freq: Hertz,
24 ) -> Self {
25 into_ref!(pin);
26
27 pin.set_as_af_pull(pin.af_num(), AFType::Input, pull_type);
28
29 Self::new_inner(tim, freq, Channel::Ch1, Channel::Ch2)
30 }
31
32 /// Create a new PWM input driver.
33 pub fn new_alt(
34 tim: impl Peripheral<P = T> + 'd,
35 pin: impl Peripheral<P = impl Channel2Pin<T>> + 'd,
36 pull_type: Pull,
37 freq: Hertz,
38 ) -> Self {
39 into_ref!(pin);
40
41 pin.set_as_af_pull(pin.af_num(), AFType::Input, pull_type);
42
43 Self::new_inner(tim, freq, Channel::Ch2, Channel::Ch1)
44 }
45
46 fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz, ch1: Channel, ch2: Channel) -> Self {
47 let mut inner = Timer::new(tim);
48
49 inner.set_counting_mode(CountingMode::EdgeAlignedUp);
50 inner.set_tick_freq(freq);
51 inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details
52 inner.start();
53
54 // Configuration steps from ST RM0390 (STM32F446) chapter 17.3.6
55 // or ST RM0008 (STM32F103) chapter 15.3.6 Input capture mode
56 inner.set_input_ti_selection(ch1, InputTISelection::Normal);
57 inner.set_input_capture_mode(ch1, InputCaptureMode::Rising);
58
59 inner.set_input_ti_selection(ch2, InputTISelection::Alternate);
60 inner.set_input_capture_mode(ch2, InputCaptureMode::Falling);
61
62 inner.set_trigger_source(match ch1 {
63 Channel::Ch1 => TriggerSource::TI1FP1,
64 Channel::Ch2 => TriggerSource::TI2FP2,
65 _ => panic!("Invalid channel for PWM input"),
66 });
67
68 inner.set_slave_mode(SlaveMode::RESET_MODE);
69
70 // Must call the `enable` function after
71
72 Self { channel: ch1, inner }
73 }
74
75 /// Enable the given channel.
76 pub fn enable(&mut self) {
77 self.inner.enable_channel(Channel::Ch1, true);
78 self.inner.enable_channel(Channel::Ch2, true);
79 }
80
81 /// Disable the given channel.
82 pub fn disable(&mut self) {
83 self.inner.enable_channel(Channel::Ch1, false);
84 self.inner.enable_channel(Channel::Ch2, false);
85 }
86
87 /// Check whether given channel is enabled
88 pub fn is_enabled(&self) -> bool {
89 self.inner.get_channel_enable_state(Channel::Ch1)
90 }
91
92 /// Get the period tick count
93 pub fn get_period_ticks(&self) -> u32 {
94 self.inner.get_capture_value(self.channel)
95 }
96
97 /// Get the pulse width tick count
98 pub fn get_width_ticks(&self) -> u32 {
99 self.inner.get_capture_value(match self.channel {
100 Channel::Ch1 => Channel::Ch2,
101 Channel::Ch2 => Channel::Ch1,
102 _ => panic!("Invalid channel for PWM input"),
103 })
104 }
105
106 /// Get the duty cycle in 100%
107 pub fn get_duty_cycle(&self) -> f32 {
108 let period = self.get_period_ticks();
109 if period == 0 {
110 return 0.;
111 }
112 100. * (self.get_width_ticks() as f32) / (period as f32)
113 }
114}
diff --git a/embassy-stm32/src/tsc/mod.rs b/embassy-stm32/src/tsc/mod.rs
index bf583f04c..045d6317c 100644
--- a/embassy-stm32/src/tsc/mod.rs
+++ b/embassy-stm32/src/tsc/mod.rs
@@ -72,7 +72,7 @@ pub use enums::*;
72 72
73use crate::gpio::{AFType, AnyPin}; 73use crate::gpio::{AFType, AnyPin};
74use crate::pac::tsc::Tsc as Regs; 74use crate::pac::tsc::Tsc as Regs;
75use crate::rcc::RccPeripheral; 75use crate::rcc::{self, RccPeripheral};
76use crate::{peripherals, Peripheral}; 76use crate::{peripherals, Peripheral};
77 77
78#[cfg(tsc_v1)] 78#[cfg(tsc_v1)]
@@ -649,7 +649,7 @@ impl<'d, T: Instance> Tsc<'d, T> {
649 ) -> Self { 649 ) -> Self {
650 into_ref!(peri); 650 into_ref!(peri);
651 651
652 T::enable_and_reset(); 652 rcc::enable_and_reset::<T>();
653 653
654 T::REGS.cr().modify(|w| { 654 T::REGS.cr().modify(|w| {
655 w.set_tsce(true); 655 w.set_tsce(true);
@@ -880,7 +880,7 @@ impl<'d, T: Instance> Tsc<'d, T> {
880 880
881impl<'d, T: Instance> Drop for Tsc<'d, T> { 881impl<'d, T: Instance> Drop for Tsc<'d, T> {
882 fn drop(&mut self) { 882 fn drop(&mut self) {
883 T::disable(); 883 rcc::disable::<T>();
884 } 884 }
885} 885}
886 886
diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs
index d6d0682b9..89e2f5d49 100644
--- a/embassy-stm32/src/ucpd.rs
+++ b/embassy-stm32/src/ucpd.rs
@@ -28,7 +28,7 @@ use crate::interrupt;
28use crate::interrupt::typelevel::Interrupt; 28use crate::interrupt::typelevel::Interrupt;
29use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode}; 29use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode};
30pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, TypecVstateCc as CcVState}; 30pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, TypecVstateCc as CcVState};
31use crate::rcc::RccPeripheral; 31use crate::rcc::{self, RccPeripheral};
32 32
33pub(crate) fn init( 33pub(crate) fn init(
34 _cs: critical_section::CriticalSection, 34 _cs: critical_section::CriticalSection,
@@ -103,7 +103,7 @@ impl<'d, T: Instance> Ucpd<'d, T> {
103 cc1.set_as_analog(); 103 cc1.set_as_analog();
104 cc2.set_as_analog(); 104 cc2.set_as_analog();
105 105
106 T::enable_and_reset(); 106 rcc::enable_and_reset::<T>();
107 T::Interrupt::unpend(); 107 T::Interrupt::unpend();
108 unsafe { T::Interrupt::enable() }; 108 unsafe { T::Interrupt::enable() };
109 109
@@ -212,7 +212,7 @@ impl<'d, T: Instance> Drop for CcPhy<'d, T> {
212 drop_not_ready.store(true, Ordering::Relaxed); 212 drop_not_ready.store(true, Ordering::Relaxed);
213 } else { 213 } else {
214 r.cfgr1().write(|w| w.set_ucpden(false)); 214 r.cfgr1().write(|w| w.set_ucpden(false));
215 T::disable(); 215 rcc::disable::<T>();
216 T::Interrupt::disable(); 216 T::Interrupt::disable();
217 } 217 }
218 } 218 }
@@ -325,7 +325,7 @@ impl<'d, T: Instance> Drop for PdPhy<'d, T> {
325 drop_not_ready.store(true, Ordering::Relaxed); 325 drop_not_ready.store(true, Ordering::Relaxed);
326 } else { 326 } else {
327 T::REGS.cfgr1().write(|w| w.set_ucpden(false)); 327 T::REGS.cfgr1().write(|w| w.set_ucpden(false));
328 T::disable(); 328 rcc::disable::<T>();
329 T::Interrupt::disable(); 329 T::Interrupt::disable();
330 } 330 }
331 } 331 }
diff --git a/embassy-stm32/src/usart/buffered.rs b/embassy-stm32/src/usart/buffered.rs
index 492ad334b..fd79e035e 100644
--- a/embassy-stm32/src/usart/buffered.rs
+++ b/embassy-stm32/src/usart/buffered.rs
@@ -6,7 +6,7 @@ use core::task::Poll;
6 6
7use embassy_embedded_hal::SetConfig; 7use embassy_embedded_hal::SetConfig;
8use embassy_hal_internal::atomic_ring_buffer::RingBuffer; 8use embassy_hal_internal::atomic_ring_buffer::RingBuffer;
9use embassy_hal_internal::{into_ref, Peripheral}; 9use embassy_hal_internal::{Peripheral, PeripheralRef};
10use embassy_sync::waitqueue::AtomicWaker; 10use embassy_sync::waitqueue::AtomicWaker;
11 11
12#[cfg(not(any(usart_v1, usart_v2)))] 12#[cfg(not(any(usart_v1, usart_v2)))]
@@ -15,8 +15,7 @@ use super::{
15 clear_interrupt_flags, configure, rdr, reconfigure, sr, tdr, Config, ConfigError, CtsPin, Error, Info, Instance, 15 clear_interrupt_flags, configure, rdr, reconfigure, sr, tdr, Config, ConfigError, CtsPin, Error, Info, Instance,
16 Regs, RtsPin, RxPin, TxPin, 16 Regs, RtsPin, RxPin, TxPin,
17}; 17};
18use crate::gpio::AFType; 18use crate::gpio::{AFType, AnyPin, SealedPin as _};
19use crate::interrupt::typelevel::Interrupt as _;
20use crate::interrupt::{self, InterruptExt}; 19use crate::interrupt::{self, InterruptExt};
21use crate::time::Hertz; 20use crate::time::Hertz;
22 21
@@ -155,7 +154,9 @@ pub struct BufferedUartTx<'d> {
155 info: &'static Info, 154 info: &'static Info,
156 state: &'static State, 155 state: &'static State,
157 kernel_clock: Hertz, 156 kernel_clock: Hertz,
158 _phantom: PhantomData<&'d mut ()>, 157 tx: Option<PeripheralRef<'d, AnyPin>>,
158 cts: Option<PeripheralRef<'d, AnyPin>>,
159 de: Option<PeripheralRef<'d, AnyPin>>,
159} 160}
160 161
161/// Rx-only buffered UART 162/// Rx-only buffered UART
@@ -165,7 +166,8 @@ pub struct BufferedUartRx<'d> {
165 info: &'static Info, 166 info: &'static Info,
166 state: &'static State, 167 state: &'static State,
167 kernel_clock: Hertz, 168 kernel_clock: Hertz,
168 _phantom: PhantomData<&'d mut ()>, 169 rx: Option<PeripheralRef<'d, AnyPin>>,
170 rts: Option<PeripheralRef<'d, AnyPin>>,
169} 171}
170 172
171impl<'d> SetConfig for BufferedUart<'d> { 173impl<'d> SetConfig for BufferedUart<'d> {
@@ -206,9 +208,17 @@ impl<'d> BufferedUart<'d> {
206 rx_buffer: &'d mut [u8], 208 rx_buffer: &'d mut [u8],
207 config: Config, 209 config: Config,
208 ) -> Result<Self, ConfigError> { 210 ) -> Result<Self, ConfigError> {
209 T::enable_and_reset(); 211 Self::new_inner(
210 212 peri,
211 Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) 213 new_pin!(rx, AFType::Input),
214 new_pin!(tx, AFType::OutputPushPull),
215 None,
216 None,
217 None,
218 tx_buffer,
219 rx_buffer,
220 config,
221 )
212 } 222 }
213 223
214 /// Create a new bidirectional buffered UART driver with request-to-send and clear-to-send pins 224 /// Create a new bidirectional buffered UART driver with request-to-send and clear-to-send pins
@@ -223,18 +233,17 @@ impl<'d> BufferedUart<'d> {
223 rx_buffer: &'d mut [u8], 233 rx_buffer: &'d mut [u8],
224 config: Config, 234 config: Config,
225 ) -> Result<Self, ConfigError> { 235 ) -> Result<Self, ConfigError> {
226 into_ref!(cts, rts); 236 Self::new_inner(
227 237 peri,
228 T::enable_and_reset(); 238 new_pin!(rx, AFType::Input),
229 239 new_pin!(tx, AFType::OutputPushPull),
230 rts.set_as_af(rts.af_num(), AFType::OutputPushPull); 240 new_pin!(rts, AFType::OutputPushPull),
231 cts.set_as_af(cts.af_num(), AFType::Input); 241 new_pin!(cts, AFType::Input),
232 T::info().regs.cr3().write(|w| { 242 None,
233 w.set_rtse(true); 243 tx_buffer,
234 w.set_ctse(true); 244 rx_buffer,
235 }); 245 config,
236 246 )
237 Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
238 } 247 }
239 248
240 /// Create a new bidirectional buffered UART driver with a driver-enable pin 249 /// Create a new bidirectional buffered UART driver with a driver-enable pin
@@ -249,66 +258,89 @@ impl<'d> BufferedUart<'d> {
249 rx_buffer: &'d mut [u8], 258 rx_buffer: &'d mut [u8],
250 config: Config, 259 config: Config,
251 ) -> Result<Self, ConfigError> { 260 ) -> Result<Self, ConfigError> {
252 into_ref!(de); 261 Self::new_inner(
253 262 peri,
254 T::enable_and_reset(); 263 new_pin!(rx, AFType::Input),
255 264 new_pin!(tx, AFType::OutputPushPull),
256 de.set_as_af(de.af_num(), AFType::OutputPushPull); 265 None,
257 T::info().regs.cr3().write(|w| { 266 None,
258 w.set_dem(true); 267 new_pin!(de, AFType::OutputPushPull),
259 }); 268 tx_buffer,
260 269 rx_buffer,
261 Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config) 270 config,
271 )
262 } 272 }
263 273
264 fn new_inner<T: Instance>( 274 fn new_inner<T: Instance>(
265 _peri: impl Peripheral<P = T> + 'd, 275 _peri: impl Peripheral<P = T> + 'd,
266 rx: impl Peripheral<P = impl RxPin<T>> + 'd, 276 rx: Option<PeripheralRef<'d, AnyPin>>,
267 tx: impl Peripheral<P = impl TxPin<T>> + 'd, 277 tx: Option<PeripheralRef<'d, AnyPin>>,
278 rts: Option<PeripheralRef<'d, AnyPin>>,
279 cts: Option<PeripheralRef<'d, AnyPin>>,
280 de: Option<PeripheralRef<'d, AnyPin>>,
268 tx_buffer: &'d mut [u8], 281 tx_buffer: &'d mut [u8],
269 rx_buffer: &'d mut [u8], 282 rx_buffer: &'d mut [u8],
270 config: Config, 283 config: Config,
271 ) -> Result<Self, ConfigError> { 284 ) -> Result<Self, ConfigError> {
272 into_ref!(_peri, rx, tx);
273
274 let info = T::info(); 285 let info = T::info();
275 let state = T::buffered_state(); 286 let state = T::buffered_state();
276 let kernel_clock = T::frequency(); 287 let kernel_clock = T::frequency();
277 let len = tx_buffer.len();
278 unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
279 let len = rx_buffer.len();
280 unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
281
282 let r = info.regs;
283 rx.set_as_af(rx.af_num(), AFType::Input);
284 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
285
286 configure(info, kernel_clock, &config, true, true)?;
287
288 r.cr1().modify(|w| {
289 w.set_rxneie(true);
290 w.set_idleie(true);
291 });
292
293 T::Interrupt::unpend();
294 unsafe { T::Interrupt::enable() };
295 288
296 state.tx_rx_refcount.store(2, Ordering::Relaxed); 289 let mut this = Self {
297
298 Ok(Self {
299 rx: BufferedUartRx { 290 rx: BufferedUartRx {
300 info, 291 info,
301 state, 292 state,
302 kernel_clock, 293 kernel_clock,
303 _phantom: PhantomData, 294 rx,
295 rts,
304 }, 296 },
305 tx: BufferedUartTx { 297 tx: BufferedUartTx {
306 info, 298 info,
307 state, 299 state,
308 kernel_clock, 300 kernel_clock,
309 _phantom: PhantomData, 301 tx,
302 cts,
303 de,
310 }, 304 },
311 }) 305 };
306 this.enable_and_configure(tx_buffer, rx_buffer, &config)?;
307 Ok(this)
308 }
309
310 fn enable_and_configure(
311 &mut self,
312 tx_buffer: &'d mut [u8],
313 rx_buffer: &'d mut [u8],
314 config: &Config,
315 ) -> Result<(), ConfigError> {
316 let info = self.rx.info;
317 let state = self.rx.state;
318 state.tx_rx_refcount.store(2, Ordering::Relaxed);
319
320 info.rcc.enable_and_reset();
321
322 let len = tx_buffer.len();
323 unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
324 let len = rx_buffer.len();
325 unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
326
327 info.regs.cr3().write(|w| {
328 w.set_rtse(self.rx.rts.is_some());
329 w.set_ctse(self.tx.cts.is_some());
330 #[cfg(not(any(usart_v1, usart_v2)))]
331 w.set_dem(self.tx.de.is_some());
332 });
333 configure(info, self.rx.kernel_clock, &config, true, true)?;
334
335 info.regs.cr1().modify(|w| {
336 w.set_rxneie(true);
337 w.set_idleie(true);
338 });
339
340 info.interrupt.unpend();
341 unsafe { info.interrupt.enable() };
342
343 Ok(())
312 } 344 }
313 345
314 /// Split the driver into a Tx and Rx part (useful for sending to separate tasks) 346 /// Split the driver into a Tx and Rx part (useful for sending to separate tasks)
@@ -515,6 +547,8 @@ impl<'d> Drop for BufferedUartRx<'d> {
515 } 547 }
516 } 548 }
517 549
550 self.rx.as_ref().map(|x| x.set_as_disconnected());
551 self.rts.as_ref().map(|x| x.set_as_disconnected());
518 drop_tx_rx(self.info, state); 552 drop_tx_rx(self.info, state);
519 } 553 }
520} 554}
@@ -532,6 +566,9 @@ impl<'d> Drop for BufferedUartTx<'d> {
532 } 566 }
533 } 567 }
534 568
569 self.tx.as_ref().map(|x| x.set_as_disconnected());
570 self.cts.as_ref().map(|x| x.set_as_disconnected());
571 self.de.as_ref().map(|x| x.set_as_disconnected());
535 drop_tx_rx(self.info, state); 572 drop_tx_rx(self.info, state);
536 } 573 }
537} 574}
@@ -545,7 +582,7 @@ fn drop_tx_rx(info: &Info, state: &State) {
545 refcount == 1 582 refcount == 1
546 }); 583 });
547 if is_last_drop { 584 if is_last_drop {
548 info.enable_bit.disable(); 585 info.rcc.disable();
549 } 586 }
550} 587}
551 588
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index b24335f3a..53321391a 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -14,7 +14,7 @@ use embassy_sync::waitqueue::AtomicWaker;
14use futures_util::future::{select, Either}; 14use futures_util::future::{select, Either};
15 15
16use crate::dma::ChannelAndRequest; 16use crate::dma::ChannelAndRequest;
17use crate::gpio::{AFType, AnyPin, SealedPin}; 17use crate::gpio::{AFType, AnyPin, SealedPin as _};
18use crate::interrupt::typelevel::Interrupt as _; 18use crate::interrupt::typelevel::Interrupt as _;
19use crate::interrupt::{self, Interrupt, InterruptExt}; 19use crate::interrupt::{self, Interrupt, InterruptExt};
20use crate::mode::{Async, Blocking, Mode}; 20use crate::mode::{Async, Blocking, Mode};
@@ -28,7 +28,7 @@ use crate::pac::usart::Lpuart as Regs;
28#[cfg(any(usart_v1, usart_v2))] 28#[cfg(any(usart_v1, usart_v2))]
29use crate::pac::usart::Usart as Regs; 29use crate::pac::usart::Usart as Regs;
30use crate::pac::usart::{regs, vals}; 30use crate::pac::usart::{regs, vals};
31use crate::rcc::{ClockEnableBit, SealedRccPeripheral}; 31use crate::rcc::{RccInfo, SealedRccPeripheral};
32use crate::time::Hertz; 32use crate::time::Hertz;
33use crate::Peripheral; 33use crate::Peripheral;
34 34
@@ -429,29 +429,33 @@ impl<'d, M: Mode> UartTx<'d, M> {
429 tx_dma: Option<ChannelAndRequest<'d>>, 429 tx_dma: Option<ChannelAndRequest<'d>>,
430 config: Config, 430 config: Config,
431 ) -> Result<Self, ConfigError> { 431 ) -> Result<Self, ConfigError> {
432 T::enable_and_reset(); 432 let mut this = Self {
433 433 info: T::info(),
434 let info = T::info(); 434 state: T::state(),
435 let state = T::state(); 435 kernel_clock: T::frequency(),
436 let kernel_clock = T::frequency();
437 let r = info.regs;
438 r.cr3().modify(|w| {
439 w.set_ctse(cts.is_some());
440 });
441 configure(info, kernel_clock, &config, false, true)?;
442
443 state.tx_rx_refcount.store(1, Ordering::Relaxed);
444
445 Ok(Self {
446 info,
447 state,
448 kernel_clock,
449 tx, 436 tx,
450 cts, 437 cts,
451 de: None, 438 de: None,
452 tx_dma, 439 tx_dma,
453 _phantom: PhantomData, 440 _phantom: PhantomData,
454 }) 441 };
442 this.enable_and_configure(&config)?;
443 Ok(this)
444 }
445
446 fn enable_and_configure(&mut self, config: &Config) -> Result<(), ConfigError> {
447 let info = self.info;
448 let state = self.state;
449 state.tx_rx_refcount.store(1, Ordering::Relaxed);
450
451 info.rcc.enable_and_reset();
452
453 info.regs.cr3().modify(|w| {
454 w.set_ctse(self.cts.is_some());
455 });
456 configure(info, self.kernel_clock, config, false, true)?;
457
458 Ok(())
455 } 459 }
456 460
457 /// Reconfigure the driver 461 /// Reconfigure the driver
@@ -775,34 +779,38 @@ impl<'d, M: Mode> UartRx<'d, M> {
775 rx_dma: Option<ChannelAndRequest<'d>>, 779 rx_dma: Option<ChannelAndRequest<'d>>,
776 config: Config, 780 config: Config,
777 ) -> Result<Self, ConfigError> { 781 ) -> Result<Self, ConfigError> {
778 T::enable_and_reset(); 782 let mut this = Self {
779
780 let info = T::info();
781 let state = T::state();
782 let kernel_clock = T::frequency();
783 let r = info.regs;
784 r.cr3().write(|w| {
785 w.set_rtse(rts.is_some());
786 });
787 configure(info, kernel_clock, &config, true, false)?;
788
789 T::Interrupt::unpend();
790 unsafe { T::Interrupt::enable() };
791
792 state.tx_rx_refcount.store(1, Ordering::Relaxed);
793
794 Ok(Self {
795 _phantom: PhantomData, 783 _phantom: PhantomData,
796 info, 784 info: T::info(),
797 state, 785 state: T::state(),
798 kernel_clock, 786 kernel_clock: T::frequency(),
799 rx, 787 rx,
800 rts, 788 rts,
801 rx_dma, 789 rx_dma,
802 detect_previous_overrun: config.detect_previous_overrun, 790 detect_previous_overrun: config.detect_previous_overrun,
803 #[cfg(any(usart_v1, usart_v2))] 791 #[cfg(any(usart_v1, usart_v2))]
804 buffered_sr: stm32_metapac::usart::regs::Sr(0), 792 buffered_sr: stm32_metapac::usart::regs::Sr(0),
805 }) 793 };
794 this.enable_and_configure(&config)?;
795 Ok(this)
796 }
797
798 fn enable_and_configure(&mut self, config: &Config) -> Result<(), ConfigError> {
799 let info = self.info;
800 let state = self.state;
801 state.tx_rx_refcount.store(1, Ordering::Relaxed);
802
803 info.rcc.enable_and_reset();
804
805 info.regs.cr3().write(|w| {
806 w.set_rtse(self.rts.is_some());
807 });
808 configure(info, self.kernel_clock, &config, true, false)?;
809
810 info.interrupt.unpend();
811 unsafe { info.interrupt.enable() };
812
813 Ok(())
806 } 814 }
807 815
808 /// Reconfigure the driver 816 /// Reconfigure the driver
@@ -916,7 +924,7 @@ fn drop_tx_rx(info: &Info, state: &State) {
916 refcount == 1 924 refcount == 1
917 }); 925 });
918 if is_last_drop { 926 if is_last_drop {
919 info.enable_bit.disable(); 927 info.rcc.disable();
920 } 928 }
921} 929}
922 930
@@ -1228,27 +1236,11 @@ impl<'d, M: Mode> Uart<'d, M> {
1228 rx_dma: Option<ChannelAndRequest<'d>>, 1236 rx_dma: Option<ChannelAndRequest<'d>>,
1229 config: Config, 1237 config: Config,
1230 ) -> Result<Self, ConfigError> { 1238 ) -> Result<Self, ConfigError> {
1231 T::enable_and_reset();
1232
1233 let info = T::info(); 1239 let info = T::info();
1234 let state = T::state(); 1240 let state = T::state();
1235 let kernel_clock = T::frequency(); 1241 let kernel_clock = T::frequency();
1236 let r = info.regs;
1237
1238 r.cr3().write(|w| {
1239 w.set_rtse(rts.is_some());
1240 w.set_ctse(cts.is_some());
1241 #[cfg(not(any(usart_v1, usart_v2)))]
1242 w.set_dem(de.is_some());
1243 });
1244 configure(info, kernel_clock, &config, true, true)?;
1245
1246 T::Interrupt::unpend();
1247 unsafe { T::Interrupt::enable() };
1248 1242
1249 state.tx_rx_refcount.store(2, Ordering::Relaxed); 1243 let mut this = Self {
1250
1251 Ok(Self {
1252 tx: UartTx { 1244 tx: UartTx {
1253 _phantom: PhantomData, 1245 _phantom: PhantomData,
1254 info, 1246 info,
@@ -1271,7 +1263,30 @@ impl<'d, M: Mode> Uart<'d, M> {
1271 #[cfg(any(usart_v1, usart_v2))] 1263 #[cfg(any(usart_v1, usart_v2))]
1272 buffered_sr: stm32_metapac::usart::regs::Sr(0), 1264 buffered_sr: stm32_metapac::usart::regs::Sr(0),
1273 }, 1265 },
1274 }) 1266 };
1267 this.enable_and_configure(&config)?;
1268 Ok(this)
1269 }
1270
1271 fn enable_and_configure(&mut self, config: &Config) -> Result<(), ConfigError> {
1272 let info = self.rx.info;
1273 let state = self.rx.state;
1274 state.tx_rx_refcount.store(2, Ordering::Relaxed);
1275
1276 info.rcc.enable_and_reset();
1277
1278 info.regs.cr3().write(|w| {
1279 w.set_rtse(self.rx.rts.is_some());
1280 w.set_ctse(self.tx.cts.is_some());
1281 #[cfg(not(any(usart_v1, usart_v2)))]
1282 w.set_dem(self.tx.de.is_some());
1283 });
1284 configure(info, self.rx.kernel_clock, config, true, true)?;
1285
1286 info.interrupt.unpend();
1287 unsafe { info.interrupt.enable() };
1288
1289 Ok(())
1275 } 1290 }
1276 1291
1277 /// Perform a blocking write 1292 /// Perform a blocking write
@@ -1718,7 +1733,7 @@ impl State {
1718 1733
1719struct Info { 1734struct Info {
1720 regs: Regs, 1735 regs: Regs,
1721 enable_bit: ClockEnableBit, 1736 rcc: RccInfo,
1722 interrupt: Interrupt, 1737 interrupt: Interrupt,
1723 kind: Kind, 1738 kind: Kind,
1724} 1739}
@@ -1754,7 +1769,7 @@ macro_rules! impl_usart {
1754 fn info() -> &'static Info { 1769 fn info() -> &'static Info {
1755 static INFO: Info = Info { 1770 static INFO: Info = Info {
1756 regs: unsafe { Regs::from_ptr(crate::pac::$inst.as_ptr()) }, 1771 regs: unsafe { Regs::from_ptr(crate::pac::$inst.as_ptr()) },
1757 enable_bit: crate::peripherals::$inst::ENABLE_BIT, 1772 rcc: crate::peripherals::$inst::RCC_INFO,
1758 interrupt: crate::interrupt::typelevel::$irq::IRQ, 1773 interrupt: crate::interrupt::typelevel::$irq::IRQ,
1759 kind: $kind, 1774 kind: $kind,
1760 }; 1775 };
diff --git a/embassy-stm32/src/usart/ringbuffered.rs b/embassy-stm32/src/usart/ringbuffered.rs
index f3a88b93f..8cf75933a 100644
--- a/embassy-stm32/src/usart/ringbuffered.rs
+++ b/embassy-stm32/src/usart/ringbuffered.rs
@@ -4,10 +4,12 @@ use core::sync::atomic::{compiler_fence, Ordering};
4use core::task::Poll; 4use core::task::Poll;
5 5
6use embassy_embedded_hal::SetConfig; 6use embassy_embedded_hal::SetConfig;
7use embassy_hal_internal::PeripheralRef;
7use futures_util::future::{select, Either}; 8use futures_util::future::{select, Either};
8 9
9use super::{clear_interrupt_flags, rdr, reconfigure, sr, Config, ConfigError, Error, Info, State, UartRx}; 10use super::{clear_interrupt_flags, rdr, reconfigure, sr, Config, ConfigError, Error, Info, State, UartRx};
10use crate::dma::ReadableRingBuffer; 11use crate::dma::ReadableRingBuffer;
12use crate::gpio::{AnyPin, SealedPin as _};
11use crate::mode::Async; 13use crate::mode::Async;
12use crate::time::Hertz; 14use crate::time::Hertz;
13use crate::usart::{Regs, Sr}; 15use crate::usart::{Regs, Sr};
@@ -19,6 +21,8 @@ pub struct RingBufferedUartRx<'d> {
19 info: &'static Info, 21 info: &'static Info,
20 state: &'static State, 22 state: &'static State,
21 kernel_clock: Hertz, 23 kernel_clock: Hertz,
24 rx: Option<PeripheralRef<'d, AnyPin>>,
25 rts: Option<PeripheralRef<'d, AnyPin>>,
22 ring_buf: ReadableRingBuffer<'d, u8>, 26 ring_buf: ReadableRingBuffer<'d, u8>,
23} 27}
24 28
@@ -49,6 +53,8 @@ impl<'d> UartRx<'d, Async> {
49 let state = self.state; 53 let state = self.state;
50 let kernel_clock = self.kernel_clock; 54 let kernel_clock = self.kernel_clock;
51 let ring_buf = unsafe { ReadableRingBuffer::new(rx_dma, request, rdr(info.regs), dma_buf, opts) }; 55 let ring_buf = unsafe { ReadableRingBuffer::new(rx_dma, request, rdr(info.regs), dma_buf, opts) };
56 let rx = unsafe { self.rx.as_ref().map(|x| x.clone_unchecked()) };
57 let rts = unsafe { self.rts.as_ref().map(|x| x.clone_unchecked()) };
52 58
53 // Don't disable the clock 59 // Don't disable the clock
54 mem::forget(self); 60 mem::forget(self);
@@ -57,6 +63,8 @@ impl<'d> UartRx<'d, Async> {
57 info, 63 info,
58 state, 64 state,
59 kernel_clock, 65 kernel_clock,
66 rx,
67 rts,
60 ring_buf, 68 ring_buf,
61 } 69 }
62 } 70 }
@@ -221,6 +229,8 @@ impl<'d> RingBufferedUartRx<'d> {
221impl Drop for RingBufferedUartRx<'_> { 229impl Drop for RingBufferedUartRx<'_> {
222 fn drop(&mut self) { 230 fn drop(&mut self) {
223 self.teardown_uart(); 231 self.teardown_uart();
232 self.rx.as_ref().map(|x| x.set_as_disconnected());
233 self.rts.as_ref().map(|x| x.set_as_disconnected());
224 super::drop_tx_rx(self.info, self.state); 234 super::drop_tx_rx(self.info, self.state);
225 } 235 }
226} 236}
diff --git a/embassy-stm32/src/usb/mod.rs b/embassy-stm32/src/usb/mod.rs
index 349438ec5..ce9fe0a9b 100644
--- a/embassy-stm32/src/usb/mod.rs
+++ b/embassy-stm32/src/usb/mod.rs
@@ -6,7 +6,7 @@ mod _version;
6pub use _version::*; 6pub use _version::*;
7 7
8use crate::interrupt::typelevel::Interrupt; 8use crate::interrupt::typelevel::Interrupt;
9use crate::rcc::SealedRccPeripheral; 9use crate::rcc;
10 10
11/// clock, power initialization stuff that's common for USB and OTG. 11/// clock, power initialization stuff that's common for USB and OTG.
12fn common_init<T: Instance>() { 12fn common_init<T: Instance>() {
@@ -65,5 +65,5 @@ fn common_init<T: Instance>() {
65 T::Interrupt::unpend(); 65 T::Interrupt::unpend();
66 unsafe { T::Interrupt::enable() }; 66 unsafe { T::Interrupt::enable() };
67 67
68 <T as SealedRccPeripheral>::enable_and_reset(); 68 rcc::enable_and_reset::<T>();
69} 69}
diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs
index 3debd5079..e5131250a 100644
--- a/embassy-stm32/src/usb/otg.rs
+++ b/embassy-stm32/src/usb/otg.rs
@@ -13,7 +13,7 @@ use embassy_usb_synopsys_otg::{
13use crate::gpio::AFType; 13use crate::gpio::AFType;
14use crate::interrupt; 14use crate::interrupt;
15use crate::interrupt::typelevel::Interrupt; 15use crate::interrupt::typelevel::Interrupt;
16use crate::rcc::{RccPeripheral, SealedRccPeripheral}; 16use crate::rcc::{self, RccPeripheral};
17 17
18const MAX_EP_COUNT: usize = 9; 18const MAX_EP_COUNT: usize = 9;
19 19
@@ -246,7 +246,7 @@ impl<'d, T: Instance> Bus<'d, T> {
246 fn disable(&mut self) { 246 fn disable(&mut self) {
247 T::Interrupt::disable(); 247 T::Interrupt::disable();
248 248
249 <T as SealedRccPeripheral>::disable(); 249 rcc::disable::<T>();
250 self.inited = false; 250 self.inited = false;
251 251
252 #[cfg(stm32l4)] 252 #[cfg(stm32l4)]
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index 81a2d2623..b6c88ac9a 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -267,9 +267,9 @@ impl<'d, T: Instance> Driver<'d, T> {
267 w.set_fres(true); 267 w.set_fres(true);
268 }); 268 });
269 269
270 #[cfg(time)] 270 #[cfg(feature = "time")]
271 embassy_time::block_for(embassy_time::Duration::from_millis(100)); 271 embassy_time::block_for(embassy_time::Duration::from_millis(100));
272 #[cfg(not(time))] 272 #[cfg(not(feature = "time"))]
273 cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 10); 273 cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 10);
274 274
275 #[cfg(not(usb_v4))] 275 #[cfg(not(usb_v4))]
diff --git a/embassy-sync/build.rs b/embassy-sync/build.rs
index afd76dad1..ecd2c0c9f 100644
--- a/embassy-sync/build.rs
+++ b/embassy-sync/build.rs
@@ -1,31 +1,7 @@
1use std::env; 1#[path = "./build_common.rs"]
2mod common;
2 3
3fn main() { 4fn main() {
4 println!("cargo:rerun-if-changed=build.rs"); 5 let mut cfgs = common::CfgSet::new();
5 6 common::set_target_cfgs(&mut cfgs);
6 let target = env::var("TARGET").unwrap();
7
8 if target.starts_with("thumbv6m-") {
9 println!("cargo:rustc-cfg=cortex_m");
10 println!("cargo:rustc-cfg=armv6m");
11 } else if target.starts_with("thumbv7m-") {
12 println!("cargo:rustc-cfg=cortex_m");
13 println!("cargo:rustc-cfg=armv7m");
14 } else if target.starts_with("thumbv7em-") {
15 println!("cargo:rustc-cfg=cortex_m");
16 println!("cargo:rustc-cfg=armv7m");
17 println!("cargo:rustc-cfg=armv7em"); // (not currently used)
18 } else if target.starts_with("thumbv8m.base") {
19 println!("cargo:rustc-cfg=cortex_m");
20 println!("cargo:rustc-cfg=armv8m");
21 println!("cargo:rustc-cfg=armv8m_base");
22 } else if target.starts_with("thumbv8m.main") {
23 println!("cargo:rustc-cfg=cortex_m");
24 println!("cargo:rustc-cfg=armv8m");
25 println!("cargo:rustc-cfg=armv8m_main");
26 }
27
28 if target.ends_with("-eabihf") {
29 println!("cargo:rustc-cfg=has_fpu");
30 }
31} 7}
diff --git a/embassy-sync/build_common.rs b/embassy-sync/build_common.rs
new file mode 100644
index 000000000..2c65f8529
--- /dev/null
+++ b/embassy-sync/build_common.rs
@@ -0,0 +1,109 @@
1// NOTE: this file is copy-pasted between several Embassy crates, because there is no
2// straightforward way to share this code:
3// - it cannot be placed into the root of the repo and linked from each build.rs using `#[path =
4// "../build_common.rs"]`, because `cargo publish` requires that all files published with a crate
5// reside in the crate's directory,
6// - it cannot be symlinked from `embassy-xxx/build_common.rs` to `../build_common.rs`, because
7// symlinks don't work on Windows.
8
9use std::collections::HashSet;
10use std::env;
11use std::ffi::OsString;
12use std::process::Command;
13
14/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring
15/// them (`cargo:rust-check-cfg=cfg(X)`).
16#[derive(Debug)]
17pub struct CfgSet {
18 enabled: HashSet<String>,
19 declared: HashSet<String>,
20 emit_declared: bool,
21}
22
23impl CfgSet {
24 pub fn new() -> Self {
25 Self {
26 enabled: HashSet::new(),
27 declared: HashSet::new(),
28 emit_declared: is_rustc_nightly(),
29 }
30 }
31
32 /// Enable a config, which can then be used in `#[cfg(...)]` for conditional compilation.
33 ///
34 /// All configs that can potentially be enabled should be unconditionally declared using
35 /// [`Self::declare()`].
36 pub fn enable(&mut self, cfg: impl AsRef<str>) {
37 if self.enabled.insert(cfg.as_ref().to_owned()) {
38 println!("cargo:rustc-cfg={}", cfg.as_ref());
39 }
40 }
41
42 pub fn enable_all(&mut self, cfgs: &[impl AsRef<str>]) {
43 for cfg in cfgs.iter() {
44 self.enable(cfg.as_ref());
45 }
46 }
47
48 /// Declare a valid config for conditional compilation, without enabling it.
49 ///
50 /// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid.
51 pub fn declare(&mut self, cfg: impl AsRef<str>) {
52 if self.declared.insert(cfg.as_ref().to_owned()) && self.emit_declared {
53 println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref());
54 }
55 }
56
57 pub fn declare_all(&mut self, cfgs: &[impl AsRef<str>]) {
58 for cfg in cfgs.iter() {
59 self.declare(cfg.as_ref());
60 }
61 }
62
63 pub fn set(&mut self, cfg: impl Into<String>, enable: bool) {
64 let cfg = cfg.into();
65 if enable {
66 self.enable(cfg.clone());
67 }
68 self.declare(cfg);
69 }
70}
71
72fn is_rustc_nightly() -> bool {
73 let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
74
75 let output = Command::new(rustc)
76 .arg("--version")
77 .output()
78 .expect("failed to run `rustc --version`");
79
80 String::from_utf8_lossy(&output.stdout).contains("nightly")
81}
82
83/// Sets configs that describe the target platform.
84pub fn set_target_cfgs(cfgs: &mut CfgSet) {
85 let target = env::var("TARGET").unwrap();
86
87 if target.starts_with("thumbv6m-") {
88 cfgs.enable_all(&["cortex_m", "armv6m"]);
89 } else if target.starts_with("thumbv7m-") {
90 cfgs.enable_all(&["cortex_m", "armv7m"]);
91 } else if target.starts_with("thumbv7em-") {
92 cfgs.enable_all(&["cortex_m", "armv7m", "armv7em"]);
93 } else if target.starts_with("thumbv8m.base") {
94 cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_base"]);
95 } else if target.starts_with("thumbv8m.main") {
96 cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_main"]);
97 }
98 cfgs.declare_all(&[
99 "cortex_m",
100 "armv6m",
101 "armv7m",
102 "armv7em",
103 "armv8m",
104 "armv8m_base",
105 "armv8m_main",
106 ]);
107
108 cfgs.set("has_fpu", target.ends_with("-eabihf"));
109}
diff --git a/embassy-sync/src/lib.rs b/embassy-sync/src/lib.rs
index 1873483f9..a5eee8d02 100644
--- a/embassy-sync/src/lib.rs
+++ b/embassy-sync/src/lib.rs
@@ -1,4 +1,4 @@
1#![cfg_attr(not(any(feature = "std", feature = "wasm")), no_std)] 1#![cfg_attr(not(feature = "std"), no_std)]
2#![allow(async_fn_in_trait)] 2#![allow(async_fn_in_trait)]
3#![allow(clippy::new_without_default)] 3#![allow(clippy::new_without_default)]
4#![doc = include_str!("../README.md")] 4#![doc = include_str!("../README.md")]
diff --git a/embassy-time/Cargo.toml b/embassy-time/Cargo.toml
index ca7ad2d09..ce3f3d8c2 100644
--- a/embassy-time/Cargo.toml
+++ b/embassy-time/Cargo.toml
@@ -27,9 +27,17 @@ features = ["defmt", "std"]
27std = ["tick-hz-1_000_000", "critical-section/std"] 27std = ["tick-hz-1_000_000", "critical-section/std"]
28wasm = ["dep:wasm-bindgen", "dep:js-sys", "dep:wasm-timer", "tick-hz-1_000_000"] 28wasm = ["dep:wasm-bindgen", "dep:js-sys", "dep:wasm-timer", "tick-hz-1_000_000"]
29 29
30## Display a timestamp of the number of seconds since startup next to defmt log messages 30## Display the time since startup next to defmt log messages.
31## At most 1 `defmt-timestamp-uptime-*` feature can be used.
32## `defmt-timestamp-uptime` is provided for backwards compatibility (provides the same format as `uptime-us`).
31## To use this you must have a time driver provided. 33## To use this you must have a time driver provided.
32defmt-timestamp-uptime = ["defmt"] 34defmt-timestamp-uptime = ["defmt"]
35defmt-timestamp-uptime-s = ["defmt"]
36defmt-timestamp-uptime-ms = ["defmt"]
37defmt-timestamp-uptime-us = ["defmt"]
38defmt-timestamp-uptime-ts = ["defmt"]
39defmt-timestamp-uptime-tms = ["defmt"]
40defmt-timestamp-uptime-tus = ["defmt"]
33 41
34## Create a `MockDriver` that can be manually advanced for testing purposes. 42## Create a `MockDriver` that can be manually advanced for testing purposes.
35mock-driver = ["tick-hz-1_000_000"] 43mock-driver = ["tick-hz-1_000_000"]
diff --git a/embassy-time/src/lib.rs b/embassy-time/src/lib.rs
index 3c8575ee9..24ee51be7 100644
--- a/embassy-time/src/lib.rs
+++ b/embassy-time/src/lib.rs
@@ -46,5 +46,20 @@ pub(crate) const GCD_1K: u64 = gcd(TICK_HZ, 1_000);
46pub(crate) const GCD_1M: u64 = gcd(TICK_HZ, 1_000_000); 46pub(crate) const GCD_1M: u64 = gcd(TICK_HZ, 1_000_000);
47pub(crate) const GCD_1G: u64 = gcd(TICK_HZ, 1_000_000_000); 47pub(crate) const GCD_1G: u64 = gcd(TICK_HZ, 1_000_000_000);
48 48
49#[cfg(feature = "defmt-timestamp-uptime")] 49#[cfg(feature = "defmt-timestamp-uptime-s")]
50defmt::timestamp! {"{=u64}", Instant::now().as_secs() }
51
52#[cfg(feature = "defmt-timestamp-uptime-ms")]
53defmt::timestamp! {"{=u64:ms}", Instant::now().as_millis() }
54
55#[cfg(any(feature = "defmt-timestamp-uptime", feature = "defmt-timestamp-uptime-us"))]
50defmt::timestamp! {"{=u64:us}", Instant::now().as_micros() } 56defmt::timestamp! {"{=u64:us}", Instant::now().as_micros() }
57
58#[cfg(feature = "defmt-timestamp-uptime-ts")]
59defmt::timestamp! {"{=u64:ts}", Instant::now().as_secs() }
60
61#[cfg(feature = "defmt-timestamp-uptime-tms")]
62defmt::timestamp! {"{=u64:tms}", Instant::now().as_millis() }
63
64#[cfg(feature = "defmt-timestamp-uptime-tus")]
65defmt::timestamp! {"{=u64:tus}", Instant::now().as_micros() }
diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml
index 267e412c0..ca87bcb62 100644
--- a/embassy-usb-dfu/Cargo.toml
+++ b/embassy-usb-dfu/Cargo.toml
@@ -26,9 +26,11 @@ flavors = [
26features = ["defmt", "cortex-m", "dfu"] 26features = ["defmt", "cortex-m", "dfu"]
27 27
28[dependencies] 28[dependencies]
29defmt = { version = "0.3.5", optional = true }
30log = { version = "0.4.17", optional = true }
31
29bitflags = "2.4.1" 32bitflags = "2.4.1"
30cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true } 33cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true }
31defmt = { version = "0.3.5", optional = true }
32embassy-boot = { version = "0.2.0", path = "../embassy-boot" } 34embassy-boot = { version = "0.2.0", path = "../embassy-boot" }
33embassy-futures = { version = "0.1.1", path = "../embassy-futures" } 35embassy-futures = { version = "0.1.1", path = "../embassy-futures" }
34embassy-sync = { version = "0.6.0", path = "../embassy-sync" } 36embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
diff --git a/examples/boot/application/nrf/Cargo.toml b/examples/boot/application/nrf/Cargo.toml
index f0a710335..cf34bb7cf 100644
--- a/examples/boot/application/nrf/Cargo.toml
+++ b/examples/boot/application/nrf/Cargo.toml
@@ -25,3 +25,10 @@ cortex-m-rt = "0.7.0"
25ed25519-dalek = ["embassy-boot/ed25519-dalek"] 25ed25519-dalek = ["embassy-boot/ed25519-dalek"]
26ed25519-salty = ["embassy-boot/ed25519-salty"] 26ed25519-salty = ["embassy-boot/ed25519-salty"]
27skip-include = [] 27skip-include = []
28defmt = [
29 "dep:defmt",
30 "dep:defmt-rtt",
31 "embassy-nrf/defmt",
32 "embassy-boot-nrf/defmt",
33 "embassy-sync/defmt",
34]
diff --git a/examples/boot/application/stm32f3/Cargo.toml b/examples/boot/application/stm32f3/Cargo.toml
index fe1a6f5b1..9b79b01ce 100644
--- a/examples/boot/application/stm32f3/Cargo.toml
+++ b/examples/boot/application/stm32f3/Cargo.toml
@@ -23,6 +23,7 @@ cortex-m-rt = "0.7.0"
23[features] 23[features]
24defmt = [ 24defmt = [
25 "dep:defmt", 25 "dep:defmt",
26 "dep:defmt-rtt",
26 "embassy-stm32/defmt", 27 "embassy-stm32/defmt",
27 "embassy-boot-stm32/defmt", 28 "embassy-boot-stm32/defmt",
28 "embassy-sync/defmt", 29 "embassy-sync/defmt",
diff --git a/examples/boot/application/stm32f3/src/bin/a.rs b/examples/boot/application/stm32f3/src/bin/a.rs
index 8858ae3da..b608b2e01 100644
--- a/examples/boot/application/stm32f3/src/bin/a.rs
+++ b/examples/boot/application/stm32f3/src/bin/a.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt")]
5use defmt_rtt::*; 5use defmt_rtt::*;
6use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; 6use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
7use embassy_embedded_hal::adapter::BlockingAsync; 7use embassy_embedded_hal::adapter::BlockingAsync;
diff --git a/examples/boot/application/stm32f3/src/bin/b.rs b/examples/boot/application/stm32f3/src/bin/b.rs
index 22ba82d5e..b1a505631 100644
--- a/examples/boot/application/stm32f3/src/bin/b.rs
+++ b/examples/boot/application/stm32f3/src/bin/b.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt")]
5use defmt_rtt::*; 5use defmt_rtt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::gpio::{Level, Output, Speed}; 7use embassy_stm32::gpio::{Level, Output, Speed};
diff --git a/examples/boot/application/stm32f7/Cargo.toml b/examples/boot/application/stm32f7/Cargo.toml
index 37e362824..0167dfb76 100644
--- a/examples/boot/application/stm32f7/Cargo.toml
+++ b/examples/boot/application/stm32f7/Cargo.toml
@@ -24,6 +24,7 @@ cortex-m-rt = "0.7.0"
24[features] 24[features]
25defmt = [ 25defmt = [
26 "dep:defmt", 26 "dep:defmt",
27 "dep:defmt-rtt",
27 "embassy-stm32/defmt", 28 "embassy-stm32/defmt",
28 "embassy-boot-stm32/defmt", 29 "embassy-boot-stm32/defmt",
29 "embassy-sync/defmt", 30 "embassy-sync/defmt",
diff --git a/examples/boot/application/stm32f7/src/bin/a.rs b/examples/boot/application/stm32f7/src/bin/a.rs
index d3df11fe4..172b4c235 100644
--- a/examples/boot/application/stm32f7/src/bin/a.rs
+++ b/examples/boot/application/stm32f7/src/bin/a.rs
@@ -3,7 +3,7 @@
3 3
4use core::cell::RefCell; 4use core::cell::RefCell;
5 5
6#[cfg(feature = "defmt-rtt")] 6#[cfg(feature = "defmt")]
7use defmt_rtt::*; 7use defmt_rtt::*;
8use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig}; 8use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig};
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
diff --git a/examples/boot/application/stm32f7/src/bin/b.rs b/examples/boot/application/stm32f7/src/bin/b.rs
index 190477204..6bc9c9ab8 100644
--- a/examples/boot/application/stm32f7/src/bin/b.rs
+++ b/examples/boot/application/stm32f7/src/bin/b.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt")]
5use defmt_rtt::*; 5use defmt_rtt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::gpio::{Level, Output, Speed}; 7use embassy_stm32::gpio::{Level, Output, Speed};
diff --git a/examples/boot/application/stm32h7/Cargo.toml b/examples/boot/application/stm32h7/Cargo.toml
index 52cd0b546..61643d485 100644
--- a/examples/boot/application/stm32h7/Cargo.toml
+++ b/examples/boot/application/stm32h7/Cargo.toml
@@ -24,6 +24,7 @@ cortex-m-rt = "0.7.0"
24[features] 24[features]
25defmt = [ 25defmt = [
26 "dep:defmt", 26 "dep:defmt",
27 "dep:defmt-rtt",
27 "embassy-stm32/defmt", 28 "embassy-stm32/defmt",
28 "embassy-boot-stm32/defmt", 29 "embassy-boot-stm32/defmt",
29 "embassy-sync/defmt", 30 "embassy-sync/defmt",
diff --git a/examples/boot/application/stm32h7/src/bin/a.rs b/examples/boot/application/stm32h7/src/bin/a.rs
index f61ac1f71..c1b1a267a 100644
--- a/examples/boot/application/stm32h7/src/bin/a.rs
+++ b/examples/boot/application/stm32h7/src/bin/a.rs
@@ -3,7 +3,7 @@
3 3
4use core::cell::RefCell; 4use core::cell::RefCell;
5 5
6#[cfg(feature = "defmt-rtt")] 6#[cfg(feature = "defmt")]
7use defmt_rtt::*; 7use defmt_rtt::*;
8use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig}; 8use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig};
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
diff --git a/examples/boot/application/stm32h7/src/bin/b.rs b/examples/boot/application/stm32h7/src/bin/b.rs
index 5f3f35207..13bdae1f1 100644
--- a/examples/boot/application/stm32h7/src/bin/b.rs
+++ b/examples/boot/application/stm32h7/src/bin/b.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt")]
5use defmt_rtt::*; 5use defmt_rtt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::gpio::{Level, Output, Speed}; 7use embassy_stm32::gpio::{Level, Output, Speed};
diff --git a/examples/boot/application/stm32l0/Cargo.toml b/examples/boot/application/stm32l0/Cargo.toml
index 0f3cbe654..2990089ac 100644
--- a/examples/boot/application/stm32l0/Cargo.toml
+++ b/examples/boot/application/stm32l0/Cargo.toml
@@ -23,6 +23,7 @@ cortex-m-rt = "0.7.0"
23[features] 23[features]
24defmt = [ 24defmt = [
25 "dep:defmt", 25 "dep:defmt",
26 "dep:defmt-rtt",
26 "embassy-stm32/defmt", 27 "embassy-stm32/defmt",
27 "embassy-boot-stm32/defmt", 28 "embassy-boot-stm32/defmt",
28 "embassy-sync/defmt", 29 "embassy-sync/defmt",
diff --git a/examples/boot/application/stm32l0/src/bin/a.rs b/examples/boot/application/stm32l0/src/bin/a.rs
index f066c1139..dcc10e5c6 100644
--- a/examples/boot/application/stm32l0/src/bin/a.rs
+++ b/examples/boot/application/stm32l0/src/bin/a.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt")]
5use defmt_rtt::*; 5use defmt_rtt::*;
6use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; 6use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
7use embassy_embedded_hal::adapter::BlockingAsync; 7use embassy_embedded_hal::adapter::BlockingAsync;
diff --git a/examples/boot/application/stm32l0/src/bin/b.rs b/examples/boot/application/stm32l0/src/bin/b.rs
index 6bf00f41a..a59c6f540 100644
--- a/examples/boot/application/stm32l0/src/bin/b.rs
+++ b/examples/boot/application/stm32l0/src/bin/b.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt")]
5use defmt_rtt::*; 5use defmt_rtt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::gpio::{Level, Output, Speed}; 7use embassy_stm32::gpio::{Level, Output, Speed};
diff --git a/examples/boot/application/stm32l1/Cargo.toml b/examples/boot/application/stm32l1/Cargo.toml
index 3e964df9c..c07d71591 100644
--- a/examples/boot/application/stm32l1/Cargo.toml
+++ b/examples/boot/application/stm32l1/Cargo.toml
@@ -23,6 +23,7 @@ cortex-m-rt = "0.7.0"
23[features] 23[features]
24defmt = [ 24defmt = [
25 "dep:defmt", 25 "dep:defmt",
26 "dep:defmt-rtt",
26 "embassy-stm32/defmt", 27 "embassy-stm32/defmt",
27 "embassy-boot-stm32/defmt", 28 "embassy-boot-stm32/defmt",
28 "embassy-sync/defmt", 29 "embassy-sync/defmt",
diff --git a/examples/boot/application/stm32l1/src/bin/a.rs b/examples/boot/application/stm32l1/src/bin/a.rs
index f066c1139..dcc10e5c6 100644
--- a/examples/boot/application/stm32l1/src/bin/a.rs
+++ b/examples/boot/application/stm32l1/src/bin/a.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt")]
5use defmt_rtt::*; 5use defmt_rtt::*;
6use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; 6use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
7use embassy_embedded_hal::adapter::BlockingAsync; 7use embassy_embedded_hal::adapter::BlockingAsync;
diff --git a/examples/boot/application/stm32l1/src/bin/b.rs b/examples/boot/application/stm32l1/src/bin/b.rs
index 6bf00f41a..a59c6f540 100644
--- a/examples/boot/application/stm32l1/src/bin/b.rs
+++ b/examples/boot/application/stm32l1/src/bin/b.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt")]
5use defmt_rtt::*; 5use defmt_rtt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::gpio::{Level, Output, Speed}; 7use embassy_stm32::gpio::{Level, Output, Speed};
diff --git a/examples/boot/application/stm32l4/Cargo.toml b/examples/boot/application/stm32l4/Cargo.toml
index b154403ac..72b937ca7 100644
--- a/examples/boot/application/stm32l4/Cargo.toml
+++ b/examples/boot/application/stm32l4/Cargo.toml
@@ -23,6 +23,7 @@ cortex-m-rt = "0.7.0"
23[features] 23[features]
24defmt = [ 24defmt = [
25 "dep:defmt", 25 "dep:defmt",
26 "dep:defmt-rtt",
26 "embassy-stm32/defmt", 27 "embassy-stm32/defmt",
27 "embassy-boot-stm32/defmt", 28 "embassy-boot-stm32/defmt",
28 "embassy-sync/defmt", 29 "embassy-sync/defmt",
diff --git a/examples/boot/application/stm32l4/src/bin/a.rs b/examples/boot/application/stm32l4/src/bin/a.rs
index a0079ee33..7f8015c04 100644
--- a/examples/boot/application/stm32l4/src/bin/a.rs
+++ b/examples/boot/application/stm32l4/src/bin/a.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt")]
5use defmt_rtt::*; 5use defmt_rtt::*;
6use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; 6use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
7use embassy_embedded_hal::adapter::BlockingAsync; 7use embassy_embedded_hal::adapter::BlockingAsync;
diff --git a/examples/boot/application/stm32l4/src/bin/b.rs b/examples/boot/application/stm32l4/src/bin/b.rs
index 22ba82d5e..b1a505631 100644
--- a/examples/boot/application/stm32l4/src/bin/b.rs
+++ b/examples/boot/application/stm32l4/src/bin/b.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt")]
5use defmt_rtt::*; 5use defmt_rtt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::gpio::{Level, Output, Speed}; 7use embassy_stm32::gpio::{Level, Output, Speed};
diff --git a/examples/boot/application/stm32wb-dfu/src/main.rs b/examples/boot/application/stm32wb-dfu/src/main.rs
index 929d6802c..0ab99ff90 100644
--- a/examples/boot/application/stm32wb-dfu/src/main.rs
+++ b/examples/boot/application/stm32wb-dfu/src/main.rs
@@ -3,7 +3,7 @@
3 3
4use core::cell::RefCell; 4use core::cell::RefCell;
5 5
6#[cfg(feature = "defmt-rtt")] 6#[cfg(feature = "defmt")]
7use defmt_rtt::*; 7use defmt_rtt::*;
8use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareState, FirmwareUpdaterConfig}; 8use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareState, FirmwareUpdaterConfig};
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
diff --git a/examples/boot/application/stm32wl/Cargo.toml b/examples/boot/application/stm32wl/Cargo.toml
index 93ead617c..a5160b797 100644
--- a/examples/boot/application/stm32wl/Cargo.toml
+++ b/examples/boot/application/stm32wl/Cargo.toml
@@ -23,6 +23,7 @@ cortex-m-rt = "0.7.0"
23[features] 23[features]
24defmt = [ 24defmt = [
25 "dep:defmt", 25 "dep:defmt",
26 "dep:defmt-rtt",
26 "embassy-stm32/defmt", 27 "embassy-stm32/defmt",
27 "embassy-boot-stm32/defmt", 28 "embassy-boot-stm32/defmt",
28 "embassy-sync/defmt", 29 "embassy-sync/defmt",
diff --git a/examples/boot/application/stm32wl/src/bin/a.rs b/examples/boot/application/stm32wl/src/bin/a.rs
index 2fb16bdc4..9f4f0b238 100644
--- a/examples/boot/application/stm32wl/src/bin/a.rs
+++ b/examples/boot/application/stm32wl/src/bin/a.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt")]
5use defmt_rtt::*; 5use defmt_rtt::*;
6use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; 6use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
7use embassy_embedded_hal::adapter::BlockingAsync; 7use embassy_embedded_hal::adapter::BlockingAsync;
diff --git a/examples/boot/application/stm32wl/src/bin/b.rs b/examples/boot/application/stm32wl/src/bin/b.rs
index 8dd15d8cd..e954d8b91 100644
--- a/examples/boot/application/stm32wl/src/bin/b.rs
+++ b/examples/boot/application/stm32wl/src/bin/b.rs
@@ -1,7 +1,7 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4#[cfg(feature = "defmt-rtt")] 4#[cfg(feature = "defmt")]
5use defmt_rtt::*; 5use defmt_rtt::*;
6use embassy_executor::Spawner; 6use embassy_executor::Spawner;
7use embassy_stm32::gpio::{Level, Output, Speed}; 7use embassy_stm32::gpio::{Level, Output, Speed};
diff --git a/examples/boot/bootloader/nrf/Cargo.toml b/examples/boot/bootloader/nrf/Cargo.toml
index 980149bea..9d5d51a13 100644
--- a/examples/boot/bootloader/nrf/Cargo.toml
+++ b/examples/boot/bootloader/nrf/Cargo.toml
@@ -19,13 +19,13 @@ cfg-if = "1.0.0"
19[features] 19[features]
20defmt = [ 20defmt = [
21 "dep:defmt", 21 "dep:defmt",
22 "dep:defmt-rtt",
22 "embassy-boot-nrf/defmt", 23 "embassy-boot-nrf/defmt",
23 "embassy-nrf/defmt", 24 "embassy-nrf/defmt",
24] 25]
25softdevice = [ 26softdevice = [
26 "embassy-boot-nrf/softdevice", 27 "embassy-boot-nrf/softdevice",
27] 28]
28debug = ["defmt-rtt", "defmt"]
29 29
30[profile.dev] 30[profile.dev]
31debug = 2 31debug = 2
diff --git a/examples/boot/bootloader/rp/Cargo.toml b/examples/boot/bootloader/rp/Cargo.toml
index 7eec3df1b..c15c980ca 100644
--- a/examples/boot/bootloader/rp/Cargo.toml
+++ b/examples/boot/bootloader/rp/Cargo.toml
@@ -23,10 +23,10 @@ cfg-if = "1.0.0"
23[features] 23[features]
24defmt = [ 24defmt = [
25 "dep:defmt", 25 "dep:defmt",
26 "dep:defmt-rtt",
26 "embassy-boot-rp/defmt", 27 "embassy-boot-rp/defmt",
27 "embassy-rp/defmt", 28 "embassy-rp/defmt",
28] 29]
29debug = ["defmt-rtt", "defmt"]
30 30
31[profile.release] 31[profile.release]
32debug = true 32debug = true
diff --git a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml
index 55adf84d7..b91b05412 100644
--- a/examples/boot/bootloader/stm32-dual-bank/Cargo.toml
+++ b/examples/boot/bootloader/stm32-dual-bank/Cargo.toml
@@ -22,8 +22,7 @@ embedded-storage-async = "0.4.0"
22cfg-if = "1.0.0" 22cfg-if = "1.0.0"
23 23
24[features] 24[features]
25defmt = ["dep:defmt", "embassy-boot-stm32/defmt", "embassy-stm32/defmt"] 25defmt = ["dep:defmt", "dep:defmt-rtt", "embassy-boot-stm32/defmt", "embassy-stm32/defmt"]
26debug = ["defmt-rtt", "defmt"]
27 26
28[profile.dev] 27[profile.dev]
29debug = 2 28debug = 2
diff --git a/examples/boot/bootloader/stm32/Cargo.toml b/examples/boot/bootloader/stm32/Cargo.toml
index ef2b99404..541186949 100644
--- a/examples/boot/bootloader/stm32/Cargo.toml
+++ b/examples/boot/bootloader/stm32/Cargo.toml
@@ -21,10 +21,10 @@ cfg-if = "1.0.0"
21[features] 21[features]
22defmt = [ 22defmt = [
23 "dep:defmt", 23 "dep:defmt",
24 "dep:defmt-rtt",
24 "embassy-boot-stm32/defmt", 25 "embassy-boot-stm32/defmt",
25 "embassy-stm32/defmt", 26 "embassy-stm32/defmt",
26] 27]
27debug = ["defmt-rtt", "defmt"]
28 28
29[profile.dev] 29[profile.dev]
30debug = 2 30debug = 2
diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
index 93b5d8b34..9950ed7b6 100644
--- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
+++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml
@@ -24,12 +24,12 @@ embassy-futures = { version = "0.1.1", path = "../../../../embassy-futures" }
24[features] 24[features]
25defmt = [ 25defmt = [
26 "dep:defmt", 26 "dep:defmt",
27 "dep:defmt-rtt",
27 "embassy-boot-stm32/defmt", 28 "embassy-boot-stm32/defmt",
28 "embassy-stm32/defmt", 29 "embassy-stm32/defmt",
29 "embassy-usb/defmt", 30 "embassy-usb/defmt",
30 "embassy-usb-dfu/defmt" 31 "embassy-usb-dfu/defmt"
31] 32]
32debug = ["defmt-rtt", "defmt"]
33 33
34[profile.dev] 34[profile.dev]
35debug = 2 35debug = 2
diff --git a/examples/rp/src/bin/zerocopy.rs b/examples/rp/src/bin/zerocopy.rs
new file mode 100644
index 000000000..39f03c8e4
--- /dev/null
+++ b/examples/rp/src/bin/zerocopy.rs
@@ -0,0 +1,94 @@
1//! This example shows how to use `zerocopy_channel` from `embassy_sync` for
2//! sending large values between two tasks without copying.
3//! The example also shows how to use the RP2040 ADC with DMA.
4#![no_std]
5#![no_main]
6
7use core::sync::atomic::{AtomicU16, Ordering};
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_rp::adc::{self, Adc, Async, Config, InterruptHandler};
12use embassy_rp::bind_interrupts;
13use embassy_rp::gpio::Pull;
14use embassy_rp::peripherals::DMA_CH0;
15use embassy_sync::blocking_mutex::raw::NoopRawMutex;
16use embassy_sync::zerocopy_channel::{Channel, Receiver, Sender};
17use embassy_time::{Duration, Ticker, Timer};
18use static_cell::StaticCell;
19use {defmt_rtt as _, panic_probe as _};
20
21type SampleBuffer = [u16; 512];
22
23bind_interrupts!(struct Irqs {
24 ADC_IRQ_FIFO => InterruptHandler;
25});
26
27const BLOCK_SIZE: usize = 512;
28const NUM_BLOCKS: usize = 2;
29static MAX: AtomicU16 = AtomicU16::new(0);
30
31struct AdcParts {
32 adc: Adc<'static, Async>,
33 pin: adc::Channel<'static>,
34 dma: DMA_CH0,
35}
36
37#[embassy_executor::main]
38async fn main(spawner: Spawner) {
39 let p = embassy_rp::init(Default::default());
40 info!("Here we go!");
41
42 let adc_parts = AdcParts {
43 adc: Adc::new(p.ADC, Irqs, Config::default()),
44 pin: adc::Channel::new_pin(p.PIN_29, Pull::None),
45 dma: p.DMA_CH0,
46 };
47
48 static BUF: StaticCell<[SampleBuffer; NUM_BLOCKS]> = StaticCell::new();
49 let buf = BUF.init([[0; BLOCK_SIZE]; NUM_BLOCKS]);
50
51 static CHANNEL: StaticCell<Channel<'_, NoopRawMutex, SampleBuffer>> = StaticCell::new();
52 let channel = CHANNEL.init(Channel::new(buf));
53 let (sender, receiver) = channel.split();
54
55 spawner.must_spawn(consumer(receiver));
56 spawner.must_spawn(producer(sender, adc_parts));
57
58 let mut ticker = Ticker::every(Duration::from_secs(1));
59 loop {
60 ticker.next().await;
61 let max = MAX.load(Ordering::Relaxed);
62 info!("latest block's max value: {:?}", max);
63 }
64}
65
66#[embassy_executor::task]
67async fn producer(mut sender: Sender<'static, NoopRawMutex, SampleBuffer>, mut adc: AdcParts) {
68 loop {
69 // Obtain a free buffer from the channel
70 let buf = sender.send().await;
71
72 // Fill it with data
73 adc.adc.read_many(&mut adc.pin, buf, 1, &mut adc.dma).await.unwrap();
74
75 // Notify the channel that the buffer is now ready to be received
76 sender.send_done();
77 }
78}
79
80#[embassy_executor::task]
81async fn consumer(mut receiver: Receiver<'static, NoopRawMutex, SampleBuffer>) {
82 loop {
83 // Receive a buffer from the channel
84 let buf = receiver.receive().await;
85
86 // Simulate using the data, while the producer is filling up the next buffer
87 Timer::after_micros(1000).await;
88 let max = buf.iter().max().unwrap();
89 MAX.store(*max, Ordering::Relaxed);
90
91 // Notify the channel that the buffer is now ready to be reused
92 receiver.receive_done();
93 }
94}
diff --git a/examples/stm32f1/src/bin/input_capture.rs b/examples/stm32f1/src/bin/input_capture.rs
new file mode 100644
index 000000000..5e2dab9e6
--- /dev/null
+++ b/examples/stm32f1/src/bin/input_capture.rs
@@ -0,0 +1,52 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Pull, Speed};
7use embassy_stm32::time::khz;
8use embassy_stm32::timer::input_capture::{CapturePin, InputCapture};
9use embassy_stm32::timer::{self, Channel};
10use embassy_stm32::{bind_interrupts, peripherals};
11use embassy_time::Timer;
12use {defmt_rtt as _, panic_probe as _};
13
14/// Connect PA2 and PC13 with a 1k Ohm resistor
15
16#[embassy_executor::task]
17async fn blinky(led: peripherals::PC13) {
18 let mut led = Output::new(led, Level::High, Speed::Low);
19
20 loop {
21 info!("high");
22 led.set_high();
23 Timer::after_millis(300).await;
24
25 info!("low");
26 led.set_low();
27 Timer::after_millis(300).await;
28 }
29}
30
31bind_interrupts!(struct Irqs {
32 TIM2 => timer::CaptureCompareInterruptHandler<peripherals::TIM2>;
33});
34
35#[embassy_executor::main]
36async fn main(spawner: Spawner) {
37 let p = embassy_stm32::init(Default::default());
38 info!("Hello World!");
39
40 unwrap!(spawner.spawn(blinky(p.PC13)));
41
42 let ch3 = CapturePin::new_ch3(p.PA2, Pull::None);
43 let mut ic = InputCapture::new(p.TIM2, None, None, Some(ch3), None, Irqs, khz(1000), Default::default());
44
45 loop {
46 info!("wait for rising edge");
47 ic.wait_for_rising_edge(Channel::Ch3).await;
48
49 let capture_value = ic.get_capture_value(Channel::Ch3);
50 info!("new capture! {}", capture_value);
51 }
52}
diff --git a/examples/stm32f1/src/bin/pwm_input.rs b/examples/stm32f1/src/bin/pwm_input.rs
new file mode 100644
index 000000000..f74853d4e
--- /dev/null
+++ b/examples/stm32f1/src/bin/pwm_input.rs
@@ -0,0 +1,54 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Pull, Speed};
7use embassy_stm32::time::khz;
8use embassy_stm32::timer::pwm_input::PwmInput;
9use embassy_stm32::{bind_interrupts, peripherals, timer};
10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _};
12
13/// Connect PA0 and PC13 with a 1k Ohm resistor
14
15#[embassy_executor::task]
16async fn blinky(led: peripherals::PC13) {
17 let mut led = Output::new(led, Level::High, Speed::Low);
18
19 loop {
20 info!("high");
21 led.set_high();
22 Timer::after_millis(300).await;
23
24 info!("low");
25 led.set_low();
26 Timer::after_millis(300).await;
27 }
28}
29
30bind_interrupts!(struct Irqs {
31 TIM2 => timer::CaptureCompareInterruptHandler<peripherals::TIM2>;
32});
33
34#[embassy_executor::main]
35async fn main(spawner: Spawner) {
36 let p = embassy_stm32::init(Default::default());
37 info!("Hello World!");
38
39 unwrap!(spawner.spawn(blinky(p.PC13)));
40
41 let mut pwm_input = PwmInput::new(p.TIM2, p.PA0, Pull::None, khz(10));
42 pwm_input.enable();
43
44 loop {
45 Timer::after_millis(500).await;
46 let period = pwm_input.get_period_ticks();
47 let width = pwm_input.get_width_ticks();
48 let duty_cycle = pwm_input.get_duty_cycle();
49 info!(
50 "period ticks: {} width ticks: {} duty cycle: {}",
51 period, width, duty_cycle
52 );
53 }
54}
diff --git a/examples/stm32f4/src/bin/i2s_dma.rs b/examples/stm32f4/src/bin/i2s_dma.rs
index 97a04b2aa..27b165f1b 100644
--- a/examples/stm32f4/src/bin/i2s_dma.rs
+++ b/examples/stm32f4/src/bin/i2s_dma.rs
@@ -15,14 +15,13 @@ async fn main(_spawner: Spawner) {
15 let p = embassy_stm32::init(Default::default()); 15 let p = embassy_stm32::init(Default::default());
16 info!("Hello World!"); 16 info!("Hello World!");
17 17
18 let mut i2s = I2S::new( 18 let mut i2s = I2S::new_txonly(
19 p.SPI2, 19 p.SPI2,
20 p.PC3, // sd 20 p.PC3, // sd
21 p.PB12, // ws 21 p.PB12, // ws
22 p.PB10, // ck 22 p.PB10, // ck
23 p.PC6, // mck 23 p.PC6, // mck
24 p.DMA1_CH4, 24 p.DMA1_CH4,
25 p.DMA1_CH3,
26 Hertz(1_000_000), 25 Hertz(1_000_000),
27 Config::default(), 26 Config::default(),
28 ); 27 );
diff --git a/examples/stm32f4/src/bin/pwm_input.rs b/examples/stm32f4/src/bin/pwm_input.rs
new file mode 100644
index 000000000..ce200549d
--- /dev/null
+++ b/examples/stm32f4/src/bin/pwm_input.rs
@@ -0,0 +1,54 @@
1#![no_std]
2#![no_main]
3
4use defmt::*;
5use embassy_executor::Spawner;
6use embassy_stm32::gpio::{Level, Output, Pull, Speed};
7use embassy_stm32::time::khz;
8use embassy_stm32::timer::pwm_input::PwmInput;
9use embassy_stm32::{bind_interrupts, peripherals, timer};
10use embassy_time::Timer;
11use {defmt_rtt as _, panic_probe as _};
12
13/// Connect PB2 and PA6 with a 1k Ohm resistor
14
15#[embassy_executor::task]
16async fn blinky(led: peripherals::PB2) {
17 let mut led = Output::new(led, Level::High, Speed::Low);
18
19 loop {
20 info!("high");
21 led.set_high();
22 Timer::after_millis(300).await;
23
24 info!("low");
25 led.set_low();
26 Timer::after_millis(300).await;
27 }
28}
29
30bind_interrupts!(struct Irqs {
31 TIM2 => timer::CaptureCompareInterruptHandler<peripherals::TIM2>;
32});
33
34#[embassy_executor::main]
35async fn main(spawner: Spawner) {
36 let p = embassy_stm32::init(Default::default());
37 info!("Hello World!");
38
39 unwrap!(spawner.spawn(blinky(p.PB2)));
40
41 let mut pwm_input = PwmInput::new(p.TIM3, p.PA6, Pull::None, khz(10));
42 pwm_input.enable();
43
44 loop {
45 Timer::after_millis(500).await;
46 let period = pwm_input.get_period_ticks();
47 let width = pwm_input.get_width_ticks();
48 let duty_cycle = pwm_input.get_duty_cycle();
49 info!(
50 "period ticks: {} width ticks: {} duty cycle: {}",
51 period, width, duty_cycle
52 );
53 }
54}
diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs
index 19ae16e8b..b398c35da 100644
--- a/examples/stm32f4/src/bin/usb_ethernet.rs
+++ b/examples/stm32f4/src/bin/usb_ethernet.rs
@@ -43,7 +43,7 @@ bind_interrupts!(struct Irqs {
43// If you are trying this and your USB device doesn't connect, the most 43// If you are trying this and your USB device doesn't connect, the most
44// common issues are the RCC config and vbus_detection 44// common issues are the RCC config and vbus_detection
45// 45//
46// See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure 46// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure
47// for more information. 47// for more information.
48#[embassy_executor::main] 48#[embassy_executor::main]
49async fn main(spawner: Spawner) { 49async fn main(spawner: Spawner) {
diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs
index 537ff63ea..1270995c4 100644
--- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs
+++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs
@@ -24,7 +24,7 @@ bind_interrupts!(struct Irqs {
24// If you are trying this and your USB device doesn't connect, the most 24// If you are trying this and your USB device doesn't connect, the most
25// common issues are the RCC config and vbus_detection 25// common issues are the RCC config and vbus_detection
26// 26//
27// See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure 27// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure
28// for more information. 28// for more information.
29#[embassy_executor::main] 29#[embassy_executor::main]
30async fn main(_spawner: Spawner) { 30async fn main(_spawner: Spawner) {
diff --git a/examples/stm32f4/src/bin/usb_hid_mouse.rs b/examples/stm32f4/src/bin/usb_hid_mouse.rs
index df4b7426c..45136f965 100644
--- a/examples/stm32f4/src/bin/usb_hid_mouse.rs
+++ b/examples/stm32f4/src/bin/usb_hid_mouse.rs
@@ -21,7 +21,7 @@ bind_interrupts!(struct Irqs {
21// If you are trying this and your USB device doesn't connect, the most 21// If you are trying this and your USB device doesn't connect, the most
22// common issues are the RCC config and vbus_detection 22// common issues are the RCC config and vbus_detection
23// 23//
24// See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure 24// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure
25// for more information. 25// for more information.
26#[embassy_executor::main] 26#[embassy_executor::main]
27async fn main(_spawner: Spawner) { 27async fn main(_spawner: Spawner) {
diff --git a/examples/stm32f4/src/bin/usb_raw.rs b/examples/stm32f4/src/bin/usb_raw.rs
index 1452e7c5f..b2d706208 100644
--- a/examples/stm32f4/src/bin/usb_raw.rs
+++ b/examples/stm32f4/src/bin/usb_raw.rs
@@ -72,7 +72,7 @@ bind_interrupts!(struct Irqs {
72// If you are trying this and your USB device doesn't connect, the most 72// If you are trying this and your USB device doesn't connect, the most
73// common issues are the RCC config and vbus_detection 73// common issues are the RCC config and vbus_detection
74// 74//
75// See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure 75// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure
76// for more information. 76// for more information.
77#[embassy_executor::main] 77#[embassy_executor::main]
78async fn main(_spawner: Spawner) { 78async fn main(_spawner: Spawner) {
diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs
index b2bd390b6..328b5effe 100644
--- a/examples/stm32f4/src/bin/usb_serial.rs
+++ b/examples/stm32f4/src/bin/usb_serial.rs
@@ -19,7 +19,7 @@ bind_interrupts!(struct Irqs {
19// If you are trying this and your USB device doesn't connect, the most 19// If you are trying this and your USB device doesn't connect, the most
20// common issues are the RCC config and vbus_detection 20// common issues are the RCC config and vbus_detection
21// 21//
22// See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure 22// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure
23// for more information. 23// for more information.
24#[embassy_executor::main] 24#[embassy_executor::main]
25async fn main(_spawner: Spawner) { 25async fn main(_spawner: Spawner) {
diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs
index e32b4d3df..a82e335a9 100644
--- a/examples/stm32f7/src/bin/can.rs
+++ b/examples/stm32f7/src/bin/can.rs
@@ -24,7 +24,7 @@ bind_interrupts!(struct Irqs {
24}); 24});
25 25
26#[embassy_executor::task] 26#[embassy_executor::task]
27pub async fn send_can_message(tx: &'static mut CanTx<'static, CAN3>) { 27pub async fn send_can_message(tx: &'static mut CanTx<'static>) {
28 loop { 28 loop {
29 let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), &[0]).unwrap(); 29 let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), &[0]).unwrap();
30 tx.write(&frame).await; 30 tx.write(&frame).await;
@@ -45,7 +45,7 @@ async fn main(spawner: Spawner) {
45 let rx_pin = Input::new(&mut p.PA15, Pull::Up); 45 let rx_pin = Input::new(&mut p.PA15, Pull::Up);
46 core::mem::forget(rx_pin); 46 core::mem::forget(rx_pin);
47 47
48 static CAN: StaticCell<Can<'static, CAN3>> = StaticCell::new(); 48 static CAN: StaticCell<Can<'static>> = StaticCell::new();
49 let can = CAN.init(Can::new(p.CAN3, p.PA8, p.PA15, Irqs)); 49 let can = CAN.init(Can::new(p.CAN3, p.PA8, p.PA15, Irqs));
50 can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); 50 can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
51 51
@@ -62,7 +62,7 @@ async fn main(spawner: Spawner) {
62 62
63 let (tx, mut rx) = can.split(); 63 let (tx, mut rx) = can.split();
64 64
65 static CAN_TX: StaticCell<CanTx<'static, CAN3>> = StaticCell::new(); 65 static CAN_TX: StaticCell<CanTx<'static>> = StaticCell::new();
66 let tx = CAN_TX.init(tx); 66 let tx = CAN_TX.init(tx);
67 spawner.spawn(send_can_message(tx)).unwrap(); 67 spawner.spawn(send_can_message(tx)).unwrap();
68 68
diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs
index 0e5cc7c5c..1906b28ed 100644
--- a/examples/stm32f7/src/bin/usb_serial.rs
+++ b/examples/stm32f7/src/bin/usb_serial.rs
@@ -19,7 +19,7 @@ bind_interrupts!(struct Irqs {
19// If you are trying this and your USB device doesn't connect, the most 19// If you are trying this and your USB device doesn't connect, the most
20// common issues are the RCC config and vbus_detection 20// common issues are the RCC config and vbus_detection
21// 21//
22// See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure 22// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure
23// for more information. 23// for more information.
24#[embassy_executor::main] 24#[embassy_executor::main]
25async fn main(_spawner: Spawner) { 25async fn main(_spawner: Spawner) {
diff --git a/examples/stm32g0/src/bin/spi_neopixel.rs b/examples/stm32g0/src/bin/spi_neopixel.rs
index 2deee271d..edcae74f7 100644
--- a/examples/stm32g0/src/bin/spi_neopixel.rs
+++ b/examples/stm32g0/src/bin/spi_neopixel.rs
@@ -76,7 +76,7 @@ async fn main(_spawner: Spawner) {
76 76
77 let mut config = Config::default(); 77 let mut config = Config::default();
78 config.frequency = Hertz(4_000_000); 78 config.frequency = Hertz(4_000_000);
79 let mut spi = Spi::new_txonly_nosck(p.SPI1, p.PB5, p.DMA1_CH3, config); 79 let mut spi = Spi::new_txonly(p.SPI1, p.PB3, p.PB5, p.DMA1_CH3, config); // SCK is unused.
80 80
81 let mut neopixels = Ws2812::new(); 81 let mut neopixels = Ws2812::new();
82 82
diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs
index 1c50fc1c8..65ae597d4 100644
--- a/examples/stm32h7/src/bin/usb_serial.rs
+++ b/examples/stm32h7/src/bin/usb_serial.rs
@@ -18,7 +18,7 @@ bind_interrupts!(struct Irqs {
18// If you are trying this and your USB device doesn't connect, the most 18// If you are trying this and your USB device doesn't connect, the most
19// common issues are the RCC config and vbus_detection 19// common issues are the RCC config and vbus_detection
20// 20//
21// See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure 21// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure
22// for more information. 22// for more information.
23#[embassy_executor::main] 23#[embassy_executor::main]
24async fn main(_spawner: Spawner) { 24async fn main(_spawner: Spawner) {
diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs
index ed9671d0f..c3b1211d8 100644
--- a/examples/stm32l4/src/bin/usb_serial.rs
+++ b/examples/stm32l4/src/bin/usb_serial.rs
@@ -19,7 +19,7 @@ bind_interrupts!(struct Irqs {
19// If you are trying this and your USB device doesn't connect, the most 19// If you are trying this and your USB device doesn't connect, the most
20// common issues are the RCC config and vbus_detection 20// common issues are the RCC config and vbus_detection
21// 21//
22// See https://embassy.dev/book/dev/faq.html#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure 22// See https://embassy.dev/book/#_the_usb_examples_are_not_working_on_my_board_is_there_anything_else_i_need_to_configure
23// for more information. 23// for more information.
24#[embassy_executor::main] 24#[embassy_executor::main]
25async fn main(_spawner: Spawner) { 25async fn main(_spawner: Spawner) {
diff --git a/rust-toolchain-nightly.toml b/rust-toolchain-nightly.toml
index ac160b995..2143c1b2d 100644
--- a/rust-toolchain-nightly.toml
+++ b/rust-toolchain-nightly.toml
@@ -1,5 +1,5 @@
1[toolchain] 1[toolchain]
2channel = "nightly-2024-04-14" 2channel = "nightly-2024-05-20"
3components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] 3components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ]
4targets = [ 4targets = [
5 "thumbv7em-none-eabi", 5 "thumbv7em-none-eabi",
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index f6d1d98eb..de390ee38 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -7,34 +7,36 @@ autobins = false
7 7
8[features] 8[features]
9stm32c031c6 = ["embassy-stm32/stm32c031c6", "cm0", "not-gpdma"] 9stm32c031c6 = ["embassy-stm32/stm32c031c6", "cm0", "not-gpdma"]
10stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"] 10stm32f103c8 = ["embassy-stm32/stm32f103c8", "spi-v1", "not-gpdma"]
11stm32f207zg = ["embassy-stm32/stm32f207zg", "chrono", "not-gpdma", "eth", "rng"] 11stm32f207zg = ["embassy-stm32/stm32f207zg", "spi-v1", "chrono", "not-gpdma", "eth", "rng"]
12stm32f303ze = ["embassy-stm32/stm32f303ze", "chrono", "not-gpdma"] 12stm32f303ze = ["embassy-stm32/stm32f303ze", "chrono", "not-gpdma"]
13stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng"] 13stm32f429zi = ["embassy-stm32/stm32f429zi", "spi-v1", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng"]
14stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"] 14stm32f446re = ["embassy-stm32/stm32f446re", "spi-v1", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"]
15stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] 15stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"]
16stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac", "ucpd"] 16stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac", "ucpd"]
17stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan", "cordic"] 17stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan", "cordic"]
18stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "fdcan", "hash", "cordic", "stop"] 18stm32h563zi = ["embassy-stm32/stm32h563zi", "spi-v345", "chrono", "eth", "rng", "fdcan", "hash", "cordic", "stop"]
19stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"] 19stm32h753zi = ["embassy-stm32/stm32h753zi", "spi-v345", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"]
20stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash", "cryp"] 20stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "spi-v345", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash", "cryp"]
21stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"] 21stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "spi-v345", "not-gpdma", "rng", "fdcan"]
22stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"] 22stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"]
23stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"] 23stm32l152re = ["embassy-stm32/stm32l152re", "spi-v1", "chrono", "not-gpdma"]
24stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"] 24stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"]
25stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma", "rng", "hash"] 25stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma", "rng", "hash"]
26stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng"] 26stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng"]
27stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng", "hash"] 27stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng", "hash"]
28stm32u585ai = ["embassy-stm32/stm32u585ai", "chrono", "rng", "hash", "cordic"] 28stm32u585ai = ["embassy-stm32/stm32u585ai", "spi-v345", "chrono", "rng", "hash", "cordic"]
29stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "chrono", "rng", "hash"] # FIXME: cordic test cause it crash 29stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "spi-v345", "chrono", "rng", "hash"] # FIXME: cordic test cause it crash
30stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng"] 30stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng"]
31stm32wba52cg = ["embassy-stm32/stm32wba52cg", "chrono", "rng", "hash"] 31stm32wba52cg = ["embassy-stm32/stm32wba52cg", "spi-v345", "chrono", "rng", "hash"]
32stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"] 32stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"]
33stm32f091rc = ["embassy-stm32/stm32f091rc", "cm0", "not-gpdma", "chrono"] 33stm32f091rc = ["embassy-stm32/stm32f091rc", "cm0", "not-gpdma", "chrono"]
34stm32h503rb = ["embassy-stm32/stm32h503rb", "rng", "stop"] 34stm32h503rb = ["embassy-stm32/stm32h503rb", "spi-v345", "rng", "stop"]
35stm32h7s3l8 = ["embassy-stm32/stm32h7s3l8", "rng", "cordic", "hash"] # TODO: fdcan crashes, cryp dma hangs. 35stm32h7s3l8 = ["embassy-stm32/stm32h7s3l8", "spi-v345", "rng", "cordic", "hash"] # TODO: fdcan crashes, cryp dma hangs.
36stm32u083rc = ["embassy-stm32/stm32u083rc", "cm0", "rng", "chrono"] 36stm32u083rc = ["embassy-stm32/stm32u083rc", "cm0", "rng", "chrono"]
37 37
38spi-v1 = []
39spi-v345 = []
38cryp = [] 40cryp = []
39hash = [] 41hash = []
40eth = ["embassy-executor/task-arena-size-16384"] 42eth = ["embassy-executor/task-arena-size-16384"]
diff --git a/tests/stm32/build.rs b/tests/stm32/build.rs
index 176adff62..675115568 100644
--- a/tests/stm32/build.rs
+++ b/tests/stm32/build.rs
@@ -14,6 +14,7 @@ fn main() -> Result<(), Box<dyn Error>> {
14 feature = "stm32c031c6", 14 feature = "stm32c031c6",
15 feature = "stm32wb55rg", 15 feature = "stm32wb55rg",
16 feature = "stm32l073rz", 16 feature = "stm32l073rz",
17 feature = "stm32h503rb",
17 // wrong ram size in stm32-data 18 // wrong ram size in stm32-data
18 feature = "stm32wl55jc", 19 feature = "stm32wl55jc",
19 feature = "stm32u5a5zj", 20 feature = "stm32u5a5zj",
diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs
index 551764458..ba8a33e34 100644
--- a/tests/stm32/src/bin/can.rs
+++ b/tests/stm32/src/bin/can.rs
@@ -9,9 +9,7 @@ use common::*;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_stm32::bind_interrupts; 10use embassy_stm32::bind_interrupts;
11use embassy_stm32::can::filter::Mask32; 11use embassy_stm32::can::filter::Mask32;
12use embassy_stm32::can::{ 12use embassy_stm32::can::{Fifo, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler};
13 Can, Fifo, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler,
14};
15use embassy_stm32::gpio::{Input, Pull}; 13use embassy_stm32::gpio::{Input, Pull};
16use embassy_stm32::peripherals::CAN1; 14use embassy_stm32::peripherals::CAN1;
17use embassy_time::Duration; 15use embassy_time::Duration;
@@ -48,7 +46,7 @@ async fn main(_spawner: Spawner) {
48 let rx_pin = Input::new(&mut rx, Pull::Up); 46 let rx_pin = Input::new(&mut rx, Pull::Up);
49 core::mem::forget(rx_pin); 47 core::mem::forget(rx_pin);
50 48
51 let mut can = Can::new(can, rx, tx, Irqs); 49 let mut can = embassy_stm32::can::Can::new(can, rx, tx, Irqs);
52 50
53 info!("Configuring can..."); 51 info!("Configuring can...");
54 52
diff --git a/tests/stm32/src/bin/can_common.rs b/tests/stm32/src/bin/can_common.rs
index 4b39269cc..4e1740ad5 100644
--- a/tests/stm32/src/bin/can_common.rs
+++ b/tests/stm32/src/bin/can_common.rs
@@ -8,7 +8,8 @@ pub struct TestOptions {
8 pub max_buffered: u8, 8 pub max_buffered: u8,
9} 9}
10 10
11pub async fn run_can_tests<'d, T: can::Instance>(can: &mut can::Can<'d, T>, options: &TestOptions) { 11pub async fn run_can_tests<'d>(can: &mut can::Can<'d>, options: &TestOptions) {
12 //pub async fn run_can_tests<'d, T: can::Instance>(can: &mut can::Can<'d, T>, options: &TestOptions) {
12 let mut i: u8 = 0; 13 let mut i: u8 = 0;
13 loop { 14 loop {
14 //let tx_frame = can::frame::Frame::new_standard(0x123, &[i, 0x12 as u8, 0x34 as u8, 0x56 as u8, 0x78 as u8, 0x9A as u8, 0xBC as u8 ]).unwrap(); 15 //let tx_frame = can::frame::Frame::new_standard(0x123, &[i, 0x12 as u8, 0x34 as u8, 0x56 as u8, 0x78 as u8, 0x9A as u8, 0xBC as u8 ]).unwrap();
@@ -79,11 +80,7 @@ pub async fn run_can_tests<'d, T: can::Instance>(can: &mut can::Can<'d, T>, opti
79 } 80 }
80} 81}
81 82
82pub async fn run_split_can_tests<'d, T: can::Instance>( 83pub async fn run_split_can_tests<'d>(tx: &mut can::CanTx<'d>, rx: &mut can::CanRx<'d>, options: &TestOptions) {
83 tx: &mut can::CanTx<'d, T>,
84 rx: &mut can::CanRx<'d, T>,
85 options: &TestOptions,
86) {
87 for i in 0..options.max_buffered { 84 for i in 0..options.max_buffered {
88 // Try filling up the RX FIFO0 buffers 85 // Try filling up the RX FIFO0 buffers
89 //let tx_frame = if 0 != (i & 0x01) { 86 //let tx_frame = if 0 != (i & 0x01) {
diff --git a/tests/stm32/src/bin/fdcan.rs b/tests/stm32/src/bin/fdcan.rs
index 20bd3f7e3..bc2b7edd4 100644
--- a/tests/stm32/src/bin/fdcan.rs
+++ b/tests/stm32/src/bin/fdcan.rs
@@ -88,7 +88,7 @@ fn options() -> (Config, TestOptions) {
88 ) 88 )
89} 89}
90 90
91#[cfg(any(feature = "stm32g491re", feature = "stm32g431cb"))] 91#[cfg(any(feature = "stm32g491re"))]
92fn options() -> (Config, TestOptions) { 92fn options() -> (Config, TestOptions) {
93 info!("G4 config"); 93 info!("G4 config");
94 ( 94 (
diff --git a/tests/stm32/src/bin/spi.rs b/tests/stm32/src/bin/spi.rs
index c1576bfeb..0ffd0f653 100644
--- a/tests/stm32/src/bin/spi.rs
+++ b/tests/stm32/src/bin/spi.rs
@@ -6,6 +6,7 @@ mod common;
6use common::*; 6use common::*;
7use defmt::assert_eq; 7use defmt::assert_eq;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::gpio::{Level, Output, Speed};
9use embassy_stm32::spi::{self, Spi}; 10use embassy_stm32::spi::{self, Spi};
10use embassy_stm32::time::Hertz; 11use embassy_stm32::time::Hertz;
11 12
@@ -14,18 +15,19 @@ async fn main(_spawner: Spawner) {
14 let p = embassy_stm32::init(config()); 15 let p = embassy_stm32::init(config());
15 info!("Hello World!"); 16 info!("Hello World!");
16 17
17 let spi = peri!(p, SPI); 18 let mut spi_peri = peri!(p, SPI);
18 let sck = peri!(p, SPI_SCK); 19 let mut sck = peri!(p, SPI_SCK);
19 let mosi = peri!(p, SPI_MOSI); 20 let mut mosi = peri!(p, SPI_MOSI);
20 let miso = peri!(p, SPI_MISO); 21 let mut miso = peri!(p, SPI_MISO);
21 22
22 let mut spi_config = spi::Config::default(); 23 let mut spi_config = spi::Config::default();
23 spi_config.frequency = Hertz(1_000_000); 24 spi_config.frequency = Hertz(1_000_000);
24 25
25 let mut spi = Spi::new_blocking( 26 let mut spi = Spi::new_blocking(
26 spi, sck, // Arduino D13 27 &mut spi_peri,
27 mosi, // Arduino D11 28 &mut sck, // Arduino D13
28 miso, // Arduino D12 29 &mut mosi, // Arduino D11
30 &mut miso, // Arduino D12
29 spi_config, 31 spi_config,
30 ); 32 );
31 33
@@ -60,11 +62,43 @@ async fn main(_spawner: Spawner) {
60 62
61 // Assert the RCC bit gets disabled on drop. 63 // Assert the RCC bit gets disabled on drop.
62 #[cfg(feature = "stm32f429zi")] 64 #[cfg(feature = "stm32f429zi")]
63 { 65 defmt::assert!(embassy_stm32::pac::RCC.apb2enr().read().spi1en());
64 defmt::assert!(embassy_stm32::pac::RCC.apb2enr().read().spi1en()); 66 drop(spi);
65 drop(spi); 67 #[cfg(feature = "stm32f429zi")]
66 defmt::assert!(!embassy_stm32::pac::RCC.apb2enr().read().spi1en()); 68 defmt::assert!(!embassy_stm32::pac::RCC.apb2enr().read().spi1en());
67 } 69
70 // test rx-only configuration
71 let mut spi = Spi::new_blocking_rxonly(&mut spi_peri, &mut sck, &mut miso, spi_config);
72 let mut mosi_out = Output::new(&mut mosi, Level::Low, Speed::VeryHigh);
73 mosi_out.set_high();
74 spi.blocking_read(&mut buf).unwrap();
75 assert_eq!(buf, [0xff; 9]);
76 mosi_out.set_low();
77 spi.blocking_read(&mut buf).unwrap();
78 assert_eq!(buf, [0x00; 9]);
79 spi.blocking_read::<u8>(&mut []).unwrap();
80 spi.blocking_read::<u8>(&mut []).unwrap();
81 drop(mosi_out);
82 drop(spi);
83
84 // Test tx-only. Just check it doesn't hang, not much else we can do without using SPI slave.
85 let mut spi = Spi::new_blocking_txonly(&mut spi_peri, &mut sck, &mut mosi, spi_config);
86 spi.blocking_transfer(&mut buf, &data).unwrap();
87 spi.blocking_transfer_in_place(&mut buf).unwrap();
88 spi.blocking_write(&buf).unwrap();
89 spi.blocking_read(&mut buf).unwrap();
90 spi.blocking_transfer::<u8>(&mut [], &[]).unwrap();
91 spi.blocking_transfer_in_place::<u8>(&mut []).unwrap();
92 spi.blocking_read::<u8>(&mut []).unwrap();
93 spi.blocking_write::<u8>(&[]).unwrap();
94 drop(spi);
95
96 // Test tx-only nosck.
97 let mut spi = Spi::new_blocking_txonly_nosck(&mut spi_peri, &mut mosi, spi_config);
98 spi.blocking_write(&buf).unwrap();
99 spi.blocking_write::<u8>(&[]).unwrap();
100 spi.blocking_write(&buf).unwrap();
101 drop(spi);
68 102
69 info!("Test OK"); 103 info!("Test OK");
70 cortex_m::asm::bkpt(); 104 cortex_m::asm::bkpt();
diff --git a/tests/stm32/src/bin/spi_dma.rs b/tests/stm32/src/bin/spi_dma.rs
index 5d46726dd..fd26d3f71 100644
--- a/tests/stm32/src/bin/spi_dma.rs
+++ b/tests/stm32/src/bin/spi_dma.rs
@@ -6,6 +6,7 @@ mod common;
6use common::*; 6use common::*;
7use defmt::assert_eq; 7use defmt::assert_eq;
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_stm32::gpio::{Level, Output, Speed};
9use embassy_stm32::spi::{self, Spi}; 10use embassy_stm32::spi::{self, Spi};
10use embassy_stm32::time::Hertz; 11use embassy_stm32::time::Hertz;
11 12
@@ -14,21 +15,24 @@ async fn main(_spawner: Spawner) {
14 let p = embassy_stm32::init(config()); 15 let p = embassy_stm32::init(config());
15 info!("Hello World!"); 16 info!("Hello World!");
16 17
17 let spi = peri!(p, SPI); 18 let mut spi_peri = peri!(p, SPI);
18 let sck = peri!(p, SPI_SCK); 19 let mut sck = peri!(p, SPI_SCK);
19 let mosi = peri!(p, SPI_MOSI); 20 let mut mosi = peri!(p, SPI_MOSI);
20 let miso = peri!(p, SPI_MISO); 21 let mut miso = peri!(p, SPI_MISO);
21 let tx_dma = peri!(p, SPI_TX_DMA); 22 let mut tx_dma = peri!(p, SPI_TX_DMA);
22 let rx_dma = peri!(p, SPI_RX_DMA); 23 let mut rx_dma = peri!(p, SPI_RX_DMA);
23 24
24 let mut spi_config = spi::Config::default(); 25 let mut spi_config = spi::Config::default();
25 spi_config.frequency = Hertz(1_000_000); 26 spi_config.frequency = Hertz(1_000_000);
26 27
27 let mut spi = Spi::new( 28 let mut spi = Spi::new(
28 spi, sck, // Arduino D13 29 &mut spi_peri,
29 mosi, // Arduino D11 30 &mut sck, // Arduino D13
30 miso, // Arduino D12 31 &mut mosi, // Arduino D11
31 tx_dma, rx_dma, spi_config, 32 &mut miso, // Arduino D12
33 &mut tx_dma,
34 &mut rx_dma,
35 spi_config,
32 ); 36 );
33 37
34 let data: [u8; 9] = [0x00, 0xFF, 0xAA, 0x55, 0xC0, 0xFF, 0xEE, 0xC0, 0xDE]; 38 let data: [u8; 9] = [0x00, 0xFF, 0xAA, 0x55, 0xC0, 0xFF, 0xEE, 0xC0, 0xDE];
@@ -59,8 +63,12 @@ async fn main(_spawner: Spawner) {
59 spi.transfer_in_place::<u8>(&mut []).await.unwrap(); 63 spi.transfer_in_place::<u8>(&mut []).await.unwrap();
60 spi.read::<u8>(&mut []).await.unwrap(); 64 spi.read::<u8>(&mut []).await.unwrap();
61 spi.write::<u8>(&[]).await.unwrap(); 65 spi.write::<u8>(&[]).await.unwrap();
66 spi.blocking_transfer::<u8>(&mut [], &[]).unwrap();
67 spi.blocking_transfer_in_place::<u8>(&mut []).unwrap();
68 spi.blocking_read::<u8>(&mut []).unwrap();
69 spi.blocking_write::<u8>(&[]).unwrap();
62 70
63 // === Check mixing blocking with async. 71 // Check mixing blocking with async.
64 spi.blocking_transfer(&mut buf, &data).unwrap(); 72 spi.blocking_transfer(&mut buf, &data).unwrap();
65 assert_eq!(buf, data); 73 assert_eq!(buf, data);
66 spi.transfer(&mut buf, &data).await.unwrap(); 74 spi.transfer(&mut buf, &data).await.unwrap();
@@ -76,6 +84,65 @@ async fn main(_spawner: Spawner) {
76 spi.blocking_read(&mut buf).unwrap(); 84 spi.blocking_read(&mut buf).unwrap();
77 spi.write(&buf).await.unwrap(); 85 spi.write(&buf).await.unwrap();
78 86
87 core::mem::drop(spi);
88
89 // test rx-only configuration
90 let mut spi = Spi::new_rxonly(
91 &mut spi_peri,
92 &mut sck,
93 &mut miso,
94 // SPIv1/f1 requires txdma even if rxonly.
95 #[cfg(not(feature = "spi-v345"))]
96 &mut tx_dma,
97 &mut rx_dma,
98 spi_config,
99 );
100 let mut mosi_out = Output::new(&mut mosi, Level::Low, Speed::VeryHigh);
101 mosi_out.set_high();
102 spi.read(&mut buf).await.unwrap();
103 assert_eq!(buf, [0xff; 9]);
104 spi.blocking_read(&mut buf).unwrap();
105 assert_eq!(buf, [0xff; 9]);
106 spi.read(&mut buf).await.unwrap();
107 assert_eq!(buf, [0xff; 9]);
108 spi.read(&mut buf).await.unwrap();
109 assert_eq!(buf, [0xff; 9]);
110 spi.blocking_read(&mut buf).unwrap();
111 assert_eq!(buf, [0xff; 9]);
112 spi.blocking_read(&mut buf).unwrap();
113 assert_eq!(buf, [0xff; 9]);
114 mosi_out.set_low();
115 spi.read(&mut buf).await.unwrap();
116 assert_eq!(buf, [0x00; 9]);
117 spi.read::<u8>(&mut []).await.unwrap();
118 spi.blocking_read::<u8>(&mut []).unwrap();
119 drop(mosi_out);
120 drop(spi);
121
122 // Test tx-only. Just check it doesn't hang, not much else we can do without using SPI slave.
123 let mut spi = Spi::new_txonly(&mut spi_peri, &mut sck, &mut mosi, &mut tx_dma, spi_config);
124 spi.blocking_write(&buf).unwrap();
125 spi.write(&buf).await.unwrap();
126 spi.blocking_write(&buf).unwrap();
127 spi.blocking_write(&buf).unwrap();
128 spi.write(&buf).await.unwrap();
129 spi.write(&buf).await.unwrap();
130 spi.write::<u8>(&[]).await.unwrap();
131 spi.blocking_write::<u8>(&[]).unwrap();
132 drop(spi);
133
134 // Test tx-only nosck.
135 let mut spi = Spi::new_txonly_nosck(&mut spi_peri, &mut mosi, &mut tx_dma, spi_config);
136 spi.blocking_write(&buf).unwrap();
137 spi.write(&buf).await.unwrap();
138 spi.blocking_write(&buf).unwrap();
139 spi.blocking_write(&buf).unwrap();
140 spi.write(&buf).await.unwrap();
141 spi.write(&buf).await.unwrap();
142 spi.write::<u8>(&[]).await.unwrap();
143 spi.blocking_write::<u8>(&[]).unwrap();
144 drop(spi);
145
79 info!("Test OK"); 146 info!("Test OK");
80 cortex_m::asm::bkpt(); 147 cortex_m::asm::bkpt();
81} 148}