diff options
| author | Gustav Toft <[email protected]> | 2024-06-05 08:11:50 +0200 |
|---|---|---|
| committer | Gustav Toft <[email protected]> | 2024-06-05 08:11:50 +0200 |
| commit | 319e18b3997756942803cb1c10ae43327a4e3056 (patch) | |
| tree | 428f0d698d58dd569f9b3fb8b1ee47c2ca9a70a1 | |
| parent | d3c3670a966cd68b8d2d46a732ab971390ec3006 (diff) | |
| parent | 5f9bc6def7ea8698a6ce45d8e12e1d1bd8cce876 (diff) | |
Merge branch 'main' of https://github.com/embassy-rs/embassy into fix_main
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 | ||
| 300 | Using `patch` will replace all direct AND indirect dependencies. | 300 | Using `patch` will replace all direct AND indirect dependencies. |
| 301 | 301 | ||
| 302 | See the link:https://embassy.dev/book/dev/new_project.html#_cargo_toml[new project docs] for more details on this approach. | 302 | See 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 | ||
| 132 | If 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]. | 132 | If 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 | ||
| 134 | If 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]. | 134 | If 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] |
| 24 | defmt = { version = "0.3", optional = true } | 24 | defmt = { version = "0.3", optional = true } |
| 25 | log = { version = "0.4.17", optional = true } | ||
| 25 | 26 | ||
| 26 | embassy-sync = { version = "0.6.0", path = "../embassy-sync" } | 27 | embassy-sync = { version = "0.6.0", path = "../embassy-sync" } |
| 27 | embassy-nrf = { version = "0.1.0", path = "../embassy-nrf", default-features = false } | 28 | embassy-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] |
| 23 | defmt = { version = "0.3", optional = true } | 23 | defmt = { version = "0.3", optional = true } |
| 24 | defmt-rtt = { version = "0.4", optional = true } | ||
| 25 | log = { version = "0.4", optional = true } | 24 | log = { version = "0.4", optional = true } |
| 26 | 25 | ||
| 27 | embassy-sync = { version = "0.6.0", path = "../embassy-sync" } | 26 | embassy-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 | ] |
| 49 | debug = ["defmt-rtt"] | ||
| 50 | 48 | ||
| 51 | [profile.dev] | 49 | [profile.dev] |
| 52 | debug = 2 | 50 | debug = 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] |
| 24 | defmt = { version = "0.3", optional = true } | 24 | defmt = { version = "0.3", optional = true } |
| 25 | defmt-rtt = { version = "0.4", optional = true } | ||
| 26 | log = { version = "0.4", optional = true } | 25 | log = { version = "0.4", optional = true } |
| 27 | 26 | ||
| 28 | embassy-sync = { version = "0.6.0", path = "../embassy-sync" } | 27 | embassy-sync = { version = "0.6.0", path = "../embassy-sync" } |
| @@ -37,7 +36,6 @@ cfg-if = "1.0.0" | |||
| 37 | [features] | 36 | [features] |
| 38 | defmt = ["dep:defmt", "embassy-boot/defmt", "embassy-stm32/defmt"] | 37 | defmt = ["dep:defmt", "embassy-boot/defmt", "embassy-stm32/defmt"] |
| 39 | log = ["dep:log", "embassy-boot/log", "embassy-stm32/log"] | 38 | log = ["dep:log", "embassy-boot/log", "embassy-stm32/log"] |
| 40 | debug = ["defmt-rtt"] | ||
| 41 | 39 | ||
| 42 | [profile.dev] | 40 | [profile.dev] |
| 43 | debug = 2 | 41 | debug = 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 | ||
| 25 | The 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. | 25 | The 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 | ||
| 27 | For more details on the bootloader, see [the documentation](https://embassy.dev/book/dev/bootloader.html). | 27 | For 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; | |||
| 3 | use std::path::PathBuf; | 3 | use std::path::PathBuf; |
| 4 | use std::{env, fs}; | 4 | use std::{env, fs}; |
| 5 | 5 | ||
| 6 | #[path = "./build_common.rs"] | ||
| 7 | mod common; | ||
| 8 | |||
| 6 | static CONFIGS: &[(&str, usize)] = &[ | 9 | static 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 | |||
| 9 | use std::collections::HashSet; | ||
| 10 | use std::env; | ||
| 11 | use std::ffi::OsString; | ||
| 12 | use 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)] | ||
| 17 | pub struct CfgSet { | ||
| 18 | enabled: HashSet<String>, | ||
| 19 | declared: HashSet<String>, | ||
| 20 | emit_declared: bool, | ||
| 21 | } | ||
| 22 | |||
| 23 | impl 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 | |||
| 72 | fn 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. | ||
| 84 | pub 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 @@ | |||
| 1 | use std::env; | 1 | #[path = "./build_common.rs"] |
| 2 | mod common; | ||
| 2 | 3 | ||
| 3 | fn main() { | 4 | fn 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 | |||
| 9 | use std::collections::HashSet; | ||
| 10 | use std::env; | ||
| 11 | use std::ffi::OsString; | ||
| 12 | use 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)] | ||
| 17 | pub struct CfgSet { | ||
| 18 | enabled: HashSet<String>, | ||
| 19 | declared: HashSet<String>, | ||
| 20 | emit_declared: bool, | ||
| 21 | } | ||
| 22 | |||
| 23 | impl 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 | |||
| 72 | fn 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. | ||
| 84 | pub 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"] } | |||
| 29 | futures-test = "0.3.28" | 29 | futures-test = "0.3.28" |
| 30 | 30 | ||
| 31 | [features] | 31 | [features] |
| 32 | default = [ ] | ||
| 33 | defmt = [ "dep:defmt", "embedded-hal-1/defmt-03" ] | 32 | defmt = [ "dep:defmt", "embedded-hal-1/defmt-03" ] |
| 34 | log = ["dep:log"] | 33 | log = ["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" } | |||
| 28 | embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver", optional=true } | 28 | embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver", optional=true } |
| 29 | 29 | ||
| 30 | defmt = { version = "0.3", optional = true } | 30 | defmt = { version = "0.3", optional = true } |
| 31 | log = { version = "0.4.17", optional = true } | ||
| 32 | |||
| 31 | cortex-m = "0.7.6" | 33 | cortex-m = "0.7.6" |
| 32 | heapless = "0.8" | 34 | heapless = "0.8" |
| 33 | aligned = "0.4.1" | 35 | aligned = "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" | |||
| 72 | sdio-host = "0.5.0" | 72 | sdio-host = "0.5.0" |
| 73 | critical-section = "1.1" | 73 | critical-section = "1.1" |
| 74 | #stm32-metapac = { version = "15" } | 74 | #stm32-metapac = { version = "15" } |
| 75 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-34c0188a682b32c32ff147d377e0629b1ebe8318" } | 75 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-59b1f65bd109c3ef35782e6c44062208d0ef3d0e" } |
| 76 | 76 | ||
| 77 | vcell = "0.1.3" | 77 | vcell = "0.1.3" |
| 78 | nb = "1.0.0" | 78 | nb = "1.0.0" |
| @@ -97,7 +97,7 @@ proc-macro2 = "1.0.36" | |||
| 97 | quote = "1.0.15" | 97 | quote = "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"]} |
| 100 | stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-34c0188a682b32c32ff147d377e0629b1ebe8318", default-features = false, features = ["metadata"]} | 100 | stm32-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] |
| 103 | default = ["rt"] | 103 | default = ["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}; | |||
| 9 | use quote::{format_ident, quote}; | 9 | use quote::{format_ident, quote}; |
| 10 | use stm32_metapac::metadata::ir::BitOffset; | 10 | use stm32_metapac::metadata::ir::BitOffset; |
| 11 | use stm32_metapac::metadata::{ | 11 | use 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 | ||
| 15 | fn main() { | 16 | #[path = "./build_common.rs"] |
| 16 | let target = env::var("TARGET").unwrap(); | 17 | mod 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") { | 19 | fn 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 | |||
| 9 | use std::collections::HashSet; | ||
| 10 | use std::env; | ||
| 11 | use std::ffi::OsString; | ||
| 12 | use 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)] | ||
| 17 | pub struct CfgSet { | ||
| 18 | enabled: HashSet<String>, | ||
| 19 | declared: HashSet<String>, | ||
| 20 | emit_declared: bool, | ||
| 21 | } | ||
| 22 | |||
| 23 | impl 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 | |||
| 72 | fn 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. | ||
| 84 | pub 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; | |||
| 7 | use super::blocking_delay_us; | 7 | use super::blocking_delay_us; |
| 8 | use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; | 8 | use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; |
| 9 | use crate::time::Hertz; | 9 | use crate::time::Hertz; |
| 10 | use crate::{interrupt, Peripheral}; | 10 | use crate::{interrupt, rcc, Peripheral}; |
| 11 | 11 | ||
| 12 | pub const VDDA_CALIB_MV: u32 = 3300; | 12 | pub const VDDA_CALIB_MV: u32 = 3300; |
| 13 | pub const ADC_MAX: u32 = (1 << 12) - 1; | 13 | pub const ADC_MAX: u32 = (1 << 12) - 1; |
| @@ -50,7 +50,7 @@ impl<T: Instance> super::SealedAdcChannel<T> for Temperature { | |||
| 50 | impl<'d, T: Instance> Adc<'d, T> { | 50 | impl<'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; | |||
| 8 | use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; | 8 | use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; |
| 9 | use crate::interrupt::typelevel::Interrupt; | 9 | use crate::interrupt::typelevel::Interrupt; |
| 10 | use crate::time::Hertz; | 10 | use crate::time::Hertz; |
| 11 | use crate::{interrupt, Peripheral}; | 11 | use crate::{interrupt, rcc, Peripheral}; |
| 12 | 12 | ||
| 13 | pub const VDDA_CALIB_MV: u32 = 3300; | 13 | pub const VDDA_CALIB_MV: u32 = 3300; |
| 14 | pub const ADC_MAX: u32 = (1 << 12) - 1; | 14 | pub 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; | |||
| 10 | use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; | 10 | use crate::adc::{Adc, AdcChannel, Instance, SampleTime}; |
| 11 | use crate::interrupt::typelevel::Interrupt; | 11 | use crate::interrupt::typelevel::Interrupt; |
| 12 | use crate::time::Hertz; | 12 | use crate::time::Hertz; |
| 13 | use crate::{interrupt, Peripheral}; | 13 | use crate::{interrupt, rcc, Peripheral}; |
| 14 | 14 | ||
| 15 | const ADC_FREQ: Hertz = crate::rcc::HSI_FREQ; | 15 | const 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 | ||
| 5 | use super::{blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime}; | 5 | use super::{blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime}; |
| 6 | use crate::time::Hertz; | 6 | use crate::time::Hertz; |
| 7 | use crate::{pac, Peripheral}; | 7 | use 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. |
| 10 | pub const VREF_DEFAULT_MV: u32 = 3300; | 10 | pub 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)] |
| 73 | pub(crate) fn blocking_delay_us(us: u32) { | 73 | pub(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; | |||
| 10 | use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; | 10 | use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; |
| 11 | use crate::interrupt::typelevel::Interrupt; | 11 | use crate::interrupt::typelevel::Interrupt; |
| 12 | use crate::peripherals::ADC1; | 12 | use crate::peripherals::ADC1; |
| 13 | use crate::{interrupt, Peripheral}; | 13 | use crate::{interrupt, rcc, Peripheral}; |
| 14 | 14 | ||
| 15 | pub const VDDA_CALIB_MV: u32 = 3300; | 15 | pub const VDDA_CALIB_MV: u32 = 3300; |
| 16 | pub const VREF_INT: u32 = 1230; | 16 | pub 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; | |||
| 4 | use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; | 4 | use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; |
| 5 | use crate::peripherals::ADC1; | 5 | use crate::peripherals::ADC1; |
| 6 | use crate::time::Hertz; | 6 | use crate::time::Hertz; |
| 7 | use crate::Peripheral; | 7 | use 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. |
| 10 | pub const VREF_DEFAULT_MV: u32 = 3300; | 10 | pub const VREF_DEFAULT_MV: u32 = 3300; |
| @@ -31,7 +31,7 @@ impl AdcChannel<ADC1> for Temperature {} | |||
| 31 | impl super::SealedAdcChannel<ADC1> for Temperature { | 31 | impl 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 | ||
| 4 | use super::blocking_delay_us; | 4 | use super::blocking_delay_us; |
| 5 | use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; | 5 | use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime}; |
| 6 | use crate::Peripheral; | 6 | use 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. |
| 9 | pub const VREF_DEFAULT_MV: u32 = 3300; | 9 | pub const VREF_DEFAULT_MV: u32 = 3300; |
| @@ -94,7 +94,7 @@ cfg_if! { | |||
| 94 | impl<'d, T: Instance> Adc<'d, T> { | 94 | impl<'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 | ||
| 5 | use super::{blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime}; | 5 | use super::{blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime}; |
| 6 | use crate::time::Hertz; | 6 | use crate::time::Hertz; |
| 7 | use crate::{pac, Peripheral}; | 7 | use 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. |
| 10 | pub const VREF_DEFAULT_MV: u32 = 3300; | 10 | pub 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 | ||
| 3 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 4 | 4 | ||
| 5 | use super::{ExtendedId, Fifo, FilterOwner, Id, Instance, MasterInstance, StandardId}; | 5 | use super::{ExtendedId, Fifo, Id, StandardId}; |
| 6 | 6 | ||
| 7 | const F32_RTR: u32 = 0b010; // set the RTR bit to match remote frames | 7 | const F32_RTR: u32 = 0b010; // set the RTR bit to match remote frames |
| 8 | const F32_IDE: u32 = 0b100; // set the IDE bit to match extended identifiers | 8 | const 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. |
| 213 | pub struct MasterFilters<'a, I: FilterOwner> { | 213 | pub 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. |
| 224 | impl<I: FilterOwner> MasterFilters<'_, I> { | 224 | impl 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 | ||
| 294 | impl<I: MasterInstance> MasterFilters<'_, I> { | 294 | impl 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 | ||
| 315 | impl<I: FilterOwner> Drop for MasterFilters<'_, I> { | 315 | impl 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. |
| 324 | pub struct SlaveFilters<'a, I: Instance> { | 324 | pub 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 | ||
| 331 | impl<I: Instance> SlaveFilters<'_, I> { | 331 | impl 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> { | |||
| 377 | struct FilterBanks { | 377 | struct 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 | ||
| 383 | impl FilterBanks { | 383 | impl 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; | |||
| 5 | use core::marker::PhantomData; | 5 | use core::marker::PhantomData; |
| 6 | use core::task::Poll; | 6 | use core::task::Poll; |
| 7 | 7 | ||
| 8 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 8 | use embassy_hal_internal::interrupt::InterruptExt; |
| 9 | use embassy_hal_internal::into_ref; | ||
| 9 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | 10 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; |
| 10 | use embassy_sync::channel::Channel; | 11 | use embassy_sync::channel::Channel; |
| 11 | use embassy_sync::waitqueue::AtomicWaker; | 12 | use embassy_sync::waitqueue::AtomicWaker; |
| @@ -19,7 +20,7 @@ use super::util; | |||
| 19 | use crate::can::enums::{BusError, TryReadError}; | 20 | use crate::can::enums::{BusError, TryReadError}; |
| 20 | use crate::gpio::AFType; | 21 | use crate::gpio::AFType; |
| 21 | use crate::interrupt::typelevel::Interrupt; | 22 | use crate::interrupt::typelevel::Interrupt; |
| 22 | use crate::rcc::RccPeripheral; | 23 | use crate::rcc::{self, RccPeripheral}; |
| 23 | use crate::{interrupt, peripherals, Peripheral}; | 24 | use 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`]. |
| 93 | pub struct CanConfig<'a, T: Instance> { | 94 | pub 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 | ||
| 97 | impl<T: Instance> CanConfig<'_, T> { | 100 | impl 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 | ||
| 148 | impl<T: Instance> Drop for CanConfig<'_, T> { | 151 | impl 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 |
| 156 | pub struct Can<'d, T: Instance> { | 159 | pub 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 | ||
| 168 | impl<'d, T: Instance> Can<'d, T> { | 174 | impl<'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 | ||
| 423 | impl<'d, T: FilterOwner> Can<'d, T> { | 459 | impl<'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. |
| 434 | pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { | 470 | pub 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 | ||
| 439 | impl<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> { | 475 | impl<'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. |
| 474 | pub struct CanTx<'d, T: Instance> { | 510 | pub struct CanTx<'d> { |
| 475 | _peri: PeripheralRef<'d, T>, | 511 | _phantom: PhantomData<&'d ()>, |
| 512 | info: &'static Info, | ||
| 513 | state: &'static State, | ||
| 476 | } | 514 | } |
| 477 | 515 | ||
| 478 | impl<'d, T: Instance> CanTx<'d, T> { | 516 | impl<'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> { | |||
| 599 | pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>; | 637 | pub 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. |
| 602 | pub struct BufferedCanTx<'d, T: Instance, const TX_BUF_SIZE: usize> { | 640 | pub 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 | ||
| 607 | impl<'d, T: Instance, const TX_BUF_SIZE: usize> BufferedCanTx<'d, T, TX_BUF_SIZE> { | 647 | impl<'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 | ||
| 638 | impl<'d, T: Instance, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, T, TX_BUF_SIZE> { | 689 | impl<'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)] |
| 648 | pub struct CanRx<'d, T: Instance> { | 703 | pub struct CanRx<'d> { |
| 649 | peri: PeripheralRef<'d, T>, | 704 | _phantom: PhantomData<&'d ()>, |
| 705 | info: &'static Info, | ||
| 706 | state: &'static State, | ||
| 650 | } | 707 | } |
| 651 | 708 | ||
| 652 | impl<'d, T: Instance> CanRx<'d, T> { | 709 | impl<'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> { | |||
| 684 | pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<Envelope, BusError>, BUF_SIZE>; | 741 | pub 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. |
| 687 | pub struct BufferedCanRx<'d, T: Instance, const RX_BUF_SIZE: usize> { | 744 | pub 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 | ||
| 692 | impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE> { | 751 | impl<'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 | ||
| 749 | impl<'d, T: Instance, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, T, RX_BUF_SIZE> { | 818 | impl<'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 | ||
| 757 | impl<'d, T: Instance> Drop for Can<'d, T> { | 830 | impl 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 | ||
| 906 | enum TxMode { | 981 | pub(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 | ||
| 946 | struct State { | 1021 | pub(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 | ||
| 1037 | pub(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 | |||
| 962 | trait SealedInstance { | 1051 | trait 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}; | |||
| 11 | pub(crate) struct Registers(pub crate::pac::can::Can); | 11 | pub(crate) struct Registers(pub crate::pac::can::Can); |
| 12 | 12 | ||
| 13 | impl Registers { | 13 | impl 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 | ||
| 22 | pub struct Registers { | 22 | pub 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; | |||
| 3 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 4 | use core::task::Poll; | 4 | use core::task::Poll; |
| 5 | 5 | ||
| 6 | use embassy_hal_internal::interrupt::InterruptExt; | ||
| 6 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 7 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 7 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | 8 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; |
| 8 | use embassy_sync::channel::{Channel, DynamicReceiver, DynamicSender}; | 9 | use embassy_sync::channel::{Channel, DynamicReceiver, DynamicSender}; |
| @@ -11,7 +12,7 @@ use embassy_sync::waitqueue::AtomicWaker; | |||
| 11 | use crate::can::fd::peripheral::Registers; | 12 | use crate::can::fd::peripheral::Registers; |
| 12 | use crate::gpio::AFType; | 13 | use crate::gpio::AFType; |
| 13 | use crate::interrupt::typelevel::Interrupt; | 14 | use crate::interrupt::typelevel::Interrupt; |
| 14 | use crate::rcc::RccPeripheral; | 15 | use crate::rcc::{self, RccPeripheral}; |
| 15 | use crate::{interrupt, peripherals, Peripheral}; | 16 | use crate::{interrupt, peripherals, Peripheral}; |
| 16 | 17 | ||
| 17 | pub(crate) mod fd; | 18 | pub(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 |
| 41 | impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0InterruptHandler<T> { | 42 | impl<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 | 144 | fn calc_ns_per_timer_tick( |
| 144 | /// Create instance of this first | 145 | info: &'static Info, |
| 145 | pub 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 | |||
| 152 | fn 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 | ||
| 167 | impl<'d, T: Instance> CanConfigurator<'d, T> { | 162 | /// FDCAN Configuration instance instance |
| 163 | /// Create instance of this first | ||
| 164 | pub 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 | |||
| 174 | impl<'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 |
| 283 | pub struct Can<'d, T: Instance> { | 297 | pub 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 | ||
| 291 | impl<'d, T: Instance> Can<'d, T> { | 306 | impl<'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< | |||
| 392 | pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>; | 410 | pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>; |
| 393 | 411 | ||
| 394 | /// Buffered FDCAN Instance | 412 | /// Buffered FDCAN Instance |
| 395 | pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> { | 413 | pub 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 | ||
| 404 | impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> | 423 | impl<'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 | ||
| 470 | impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop | 493 | impl<'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 |
| 485 | pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFrame, BUF_SIZE>; | 510 | pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFrame, BUF_SIZE>; |
| 486 | 511 | ||
| 487 | /// Buffered FDCAN Instance | ||
| 488 | pub 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)] |
| 499 | pub struct BufferedFdCanSender { | 514 | pub 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. |
| 525 | pub type BufferedFdCanReceiver = DynamicReceiver<'static, Result<FdEnvelope, BusError>>; | 540 | pub type BufferedFdCanReceiver = DynamicReceiver<'static, Result<FdEnvelope, BusError>>; |
| 526 | 541 | ||
| 527 | impl<'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> | 543 | pub 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 | |||
| 553 | impl<'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 | ||
| 593 | impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop | 623 | impl<'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 |
| 605 | pub struct CanRx<'d, T: Instance> { | 637 | pub 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 | ||
| 644 | impl<'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 |
| 612 | pub struct CanTx<'d, T: Instance> { | 657 | pub 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 | ||
| 618 | impl<'c, 'd, T: Instance> CanTx<'d, T> { | 665 | impl<'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 | |||
| 636 | impl<'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 |
| 812 | pub struct Properties<T> { | 855 | pub 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 | ||
| 817 | impl<T: Instance> Properties<T> { | 861 | impl 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 | ||
| 940 | struct Info { | ||
| 941 | regs: Registers, | ||
| 942 | interrupt0: crate::interrupt::Interrupt, | ||
| 943 | _interrupt1: crate::interrupt::Interrupt, | ||
| 944 | tx_waker: fn(), | ||
| 945 | } | ||
| 946 | |||
| 947 | impl 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 | |||
| 895 | trait SealedInstance { | 966 | trait 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 { | |||
| 915 | pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>); | 986 | pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>); |
| 916 | 987 | ||
| 917 | macro_rules! impl_fdcan { | 988 | macro_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; | |||
| 4 | use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; | 4 | use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; |
| 5 | 5 | ||
| 6 | use crate::pac::cordic::vals; | 6 | use crate::pac::cordic::vals; |
| 7 | use crate::{dma, peripherals}; | 7 | use crate::{dma, peripherals, rcc}; |
| 8 | 8 | ||
| 9 | mod enums; | 9 | mod enums; |
| 10 | pub use enums::*; | 10 | pub 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 | ||
| 260 | impl<'d, T: Instance> Drop for Cordic<'d, T> { | 260 | impl<'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 | ||
| 3 | use crate::pac::CRC as PAC_CRC; | 3 | use crate::pac::CRC as PAC_CRC; |
| 4 | use crate::peripherals::CRC; | 4 | use crate::peripherals::CRC; |
| 5 | use crate::rcc::SealedRccPeripheral; | 5 | use crate::{rcc, Peripheral}; |
| 6 | use crate::Peripheral; | ||
| 7 | 6 | ||
| 8 | /// CRC driver. | 7 | /// CRC driver. |
| 9 | pub struct Crc<'d> { | 8 | pub 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}; | |||
| 3 | use crate::pac::crc::vals; | 3 | use crate::pac::crc::vals; |
| 4 | use crate::pac::CRC as PAC_CRC; | 4 | use crate::pac::CRC as PAC_CRC; |
| 5 | use crate::peripherals::CRC; | 5 | use crate::peripherals::CRC; |
| 6 | use crate::rcc::SealedRccPeripheral; | 6 | use crate::{rcc, Peripheral}; |
| 7 | use crate::Peripheral; | ||
| 8 | 7 | ||
| 9 | /// CRC driver. | 8 | /// CRC driver. |
| 10 | pub struct Crc<'d> { | 9 | pub 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 | ||
| 10 | use crate::dma::{NoDma, Transfer, TransferOptions}; | 10 | use crate::dma::{NoDma, Transfer, TransferOptions}; |
| 11 | use crate::interrupt::typelevel::Interrupt; | 11 | use crate::interrupt::typelevel::Interrupt; |
| 12 | use crate::{interrupt, pac, peripherals, Peripheral}; | 12 | use crate::{interrupt, pac, peripherals, rcc, Peripheral}; |
| 13 | 13 | ||
| 14 | const DES_BLOCK_SIZE: usize = 8; // 64 bits | 14 | const DES_BLOCK_SIZE: usize = 8; // 64 bits |
| 15 | const AES_BLOCK_SIZE: usize = 16; // 128 bits | 15 | const 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}; | |||
| 8 | use crate::dma::NoDma; | 8 | use 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))] |
| 10 | use crate::pac::dac; | 10 | use crate::pac::dac; |
| 11 | use crate::rcc::RccPeripheral; | 11 | use crate::rcc::{self, RccPeripheral}; |
| 12 | use crate::{peripherals, Peripheral}; | 12 | use crate::{peripherals, Peripheral}; |
| 13 | 13 | ||
| 14 | mod tsel; | 14 | mod 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 | ||
| 357 | impl<'d, T: Instance, const N: u8, DMA> Drop for DacChannel<'d, T, N, DMA> { | 357 | impl<'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 | ||
| 510 | trait SealedInstance { | 510 | trait 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 {} | |||
| 523 | foreach_peripheral!( | 523 | foreach_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; | |||
| 9 | use crate::dma::Transfer; | 9 | use crate::dma::Transfer; |
| 10 | use crate::gpio::{AFType, Speed}; | 10 | use crate::gpio::{AFType, Speed}; |
| 11 | use crate::interrupt::typelevel::Interrupt; | 11 | use crate::interrupt::typelevel::Interrupt; |
| 12 | use crate::{interrupt, Peripheral}; | 12 | use crate::{interrupt, rcc, Peripheral}; |
| 13 | 13 | ||
| 14 | /// Interrupt handler. | 14 | /// Interrupt handler. |
| 15 | pub struct InterruptHandler<T: Instance> { | 15 | pub 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}; |
| 8 | use crate::gpio::{AFType, AnyPin, Pull, Speed}; | 8 | use crate::gpio::{AFType, AnyPin, Pull, Speed}; |
| 9 | use crate::rcc::RccPeripheral; | 9 | use crate::rcc::{self, RccPeripheral}; |
| 10 | use crate::{peripherals, Peripheral}; | 10 | use 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. |
| 13 | pub fn blocking_delay_ms(ms: u32) { | 13 | pub 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 | ||
| 409 | trait SealedInstance: crate::rcc::SealedRccPeripheral { | 409 | trait 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); | |||
| 419 | foreach_peripheral!( | 419 | foreach_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; | |||
| 4 | use embassy_hal_internal::into_ref; | 4 | use embassy_hal_internal::into_ref; |
| 5 | 5 | ||
| 6 | use crate::gpio::{AFType, Pull, Speed}; | 6 | use crate::gpio::{AFType, Pull, Speed}; |
| 7 | use crate::Peripheral; | 7 | use crate::{rcc, Peripheral}; |
| 8 | 8 | ||
| 9 | /// FMC driver | 9 | /// FMC driver |
| 10 | pub struct Fmc<'d, T: Instance> { | 10 | pub 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 | ||
| 203 | trait SealedInstance: crate::rcc::SealedRccPeripheral { | 203 | trait 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 | ||
| 823 | pub(crate) unsafe fn init(_cs: CriticalSection) { | 823 | pub(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; | |||
| 17 | use crate::dma::Transfer; | 17 | use crate::dma::Transfer; |
| 18 | use crate::interrupt::typelevel::Interrupt; | 18 | use crate::interrupt::typelevel::Interrupt; |
| 19 | use crate::peripherals::HASH; | 19 | use crate::peripherals::HASH; |
| 20 | use crate::rcc::SealedRccPeripheral; | 20 | use crate::{interrupt, pac, peripherals, rcc, Peripheral}; |
| 21 | use crate::{interrupt, pac, peripherals, Peripheral}; | ||
| 22 | 21 | ||
| 23 | #[cfg(hash_v1)] | 22 | #[cfg(hash_v1)] |
| 24 | const NUM_CONTEXT_REGS: usize = 51; | 23 | const 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 | ||
| 10 | use crate::gpio::{AFType, AnyPin}; | 10 | use crate::gpio::{AFType, AnyPin}; |
| 11 | use crate::time::Hertz; | 11 | use crate::time::Hertz; |
| 12 | use crate::Peripheral; | 12 | use crate::{rcc, Peripheral}; |
| 13 | 13 | ||
| 14 | /// HRTIM burst controller instance. | 14 | /// HRTIM burst controller instance. |
| 15 | pub struct BurstController<T: Instance> { | 15 | pub 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; | |||
| 9 | use core::iter; | 9 | use core::iter; |
| 10 | use core::marker::PhantomData; | 10 | use core::marker::PhantomData; |
| 11 | 11 | ||
| 12 | use embassy_hal_internal::{into_ref, Peripheral}; | 12 | use embassy_hal_internal::{Peripheral, PeripheralRef}; |
| 13 | use embassy_sync::waitqueue::AtomicWaker; | 13 | use embassy_sync::waitqueue::AtomicWaker; |
| 14 | #[cfg(feature = "time")] | 14 | #[cfg(feature = "time")] |
| 15 | use embassy_time::{Duration, Instant}; | 15 | use embassy_time::{Duration, Instant}; |
| 16 | 16 | ||
| 17 | use crate::dma::ChannelAndRequest; | 17 | use crate::dma::ChannelAndRequest; |
| 18 | use crate::gpio::{AFType, Pull}; | 18 | use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed}; |
| 19 | use crate::interrupt::typelevel::Interrupt; | 19 | use crate::interrupt::typelevel::Interrupt; |
| 20 | use crate::mode::{Async, Blocking, Mode}; | 20 | use crate::mode::{Async, Blocking, Mode}; |
| 21 | use crate::rcc::{ClockEnableBit, SealedRccPeripheral}; | 21 | use crate::rcc::{RccInfo, SealedRccPeripheral}; |
| 22 | use crate::time::Hertz; | 22 | use crate::time::Hertz; |
| 23 | use crate::{interrupt, peripherals}; | 23 | use crate::{interrupt, peripherals}; |
| 24 | 24 | ||
| @@ -72,11 +72,29 @@ impl Default for Config { | |||
| 72 | } | 72 | } |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | impl 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. |
| 76 | pub struct I2c<'d, M: Mode> { | 92 | pub 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 | ||
| 195 | impl<'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)] |
| 178 | struct Timeout { | 205 | struct Timeout { |
| 179 | #[cfg(feature = "time")] | 206 | #[cfg(feature = "time")] |
| @@ -224,7 +251,7 @@ impl State { | |||
| 224 | 251 | ||
| 225 | struct Info { | 252 | struct 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 | ||
| 230 | peri_trait!( | 257 | peri_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 | ||
| 703 | impl<'d, M: PeriMode> Drop for I2c<'d, M> { | ||
| 704 | fn drop(&mut self) { | ||
| 705 | self.info.enable_bit.disable() | ||
| 706 | } | ||
| 707 | } | ||
| 708 | |||
| 709 | enum Mode { | 703 | enum 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 | ||
| 674 | impl<'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 | |||
| 2 | use embassy_hal_internal::into_ref; | 3 | use embassy_hal_internal::into_ref; |
| 3 | 4 | ||
| 4 | use crate::gpio::{AFType, AnyPin, SealedPin}; | 5 | use crate::dma::ChannelAndRequest; |
| 6 | use crate::gpio::{AFType, AnyPin, SealedPin, Speed}; | ||
| 5 | use crate::mode::Async; | 7 | use crate::mode::Async; |
| 6 | use crate::pac::spi::vals; | 8 | use crate::pac::spi::vals; |
| 7 | use crate::spi::{Config as SpiConfig, *}; | 9 | use 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)] | ||
| 22 | pub 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)] |
| 31 | pub enum Standard { | 24 | pub enum Standard { |
| @@ -42,7 +35,7 @@ pub enum Standard { | |||
| 42 | } | 35 | } |
| 43 | 36 | ||
| 44 | impl Standard { | 37 | impl 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 | ||
| 78 | impl Format { | 71 | impl 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 | ||
| 109 | impl ClockPolarity { | 102 | impl 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 { | |||
| 127 | pub struct Config { | 120 | pub 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. |
| 156 | pub struct I2S<'d> { | 146 | pub 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)] | ||
| 158 | enum 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 | |||
| 164 | impl<'d> I2S<'d> { | 168 | impl<'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 | ||
| 279 | impl<'d> Drop for I2S<'d> { | 413 | impl<'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. | ||
| 462 | fn 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 | ||
| 7 | use embassy_sync::waitqueue::AtomicWaker; | 7 | use embassy_sync::waitqueue::AtomicWaker; |
| 8 | 8 | ||
| 9 | use crate::interrupt; | ||
| 10 | use crate::interrupt::typelevel::Interrupt; | 9 | use crate::interrupt::typelevel::Interrupt; |
| 11 | use crate::peripherals::IPCC; | 10 | use crate::peripherals::IPCC; |
| 12 | use crate::rcc::SealedRccPeripheral; | 11 | use crate::{interrupt, rcc}; |
| 13 | 12 | ||
| 14 | /// Interrupt handler. | 13 | /// Interrupt handler. |
| 15 | pub struct ReceiveInterruptHandler {} | 14 | pub struct ReceiveInterruptHandler {} |
| @@ -102,7 +101,7 @@ pub struct Ipcc; | |||
| 102 | impl Ipcc { | 101 | impl 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; | |||
| 83 | pub mod hsem; | 83 | pub mod hsem; |
| 84 | #[cfg(i2c)] | 84 | #[cfg(i2c)] |
| 85 | pub mod i2c; | 85 | pub mod i2c; |
| 86 | #[cfg(all(spi_v1, rcc_f4))] | 86 | #[cfg(any(all(spi_v1, rcc_f4), spi_v3))] |
| 87 | pub mod i2s; | 87 | pub mod i2s; |
| 88 | #[cfg(stm32wb)] | 88 | #[cfg(stm32wb)] |
| 89 | pub mod ipcc; | 89 | pub mod ipcc; |
| @@ -194,7 +194,6 @@ pub(crate) use stm32_metapac as pac; | |||
| 194 | use crate::interrupt::Priority; | 194 | use crate::interrupt::Priority; |
| 195 | #[cfg(feature = "rt")] | 195 | #[cfg(feature = "rt")] |
| 196 | pub use crate::pac::NVIC_PRIO_BITS; | 196 | pub use crate::pac::NVIC_PRIO_BITS; |
| 197 | use 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 |
| 2 | use core::marker::PhantomData; | 2 | use core::marker::PhantomData; |
| 3 | 3 | ||
| 4 | use crate::rcc::RccPeripheral; | 4 | use crate::rcc::{self, RccPeripheral}; |
| 5 | use crate::{peripherals, Peripheral}; | 5 | use 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 | ||
| 95 | trait SealedInstance: crate::rcc::SealedRccPeripheral { | 95 | trait 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); | |||
| 132 | foreach_peripheral!( | 132 | foreach_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}; | |||
| 16 | use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed}; | 16 | use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed}; |
| 17 | use crate::mode::{Async, Blocking, Mode as PeriMode}; | 17 | use crate::mode::{Async, Blocking, Mode as PeriMode}; |
| 18 | use crate::pac::octospi::{vals, Octospi as Regs}; | 18 | use crate::pac::octospi::{vals, Octospi as Regs}; |
| 19 | use crate::rcc::RccPeripheral; | 19 | use crate::rcc::{self, RccPeripheral}; |
| 20 | use crate::{peripherals, Peripheral}; | 20 | use 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; | |||
| 13 | use crate::gpio::{AFType, AnyPin, Pull, Speed}; | 13 | use crate::gpio::{AFType, AnyPin, Pull, Speed}; |
| 14 | use crate::mode::{Async, Blocking, Mode as PeriMode}; | 14 | use crate::mode::{Async, Blocking, Mode as PeriMode}; |
| 15 | use crate::pac::quadspi::Quadspi as Regs; | 15 | use crate::pac::quadspi::Quadspi as Regs; |
| 16 | use crate::rcc::RccPeripheral; | 16 | use crate::rcc::{self, RccPeripheral}; |
| 17 | use crate::{peripherals, Peripheral}; | 17 | use 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)))] |
| 37 | impl From<LseDrive> for crate::pac::rcc::vals::Lsedrv { | 37 | impl 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 | ||
| 3 | use crate::pac::crs::vals::Syncsrc; | 3 | use crate::pac::crs::vals::Syncsrc; |
| 4 | use crate::pac::{CRS, RCC}; | 4 | use crate::pac::{CRS, RCC}; |
| 5 | use crate::rcc::SealedRccPeripheral; | 5 | use crate::rcc::{self, SealedRccPeripheral}; |
| 6 | use crate::time::Hertz; | 6 | use 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 | ||
| 69 | pub(crate) trait SealedRccPeripheral { | 69 | pub(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)] |
| 85 | pub trait RccPeripheral: SealedRccPeripheral + 'static {} | 75 | pub trait RccPeripheral: SealedRccPeripheral + 'static {} |
| 86 | 76 | ||
| 77 | /// Runtime information necessary to reset, enable and disable a peripheral. | ||
| 78 | pub(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)] | ||
| 99 | pub(crate) enum StopMode { | ||
| 100 | Standby, | ||
| 101 | Stop2, | ||
| 102 | Stop1, | ||
| 103 | } | ||
| 104 | |||
| 105 | impl 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)] |
| 88 | mod util { | 250 | mod 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. |
| 131 | pub unsafe fn enable_and_reset<T: RccPeripheral>() { | 293 | // TODO: should this be `unsafe`? |
| 132 | T::enable_and_reset(); | 294 | pub 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. |
| 140 | pub unsafe fn disable<T: RccPeripheral>() { | 303 | // TODO: should this be `unsafe`? |
| 141 | T::disable(); | 304 | pub 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 | /// |
| 146 | pub(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, | 314 | pub fn enable_and_reset<T: RccPeripheral>() { |
| 315 | T::RCC_INFO.enable_and_reset(); | ||
| 151 | } | 316 | } |
| 152 | 317 | ||
| 153 | impl 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 { | 324 | pub 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; | |||
| 10 | use rand_core::{CryptoRng, RngCore}; | 10 | use rand_core::{CryptoRng, RngCore}; |
| 11 | 11 | ||
| 12 | use crate::interrupt::typelevel::Interrupt; | 12 | use crate::interrupt::typelevel::Interrupt; |
| 13 | use crate::{interrupt, pac, peripherals, Peripheral}; | 13 | use crate::{interrupt, pac, peripherals, rcc, Peripheral}; |
| 14 | 14 | ||
| 15 | static RNG_WAKER: AtomicWaker = AtomicWaker::new(); | 15 | static 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")] |
| 2 | use chrono::{Datelike, NaiveDate, Timelike, Weekday}; | 2 | use chrono::{Datelike, NaiveDate, Timelike, Weekday}; |
| 3 | 3 | ||
| 4 | #[cfg(any(feature = "defmt", feature = "time"))] | ||
| 5 | use crate::peripherals::RTC; | ||
| 6 | #[cfg(any(feature = "defmt", feature = "time"))] | ||
| 7 | use crate::rtc::SealedInstance; | ||
| 8 | |||
| 9 | /// Represents an instant in time that can be substracted to compute a duration | ||
| 10 | pub struct RtcInstant { | ||
| 11 | /// 0..59 | ||
| 12 | pub second: u8, | ||
| 13 | /// 0..256 | ||
| 14 | pub subsecond: u16, | ||
| 15 | } | ||
| 16 | |||
| 17 | impl 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")] | ||
| 29 | impl 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")] | ||
| 41 | impl 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)] |
| 65 | pub enum Error { | 6 | pub 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 @@ | |||
| 1 | use super::{bcd2_to_byte, DateTimeError, Rtc, RtcError}; | ||
| 2 | use crate::peripherals::RTC; | ||
| 3 | use crate::rtc::SealedInstance; | ||
| 4 | |||
| 5 | /// Represents an instant in time that can be substracted to compute a duration | ||
| 6 | pub(super) struct RtcInstant { | ||
| 7 | /// 0..59 | ||
| 8 | second: u8, | ||
| 9 | /// 0..256 | ||
| 10 | subsecond: u16, | ||
| 11 | } | ||
| 12 | |||
| 13 | impl 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")] | ||
| 25 | impl 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")] | ||
| 37 | impl 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)] | ||
| 61 | pub(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))] | ||
| 69 | impl 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))] | ||
| 83 | impl 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 | |||
| 97 | impl 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 | |||
| 111 | impl 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 @@ | |||
| 2 | mod datetime; | 2 | mod datetime; |
| 3 | 3 | ||
| 4 | #[cfg(feature = "low-power")] | 4 | #[cfg(feature = "low-power")] |
| 5 | mod low_power; | ||
| 6 | |||
| 7 | #[cfg(feature = "low-power")] | ||
| 5 | use core::cell::Cell; | 8 | use 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")] |
| 10 | use embassy_sync::blocking_mutex::Mutex; | 13 | use embassy_sync::blocking_mutex::Mutex; |
| 11 | 14 | ||
| 12 | #[cfg(not(rtc_v2f2))] | ||
| 13 | use self::datetime::RtcInstant; | ||
| 14 | use self::datetime::{day_of_week_from_u8, day_of_week_to_u8}; | 15 | use self::datetime::{day_of_week_from_u8, day_of_week_to_u8}; |
| 15 | pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; | 16 | pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError}; |
| 16 | use crate::pac::rtc::regs::{Dr, Tr}; | 17 | use crate::pac::rtc::regs::{Dr, Tr}; |
| @@ -32,60 +33,6 @@ use embassy_hal_internal::Peripheral; | |||
| 32 | 33 | ||
| 33 | use crate::peripherals::RTC; | 34 | use crate::peripherals::RTC; |
| 34 | 35 | ||
| 35 | #[allow(dead_code)] | ||
| 36 | #[repr(u8)] | ||
| 37 | #[derive(Clone, Copy, Debug)] | ||
| 38 | pub(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))] | ||
| 46 | impl 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))] | ||
| 60 | impl 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")] | ||
| 75 | impl 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 | ||
| 108 | impl RtcTimeProvider { | 55 | impl 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. |
| 166 | pub struct Rtc { | 104 | pub 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; | |||
| 11 | use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; | 11 | use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer}; |
| 12 | use crate::gpio::{AFType, AnyPin, SealedPin as _}; | 12 | use crate::gpio::{AFType, AnyPin, SealedPin as _}; |
| 13 | use crate::pac::sai::{vals, Sai as Regs}; | 13 | use crate::pac::sai::{vals, Sai as Regs}; |
| 14 | use crate::rcc::RccPeripheral; | 14 | use crate::rcc::{self, RccPeripheral}; |
| 15 | use crate::{peripherals, Peripheral}; | 15 | use 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. |
| 723 | pub fn split_subblocks<'d, T: Instance>(peri: impl Peripheral<P = T> + 'd) -> (SubBlock<'d, T, A>, SubBlock<'d, T, B>) { | 723 | pub 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; | |||
| 16 | use crate::gpio::{AFType, AnyPin, Pull, SealedPin, Speed}; | 16 | use crate::gpio::{AFType, AnyPin, Pull, SealedPin, Speed}; |
| 17 | use crate::interrupt::typelevel::Interrupt; | 17 | use crate::interrupt::typelevel::Interrupt; |
| 18 | use crate::pac::sdmmc::Sdmmc as RegBlock; | 18 | use crate::pac::sdmmc::Sdmmc as RegBlock; |
| 19 | use crate::rcc::RccPeripheral; | 19 | use crate::rcc::{self, RccPeripheral}; |
| 20 | use crate::time::Hertz; | 20 | use crate::time::Hertz; |
| 21 | use crate::{interrupt, peripherals, Peripheral}; | 21 | use 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}; | |||
| 13 | use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed}; | 13 | use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed}; |
| 14 | use crate::mode::{Async, Blocking, Mode as PeriMode}; | 14 | use crate::mode::{Async, Blocking, Mode as PeriMode}; |
| 15 | use crate::pac::spi::{regs, vals, Spi as Regs}; | 15 | use crate::pac::spi::{regs, vals, Spi as Regs}; |
| 16 | use crate::rcc::{ClockEnableBit, SealedRccPeripheral}; | 16 | use crate::rcc::{RccInfo, SealedRccPeripheral}; |
| 17 | use crate::time::Hertz; | 17 | use crate::time::Hertz; |
| 18 | use crate::Peripheral; | 18 | use 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 | ||
| 808 | fn check_error_flags(sr: regs::Sr) -> Result<(), Error> { | 937 | fn 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 | ||
| 835 | fn spin_until_tx_ready(regs: Regs) -> Result<(), Error> { | 964 | fn 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 | ||
| 933 | fn transfer_word<W: Word>(regs: Regs, tx_word: W) -> Result<W, Error> { | 1068 | fn 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 | ||
| 1085 | fn 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 |
| 951 | macro_rules! impl_blocking { | 1101 | macro_rules! impl_blocking { |
| @@ -1118,7 +1268,7 @@ mod word_impl { | |||
| 1118 | 1268 | ||
| 1119 | pub(crate) struct Info { | 1269 | pub(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 | ||
| 1124 | struct State {} | 1274 | struct 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 | ||
| 13 | use crate::interrupt::typelevel::Interrupt; | 13 | use crate::interrupt::typelevel::Interrupt; |
| 14 | use crate::pac::timer::vals; | 14 | use crate::pac::timer::vals; |
| 15 | use crate::rcc::SealedRccPeripheral; | 15 | use crate::rcc::{self, SealedRccPeripheral}; |
| 16 | #[cfg(feature = "low-power")] | 16 | #[cfg(feature = "low-power")] |
| 17 | use crate::rtc::Rtc; | 17 | use crate::rtc::Rtc; |
| 18 | use crate::timer::{CoreInstance, GeneralInstance1Channel}; | 18 | use 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 | ||
| 8 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 8 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 9 | 9 | ||
| 10 | use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, Timer}; | 10 | use super::low_level::{CountingMode, FilterValue, InputCaptureMode, InputTISelection, Timer}; |
| 11 | use super::{ | 11 | use 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 | ||
| 9 | use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; | 9 | use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; |
| 10 | // Re-export useful enums | ||
| 11 | pub use stm32_metapac::timer::vals::{FilterValue, Sms as SlaveMode, Ts as TriggerSource}; | ||
| 10 | 12 | ||
| 11 | use super::*; | 13 | use super::*; |
| 12 | use crate::pac::timer::vals; | 14 | use crate::pac::timer::vals; |
| 15 | use crate::rcc; | ||
| 13 | use crate::time::Hertz; | 16 | use 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 | ||
| 182 | impl<'d, T: CoreInstance> Drop for Timer<'d, T> { | 185 | impl<'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; | |||
| 8 | pub mod complementary_pwm; | 8 | pub mod complementary_pwm; |
| 9 | pub mod input_capture; | 9 | pub mod input_capture; |
| 10 | pub mod low_level; | 10 | pub mod low_level; |
| 11 | pub mod pwm_input; | ||
| 11 | pub mod qei; | 12 | pub mod qei; |
| 12 | pub mod simple_pwm; | 13 | pub 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 | |||
| 3 | use embassy_hal_internal::into_ref; | ||
| 4 | |||
| 5 | use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource}; | ||
| 6 | use super::{Channel, Channel1Pin, Channel2Pin, GeneralInstance4Channel}; | ||
| 7 | use crate::gpio::{AFType, Pull}; | ||
| 8 | use crate::time::Hertz; | ||
| 9 | use crate::Peripheral; | ||
| 10 | |||
| 11 | /// PWM Input driver. | ||
| 12 | pub struct PwmInput<'d, T: GeneralInstance4Channel> { | ||
| 13 | channel: Channel, | ||
| 14 | inner: Timer<'d, T>, | ||
| 15 | } | ||
| 16 | |||
| 17 | impl<'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 | ||
| 73 | use crate::gpio::{AFType, AnyPin}; | 73 | use crate::gpio::{AFType, AnyPin}; |
| 74 | use crate::pac::tsc::Tsc as Regs; | 74 | use crate::pac::tsc::Tsc as Regs; |
| 75 | use crate::rcc::RccPeripheral; | 75 | use crate::rcc::{self, RccPeripheral}; |
| 76 | use crate::{peripherals, Peripheral}; | 76 | use 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 | ||
| 881 | impl<'d, T: Instance> Drop for Tsc<'d, T> { | 881 | impl<'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; | |||
| 28 | use crate::interrupt::typelevel::Interrupt; | 28 | use crate::interrupt::typelevel::Interrupt; |
| 29 | use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode}; | 29 | use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode}; |
| 30 | pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, TypecVstateCc as CcVState}; | 30 | pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, TypecVstateCc as CcVState}; |
| 31 | use crate::rcc::RccPeripheral; | 31 | use crate::rcc::{self, RccPeripheral}; |
| 32 | 32 | ||
| 33 | pub(crate) fn init( | 33 | pub(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 | ||
| 7 | use embassy_embedded_hal::SetConfig; | 7 | use embassy_embedded_hal::SetConfig; |
| 8 | use embassy_hal_internal::atomic_ring_buffer::RingBuffer; | 8 | use embassy_hal_internal::atomic_ring_buffer::RingBuffer; |
| 9 | use embassy_hal_internal::{into_ref, Peripheral}; | 9 | use embassy_hal_internal::{Peripheral, PeripheralRef}; |
| 10 | use embassy_sync::waitqueue::AtomicWaker; | 10 | use 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 | }; |
| 18 | use crate::gpio::AFType; | 18 | use crate::gpio::{AFType, AnyPin, SealedPin as _}; |
| 19 | use crate::interrupt::typelevel::Interrupt as _; | ||
| 20 | use crate::interrupt::{self, InterruptExt}; | 19 | use crate::interrupt::{self, InterruptExt}; |
| 21 | use crate::time::Hertz; | 20 | use 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 | ||
| 171 | impl<'d> SetConfig for BufferedUart<'d> { | 173 | impl<'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; | |||
| 14 | use futures_util::future::{select, Either}; | 14 | use futures_util::future::{select, Either}; |
| 15 | 15 | ||
| 16 | use crate::dma::ChannelAndRequest; | 16 | use crate::dma::ChannelAndRequest; |
| 17 | use crate::gpio::{AFType, AnyPin, SealedPin}; | 17 | use crate::gpio::{AFType, AnyPin, SealedPin as _}; |
| 18 | use crate::interrupt::typelevel::Interrupt as _; | 18 | use crate::interrupt::typelevel::Interrupt as _; |
| 19 | use crate::interrupt::{self, Interrupt, InterruptExt}; | 19 | use crate::interrupt::{self, Interrupt, InterruptExt}; |
| 20 | use crate::mode::{Async, Blocking, Mode}; | 20 | use 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))] |
| 29 | use crate::pac::usart::Usart as Regs; | 29 | use crate::pac::usart::Usart as Regs; |
| 30 | use crate::pac::usart::{regs, vals}; | 30 | use crate::pac::usart::{regs, vals}; |
| 31 | use crate::rcc::{ClockEnableBit, SealedRccPeripheral}; | 31 | use crate::rcc::{RccInfo, SealedRccPeripheral}; |
| 32 | use crate::time::Hertz; | 32 | use crate::time::Hertz; |
| 33 | use crate::Peripheral; | 33 | use 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 | ||
| 1719 | struct Info { | 1734 | struct 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}; | |||
| 4 | use core::task::Poll; | 4 | use core::task::Poll; |
| 5 | 5 | ||
| 6 | use embassy_embedded_hal::SetConfig; | 6 | use embassy_embedded_hal::SetConfig; |
| 7 | use embassy_hal_internal::PeripheralRef; | ||
| 7 | use futures_util::future::{select, Either}; | 8 | use futures_util::future::{select, Either}; |
| 8 | 9 | ||
| 9 | use super::{clear_interrupt_flags, rdr, reconfigure, sr, Config, ConfigError, Error, Info, State, UartRx}; | 10 | use super::{clear_interrupt_flags, rdr, reconfigure, sr, Config, ConfigError, Error, Info, State, UartRx}; |
| 10 | use crate::dma::ReadableRingBuffer; | 11 | use crate::dma::ReadableRingBuffer; |
| 12 | use crate::gpio::{AnyPin, SealedPin as _}; | ||
| 11 | use crate::mode::Async; | 13 | use crate::mode::Async; |
| 12 | use crate::time::Hertz; | 14 | use crate::time::Hertz; |
| 13 | use crate::usart::{Regs, Sr}; | 15 | use 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> { | |||
| 221 | impl Drop for RingBufferedUartRx<'_> { | 229 | impl 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; | |||
| 6 | pub use _version::*; | 6 | pub use _version::*; |
| 7 | 7 | ||
| 8 | use crate::interrupt::typelevel::Interrupt; | 8 | use crate::interrupt::typelevel::Interrupt; |
| 9 | use crate::rcc::SealedRccPeripheral; | 9 | use 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. |
| 12 | fn common_init<T: Instance>() { | 12 | fn 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::{ | |||
| 13 | use crate::gpio::AFType; | 13 | use crate::gpio::AFType; |
| 14 | use crate::interrupt; | 14 | use crate::interrupt; |
| 15 | use crate::interrupt::typelevel::Interrupt; | 15 | use crate::interrupt::typelevel::Interrupt; |
| 16 | use crate::rcc::{RccPeripheral, SealedRccPeripheral}; | 16 | use crate::rcc::{self, RccPeripheral}; |
| 17 | 17 | ||
| 18 | const MAX_EP_COUNT: usize = 9; | 18 | const 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 @@ | |||
| 1 | use std::env; | 1 | #[path = "./build_common.rs"] |
| 2 | mod common; | ||
| 2 | 3 | ||
| 3 | fn main() { | 4 | fn 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 | |||
| 9 | use std::collections::HashSet; | ||
| 10 | use std::env; | ||
| 11 | use std::ffi::OsString; | ||
| 12 | use 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)] | ||
| 17 | pub struct CfgSet { | ||
| 18 | enabled: HashSet<String>, | ||
| 19 | declared: HashSet<String>, | ||
| 20 | emit_declared: bool, | ||
| 21 | } | ||
| 22 | |||
| 23 | impl 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 | |||
| 72 | fn 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. | ||
| 84 | pub 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"] | |||
| 27 | std = ["tick-hz-1_000_000", "critical-section/std"] | 27 | std = ["tick-hz-1_000_000", "critical-section/std"] |
| 28 | wasm = ["dep:wasm-bindgen", "dep:js-sys", "dep:wasm-timer", "tick-hz-1_000_000"] | 28 | wasm = ["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. |
| 32 | defmt-timestamp-uptime = ["defmt"] | 34 | defmt-timestamp-uptime = ["defmt"] |
| 35 | defmt-timestamp-uptime-s = ["defmt"] | ||
| 36 | defmt-timestamp-uptime-ms = ["defmt"] | ||
| 37 | defmt-timestamp-uptime-us = ["defmt"] | ||
| 38 | defmt-timestamp-uptime-ts = ["defmt"] | ||
| 39 | defmt-timestamp-uptime-tms = ["defmt"] | ||
| 40 | defmt-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. |
| 35 | mock-driver = ["tick-hz-1_000_000"] | 43 | mock-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); | |||
| 46 | pub(crate) const GCD_1M: u64 = gcd(TICK_HZ, 1_000_000); | 46 | pub(crate) const GCD_1M: u64 = gcd(TICK_HZ, 1_000_000); |
| 47 | pub(crate) const GCD_1G: u64 = gcd(TICK_HZ, 1_000_000_000); | 47 | pub(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")] |
| 50 | defmt::timestamp! {"{=u64}", Instant::now().as_secs() } | ||
| 51 | |||
| 52 | #[cfg(feature = "defmt-timestamp-uptime-ms")] | ||
| 53 | defmt::timestamp! {"{=u64:ms}", Instant::now().as_millis() } | ||
| 54 | |||
| 55 | #[cfg(any(feature = "defmt-timestamp-uptime", feature = "defmt-timestamp-uptime-us"))] | ||
| 50 | defmt::timestamp! {"{=u64:us}", Instant::now().as_micros() } | 56 | defmt::timestamp! {"{=u64:us}", Instant::now().as_micros() } |
| 57 | |||
| 58 | #[cfg(feature = "defmt-timestamp-uptime-ts")] | ||
| 59 | defmt::timestamp! {"{=u64:ts}", Instant::now().as_secs() } | ||
| 60 | |||
| 61 | #[cfg(feature = "defmt-timestamp-uptime-tms")] | ||
| 62 | defmt::timestamp! {"{=u64:tms}", Instant::now().as_millis() } | ||
| 63 | |||
| 64 | #[cfg(feature = "defmt-timestamp-uptime-tus")] | ||
| 65 | defmt::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 = [ | |||
| 26 | features = ["defmt", "cortex-m", "dfu"] | 26 | features = ["defmt", "cortex-m", "dfu"] |
| 27 | 27 | ||
| 28 | [dependencies] | 28 | [dependencies] |
| 29 | defmt = { version = "0.3.5", optional = true } | ||
| 30 | log = { version = "0.4.17", optional = true } | ||
| 31 | |||
| 29 | bitflags = "2.4.1" | 32 | bitflags = "2.4.1" |
| 30 | cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true } | 33 | cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true } |
| 31 | defmt = { version = "0.3.5", optional = true } | ||
| 32 | embassy-boot = { version = "0.2.0", path = "../embassy-boot" } | 34 | embassy-boot = { version = "0.2.0", path = "../embassy-boot" } |
| 33 | embassy-futures = { version = "0.1.1", path = "../embassy-futures" } | 35 | embassy-futures = { version = "0.1.1", path = "../embassy-futures" } |
| 34 | embassy-sync = { version = "0.6.0", path = "../embassy-sync" } | 36 | embassy-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" | |||
| 25 | ed25519-dalek = ["embassy-boot/ed25519-dalek"] | 25 | ed25519-dalek = ["embassy-boot/ed25519-dalek"] |
| 26 | ed25519-salty = ["embassy-boot/ed25519-salty"] | 26 | ed25519-salty = ["embassy-boot/ed25519-salty"] |
| 27 | skip-include = [] | 27 | skip-include = [] |
| 28 | defmt = [ | ||
| 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] |
| 24 | defmt = [ | 24 | defmt = [ |
| 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")] |
| 5 | use defmt_rtt::*; | 5 | use defmt_rtt::*; |
| 6 | use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; | 6 | use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; |
| 7 | use embassy_embedded_hal::adapter::BlockingAsync; | 7 | use 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")] |
| 5 | use defmt_rtt::*; | 5 | use defmt_rtt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::gpio::{Level, Output, Speed}; | 7 | use 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] |
| 25 | defmt = [ | 25 | defmt = [ |
| 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 | ||
| 4 | use core::cell::RefCell; | 4 | use core::cell::RefCell; |
| 5 | 5 | ||
| 6 | #[cfg(feature = "defmt-rtt")] | 6 | #[cfg(feature = "defmt")] |
| 7 | use defmt_rtt::*; | 7 | use defmt_rtt::*; |
| 8 | use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig}; | 8 | use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig}; |
| 9 | use embassy_executor::Spawner; | 9 | use 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")] |
| 5 | use defmt_rtt::*; | 5 | use defmt_rtt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::gpio::{Level, Output, Speed}; | 7 | use 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] |
| 25 | defmt = [ | 25 | defmt = [ |
| 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 | ||
| 4 | use core::cell::RefCell; | 4 | use core::cell::RefCell; |
| 5 | 5 | ||
| 6 | #[cfg(feature = "defmt-rtt")] | 6 | #[cfg(feature = "defmt")] |
| 7 | use defmt_rtt::*; | 7 | use defmt_rtt::*; |
| 8 | use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig}; | 8 | use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig}; |
| 9 | use embassy_executor::Spawner; | 9 | use 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")] |
| 5 | use defmt_rtt::*; | 5 | use defmt_rtt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::gpio::{Level, Output, Speed}; | 7 | use 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] |
| 24 | defmt = [ | 24 | defmt = [ |
| 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")] |
| 5 | use defmt_rtt::*; | 5 | use defmt_rtt::*; |
| 6 | use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; | 6 | use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; |
| 7 | use embassy_embedded_hal::adapter::BlockingAsync; | 7 | use 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")] |
| 5 | use defmt_rtt::*; | 5 | use defmt_rtt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::gpio::{Level, Output, Speed}; | 7 | use 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] |
| 24 | defmt = [ | 24 | defmt = [ |
| 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")] |
| 5 | use defmt_rtt::*; | 5 | use defmt_rtt::*; |
| 6 | use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; | 6 | use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; |
| 7 | use embassy_embedded_hal::adapter::BlockingAsync; | 7 | use 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")] |
| 5 | use defmt_rtt::*; | 5 | use defmt_rtt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::gpio::{Level, Output, Speed}; | 7 | use 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] |
| 24 | defmt = [ | 24 | defmt = [ |
| 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")] |
| 5 | use defmt_rtt::*; | 5 | use defmt_rtt::*; |
| 6 | use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; | 6 | use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; |
| 7 | use embassy_embedded_hal::adapter::BlockingAsync; | 7 | use 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")] |
| 5 | use defmt_rtt::*; | 5 | use defmt_rtt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::gpio::{Level, Output, Speed}; | 7 | use 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 | ||
| 4 | use core::cell::RefCell; | 4 | use core::cell::RefCell; |
| 5 | 5 | ||
| 6 | #[cfg(feature = "defmt-rtt")] | 6 | #[cfg(feature = "defmt")] |
| 7 | use defmt_rtt::*; | 7 | use defmt_rtt::*; |
| 8 | use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareState, FirmwareUpdaterConfig}; | 8 | use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareState, FirmwareUpdaterConfig}; |
| 9 | use embassy_executor::Spawner; | 9 | use 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] |
| 24 | defmt = [ | 24 | defmt = [ |
| 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")] |
| 5 | use defmt_rtt::*; | 5 | use defmt_rtt::*; |
| 6 | use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; | 6 | use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig}; |
| 7 | use embassy_embedded_hal::adapter::BlockingAsync; | 7 | use 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")] |
| 5 | use defmt_rtt::*; | 5 | use defmt_rtt::*; |
| 6 | use embassy_executor::Spawner; | 6 | use embassy_executor::Spawner; |
| 7 | use embassy_stm32::gpio::{Level, Output, Speed}; | 7 | use 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] |
| 20 | defmt = [ | 20 | defmt = [ |
| 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 | ] |
| 25 | softdevice = [ | 26 | softdevice = [ |
| 26 | "embassy-boot-nrf/softdevice", | 27 | "embassy-boot-nrf/softdevice", |
| 27 | ] | 28 | ] |
| 28 | debug = ["defmt-rtt", "defmt"] | ||
| 29 | 29 | ||
| 30 | [profile.dev] | 30 | [profile.dev] |
| 31 | debug = 2 | 31 | debug = 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] |
| 24 | defmt = [ | 24 | defmt = [ |
| 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 | ] |
| 29 | debug = ["defmt-rtt", "defmt"] | ||
| 30 | 30 | ||
| 31 | [profile.release] | 31 | [profile.release] |
| 32 | debug = true | 32 | debug = 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" | |||
| 22 | cfg-if = "1.0.0" | 22 | cfg-if = "1.0.0" |
| 23 | 23 | ||
| 24 | [features] | 24 | [features] |
| 25 | defmt = ["dep:defmt", "embassy-boot-stm32/defmt", "embassy-stm32/defmt"] | 25 | defmt = ["dep:defmt", "dep:defmt-rtt", "embassy-boot-stm32/defmt", "embassy-stm32/defmt"] |
| 26 | debug = ["defmt-rtt", "defmt"] | ||
| 27 | 26 | ||
| 28 | [profile.dev] | 27 | [profile.dev] |
| 29 | debug = 2 | 28 | debug = 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] |
| 22 | defmt = [ | 22 | defmt = [ |
| 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 | ] |
| 27 | debug = ["defmt-rtt", "defmt"] | ||
| 28 | 28 | ||
| 29 | [profile.dev] | 29 | [profile.dev] |
| 30 | debug = 2 | 30 | debug = 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] |
| 25 | defmt = [ | 25 | defmt = [ |
| 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 | ] |
| 32 | debug = ["defmt-rtt", "defmt"] | ||
| 33 | 33 | ||
| 34 | [profile.dev] | 34 | [profile.dev] |
| 35 | debug = 2 | 35 | debug = 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 | |||
| 7 | use core::sync::atomic::{AtomicU16, Ordering}; | ||
| 8 | |||
| 9 | use defmt::*; | ||
| 10 | use embassy_executor::Spawner; | ||
| 11 | use embassy_rp::adc::{self, Adc, Async, Config, InterruptHandler}; | ||
| 12 | use embassy_rp::bind_interrupts; | ||
| 13 | use embassy_rp::gpio::Pull; | ||
| 14 | use embassy_rp::peripherals::DMA_CH0; | ||
| 15 | use embassy_sync::blocking_mutex::raw::NoopRawMutex; | ||
| 16 | use embassy_sync::zerocopy_channel::{Channel, Receiver, Sender}; | ||
| 17 | use embassy_time::{Duration, Ticker, Timer}; | ||
| 18 | use static_cell::StaticCell; | ||
| 19 | use {defmt_rtt as _, panic_probe as _}; | ||
| 20 | |||
| 21 | type SampleBuffer = [u16; 512]; | ||
| 22 | |||
| 23 | bind_interrupts!(struct Irqs { | ||
| 24 | ADC_IRQ_FIFO => InterruptHandler; | ||
| 25 | }); | ||
| 26 | |||
| 27 | const BLOCK_SIZE: usize = 512; | ||
| 28 | const NUM_BLOCKS: usize = 2; | ||
| 29 | static MAX: AtomicU16 = AtomicU16::new(0); | ||
| 30 | |||
| 31 | struct AdcParts { | ||
| 32 | adc: Adc<'static, Async>, | ||
| 33 | pin: adc::Channel<'static>, | ||
| 34 | dma: DMA_CH0, | ||
| 35 | } | ||
| 36 | |||
| 37 | #[embassy_executor::main] | ||
| 38 | async 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] | ||
| 67 | async 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] | ||
| 81 | async 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 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::gpio::{Level, Output, Pull, Speed}; | ||
| 7 | use embassy_stm32::time::khz; | ||
| 8 | use embassy_stm32::timer::input_capture::{CapturePin, InputCapture}; | ||
| 9 | use embassy_stm32::timer::{self, Channel}; | ||
| 10 | use embassy_stm32::{bind_interrupts, peripherals}; | ||
| 11 | use embassy_time::Timer; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | ||
| 13 | |||
| 14 | /// Connect PA2 and PC13 with a 1k Ohm resistor | ||
| 15 | |||
| 16 | #[embassy_executor::task] | ||
| 17 | async 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 | |||
| 31 | bind_interrupts!(struct Irqs { | ||
| 32 | TIM2 => timer::CaptureCompareInterruptHandler<peripherals::TIM2>; | ||
| 33 | }); | ||
| 34 | |||
| 35 | #[embassy_executor::main] | ||
| 36 | async 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 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::gpio::{Level, Output, Pull, Speed}; | ||
| 7 | use embassy_stm32::time::khz; | ||
| 8 | use embassy_stm32::timer::pwm_input::PwmInput; | ||
| 9 | use embassy_stm32::{bind_interrupts, peripherals, timer}; | ||
| 10 | use embassy_time::Timer; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | /// Connect PA0 and PC13 with a 1k Ohm resistor | ||
| 14 | |||
| 15 | #[embassy_executor::task] | ||
| 16 | async 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 | |||
| 30 | bind_interrupts!(struct Irqs { | ||
| 31 | TIM2 => timer::CaptureCompareInterruptHandler<peripherals::TIM2>; | ||
| 32 | }); | ||
| 33 | |||
| 34 | #[embassy_executor::main] | ||
| 35 | async 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 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_stm32::gpio::{Level, Output, Pull, Speed}; | ||
| 7 | use embassy_stm32::time::khz; | ||
| 8 | use embassy_stm32::timer::pwm_input::PwmInput; | ||
| 9 | use embassy_stm32::{bind_interrupts, peripherals, timer}; | ||
| 10 | use embassy_time::Timer; | ||
| 11 | use {defmt_rtt as _, panic_probe as _}; | ||
| 12 | |||
| 13 | /// Connect PB2 and PA6 with a 1k Ohm resistor | ||
| 14 | |||
| 15 | #[embassy_executor::task] | ||
| 16 | async 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 | |||
| 30 | bind_interrupts!(struct Irqs { | ||
| 31 | TIM2 => timer::CaptureCompareInterruptHandler<peripherals::TIM2>; | ||
| 32 | }); | ||
| 33 | |||
| 34 | #[embassy_executor::main] | ||
| 35 | async 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] |
| 49 | async fn main(spawner: Spawner) { | 49 | async 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] |
| 30 | async fn main(_spawner: Spawner) { | 30 | async 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] |
| 27 | async fn main(_spawner: Spawner) { | 27 | async 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] |
| 78 | async fn main(_spawner: Spawner) { | 78 | async 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] |
| 25 | async fn main(_spawner: Spawner) { | 25 | async 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] |
| 27 | pub async fn send_can_message(tx: &'static mut CanTx<'static, CAN3>) { | 27 | pub 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] |
| 25 | async fn main(_spawner: Spawner) { | 25 | async 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] |
| 24 | async fn main(_spawner: Spawner) { | 24 | async 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] |
| 25 | async fn main(_spawner: Spawner) { | 25 | async 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] |
| 2 | channel = "nightly-2024-04-14" | 2 | channel = "nightly-2024-05-20" |
| 3 | components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] | 3 | components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] |
| 4 | targets = [ | 4 | targets = [ |
| 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] |
| 9 | stm32c031c6 = ["embassy-stm32/stm32c031c6", "cm0", "not-gpdma"] | 9 | stm32c031c6 = ["embassy-stm32/stm32c031c6", "cm0", "not-gpdma"] |
| 10 | stm32f103c8 = ["embassy-stm32/stm32f103c8", "not-gpdma"] | 10 | stm32f103c8 = ["embassy-stm32/stm32f103c8", "spi-v1", "not-gpdma"] |
| 11 | stm32f207zg = ["embassy-stm32/stm32f207zg", "chrono", "not-gpdma", "eth", "rng"] | 11 | stm32f207zg = ["embassy-stm32/stm32f207zg", "spi-v1", "chrono", "not-gpdma", "eth", "rng"] |
| 12 | stm32f303ze = ["embassy-stm32/stm32f303ze", "chrono", "not-gpdma"] | 12 | stm32f303ze = ["embassy-stm32/stm32f303ze", "chrono", "not-gpdma"] |
| 13 | stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng"] | 13 | stm32f429zi = ["embassy-stm32/stm32f429zi", "spi-v1", "chrono", "eth", "stop", "can", "not-gpdma", "dac", "rng"] |
| 14 | stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"] | 14 | stm32f446re = ["embassy-stm32/stm32f446re", "spi-v1", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"] |
| 15 | stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] | 15 | stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"] |
| 16 | stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac", "ucpd"] | 16 | stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac", "ucpd"] |
| 17 | stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan", "cordic"] | 17 | stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan", "cordic"] |
| 18 | stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "fdcan", "hash", "cordic", "stop"] | 18 | stm32h563zi = ["embassy-stm32/stm32h563zi", "spi-v345", "chrono", "eth", "rng", "fdcan", "hash", "cordic", "stop"] |
| 19 | stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"] | 19 | stm32h753zi = ["embassy-stm32/stm32h753zi", "spi-v345", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"] |
| 20 | stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash", "cryp"] | 20 | stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "spi-v345", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash", "cryp"] |
| 21 | stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"] | 21 | stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "spi-v345", "not-gpdma", "rng", "fdcan"] |
| 22 | stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"] | 22 | stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"] |
| 23 | stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"] | 23 | stm32l152re = ["embassy-stm32/stm32l152re", "spi-v1", "chrono", "not-gpdma"] |
| 24 | stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"] | 24 | stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"] |
| 25 | stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma", "rng", "hash"] | 25 | stm32l4a6zg = ["embassy-stm32/stm32l4a6zg", "chrono", "not-gpdma", "rng", "hash"] |
| 26 | stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng"] | 26 | stm32l4r5zi = ["embassy-stm32/stm32l4r5zi", "chrono", "not-gpdma", "rng"] |
| 27 | stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng", "hash"] | 27 | stm32l552ze = ["embassy-stm32/stm32l552ze", "not-gpdma", "rng", "hash"] |
| 28 | stm32u585ai = ["embassy-stm32/stm32u585ai", "chrono", "rng", "hash", "cordic"] | 28 | stm32u585ai = ["embassy-stm32/stm32u585ai", "spi-v345", "chrono", "rng", "hash", "cordic"] |
| 29 | stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "chrono", "rng", "hash"] # FIXME: cordic test cause it crash | 29 | stm32u5a5zj = ["embassy-stm32/stm32u5a5zj", "spi-v345", "chrono", "rng", "hash"] # FIXME: cordic test cause it crash |
| 30 | stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng"] | 30 | stm32wb55rg = ["embassy-stm32/stm32wb55rg", "chrono", "not-gpdma", "ble", "mac" , "rng"] |
| 31 | stm32wba52cg = ["embassy-stm32/stm32wba52cg", "chrono", "rng", "hash"] | 31 | stm32wba52cg = ["embassy-stm32/stm32wba52cg", "spi-v345", "chrono", "rng", "hash"] |
| 32 | stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"] | 32 | stm32wl55jc = ["embassy-stm32/stm32wl55jc-cm4", "not-gpdma", "rng", "chrono"] |
| 33 | stm32f091rc = ["embassy-stm32/stm32f091rc", "cm0", "not-gpdma", "chrono"] | 33 | stm32f091rc = ["embassy-stm32/stm32f091rc", "cm0", "not-gpdma", "chrono"] |
| 34 | stm32h503rb = ["embassy-stm32/stm32h503rb", "rng", "stop"] | 34 | stm32h503rb = ["embassy-stm32/stm32h503rb", "spi-v345", "rng", "stop"] |
| 35 | stm32h7s3l8 = ["embassy-stm32/stm32h7s3l8", "rng", "cordic", "hash"] # TODO: fdcan crashes, cryp dma hangs. | 35 | stm32h7s3l8 = ["embassy-stm32/stm32h7s3l8", "spi-v345", "rng", "cordic", "hash"] # TODO: fdcan crashes, cryp dma hangs. |
| 36 | stm32u083rc = ["embassy-stm32/stm32u083rc", "cm0", "rng", "chrono"] | 36 | stm32u083rc = ["embassy-stm32/stm32u083rc", "cm0", "rng", "chrono"] |
| 37 | 37 | ||
| 38 | spi-v1 = [] | ||
| 39 | spi-v345 = [] | ||
| 38 | cryp = [] | 40 | cryp = [] |
| 39 | hash = [] | 41 | hash = [] |
| 40 | eth = ["embassy-executor/task-arena-size-16384"] | 42 | eth = ["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::*; | |||
| 9 | use embassy_executor::Spawner; | 9 | use embassy_executor::Spawner; |
| 10 | use embassy_stm32::bind_interrupts; | 10 | use embassy_stm32::bind_interrupts; |
| 11 | use embassy_stm32::can::filter::Mask32; | 11 | use embassy_stm32::can::filter::Mask32; |
| 12 | use embassy_stm32::can::{ | 12 | use embassy_stm32::can::{Fifo, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; |
| 13 | Can, Fifo, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler, | ||
| 14 | }; | ||
| 15 | use embassy_stm32::gpio::{Input, Pull}; | 13 | use embassy_stm32::gpio::{Input, Pull}; |
| 16 | use embassy_stm32::peripherals::CAN1; | 14 | use embassy_stm32::peripherals::CAN1; |
| 17 | use embassy_time::Duration; | 15 | use 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 | ||
| 11 | pub async fn run_can_tests<'d, T: can::Instance>(can: &mut can::Can<'d, T>, options: &TestOptions) { | 11 | pub 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 | ||
| 82 | pub async fn run_split_can_tests<'d, T: can::Instance>( | 83 | pub 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"))] |
| 92 | fn options() -> (Config, TestOptions) { | 92 | fn 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; | |||
| 6 | use common::*; | 6 | use common::*; |
| 7 | use defmt::assert_eq; | 7 | use defmt::assert_eq; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 9 | use embassy_stm32::spi::{self, Spi}; | 10 | use embassy_stm32::spi::{self, Spi}; |
| 10 | use embassy_stm32::time::Hertz; | 11 | use 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; | |||
| 6 | use common::*; | 6 | use common::*; |
| 7 | use defmt::assert_eq; | 7 | use defmt::assert_eq; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 9 | use embassy_stm32::spi::{self, Spi}; | 10 | use embassy_stm32::spi::{self, Spi}; |
| 10 | use embassy_stm32::time::Hertz; | 11 | use 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 | } |
