mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-25 00:02:28 +00:00
Merge branch 'main' of https://github.com/embassy-rs/embassy into fix_main
This commit is contained in:
commit
319e18b399
@ -299,7 +299,7 @@ You can add a section to your `Cargo.toml` file like this, you'll need to patch
|
||||
|
||||
Using `patch` will replace all direct AND indirect dependencies.
|
||||
|
||||
See the link:https://embassy.dev/book/dev/new_project.html#_cargo_toml[new project docs] for more details on this approach.
|
||||
See the link:https://embassy.dev/book/#_starting_a_new_project[new project docs] for more details on this approach.
|
||||
|
||||
[source,toml]
|
||||
----
|
||||
|
@ -131,7 +131,7 @@ If you’re using a raspberry pi pico-w, make sure you’re running `+cargo run
|
||||
|
||||
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].
|
||||
|
||||
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].
|
||||
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].
|
||||
|
||||
== What's next?
|
||||
|
||||
|
@ -22,6 +22,7 @@ target = "thumbv7em-none-eabi"
|
||||
|
||||
[dependencies]
|
||||
defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.17", optional = true }
|
||||
|
||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
||||
embassy-nrf = { version = "0.1.0", path = "../embassy-nrf", default-features = false }
|
||||
|
@ -21,7 +21,6 @@ target = "thumbv6m-none-eabi"
|
||||
|
||||
[dependencies]
|
||||
defmt = { version = "0.3", optional = true }
|
||||
defmt-rtt = { version = "0.4", optional = true }
|
||||
log = { version = "0.4", optional = true }
|
||||
|
||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
||||
@ -46,7 +45,6 @@ log = [
|
||||
"embassy-boot/log",
|
||||
"embassy-rp/log",
|
||||
]
|
||||
debug = ["defmt-rtt"]
|
||||
|
||||
[profile.dev]
|
||||
debug = 2
|
||||
|
@ -5,4 +5,5 @@ fn main() {
|
||||
if target.starts_with("thumbv6m-") {
|
||||
println!("cargo:rustc-cfg=armv6m");
|
||||
}
|
||||
println!("cargo:rustc-check-cfg=cfg(armv6m)");
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ target = "thumbv7em-none-eabi"
|
||||
|
||||
[dependencies]
|
||||
defmt = { version = "0.3", optional = true }
|
||||
defmt-rtt = { version = "0.4", optional = true }
|
||||
log = { version = "0.4", optional = true }
|
||||
|
||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
||||
@ -37,7 +36,6 @@ cfg-if = "1.0.0"
|
||||
[features]
|
||||
defmt = ["dep:defmt", "embassy-boot/defmt", "embassy-stm32/defmt"]
|
||||
log = ["dep:log", "embassy-boot/log", "embassy-stm32/log"]
|
||||
debug = ["defmt-rtt"]
|
||||
|
||||
[profile.dev]
|
||||
debug = 2
|
||||
|
@ -5,4 +5,5 @@ fn main() {
|
||||
if target.starts_with("thumbv6m-") {
|
||||
println!("cargo:rustc-cfg=armv6m");
|
||||
}
|
||||
println!("cargo:rustc-check-cfg=cfg(armv6m)");
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ For any partition, the following preconditions are required:
|
||||
|
||||
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.
|
||||
|
||||
For more details on the bootloader, see [the documentation](https://embassy.dev/book/dev/bootloader.html).
|
||||
For more details on the bootloader, see [the documentation](https://embassy.dev/book/#_bootloader).
|
||||
|
||||
## Hardware support
|
||||
|
||||
|
@ -3,6 +3,9 @@ use std::fmt::Write;
|
||||
use std::path::PathBuf;
|
||||
use std::{env, fs};
|
||||
|
||||
#[path = "./build_common.rs"]
|
||||
mod common;
|
||||
|
||||
static CONFIGS: &[(&str, usize)] = &[
|
||||
// BEGIN AUTOGENERATED CONFIG FEATURES
|
||||
// Generated by gen_config.py. DO NOT EDIT.
|
||||
@ -91,30 +94,6 @@ fn main() {
|
||||
let out_file = out_dir.join("config.rs").to_string_lossy().to_string();
|
||||
fs::write(out_file, data).unwrap();
|
||||
|
||||
// cortex-m targets
|
||||
let target = env::var("TARGET").unwrap();
|
||||
|
||||
if target.starts_with("thumbv6m-") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv6m");
|
||||
} else if target.starts_with("thumbv7m-") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv7m");
|
||||
} else if target.starts_with("thumbv7em-") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv7m");
|
||||
println!("cargo:rustc-cfg=armv7em"); // (not currently used)
|
||||
} else if target.starts_with("thumbv8m.base") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv8m");
|
||||
println!("cargo:rustc-cfg=armv8m_base");
|
||||
} else if target.starts_with("thumbv8m.main") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv8m");
|
||||
println!("cargo:rustc-cfg=armv8m_main");
|
||||
}
|
||||
|
||||
if target.ends_with("-eabihf") {
|
||||
println!("cargo:rustc-cfg=has_fpu");
|
||||
}
|
||||
let mut rustc_cfgs = common::CfgSet::new();
|
||||
common::set_target_cfgs(&mut rustc_cfgs);
|
||||
}
|
||||
|
109
embassy-executor/build_common.rs
Normal file
109
embassy-executor/build_common.rs
Normal file
@ -0,0 +1,109 @@
|
||||
// NOTE: this file is copy-pasted between several Embassy crates, because there is no
|
||||
// straightforward way to share this code:
|
||||
// - it cannot be placed into the root of the repo and linked from each build.rs using `#[path =
|
||||
// "../build_common.rs"]`, because `cargo publish` requires that all files published with a crate
|
||||
// reside in the crate's directory,
|
||||
// - it cannot be symlinked from `embassy-xxx/build_common.rs` to `../build_common.rs`, because
|
||||
// symlinks don't work on Windows.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::process::Command;
|
||||
|
||||
/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring
|
||||
/// them (`cargo:rust-check-cfg=cfg(X)`).
|
||||
#[derive(Debug)]
|
||||
pub struct CfgSet {
|
||||
enabled: HashSet<String>,
|
||||
declared: HashSet<String>,
|
||||
emit_declared: bool,
|
||||
}
|
||||
|
||||
impl CfgSet {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
enabled: HashSet::new(),
|
||||
declared: HashSet::new(),
|
||||
emit_declared: is_rustc_nightly(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable a config, which can then be used in `#[cfg(...)]` for conditional compilation.
|
||||
///
|
||||
/// All configs that can potentially be enabled should be unconditionally declared using
|
||||
/// [`Self::declare()`].
|
||||
pub fn enable(&mut self, cfg: impl AsRef<str>) {
|
||||
if self.enabled.insert(cfg.as_ref().to_owned()) {
|
||||
println!("cargo:rustc-cfg={}", cfg.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enable_all(&mut self, cfgs: &[impl AsRef<str>]) {
|
||||
for cfg in cfgs.iter() {
|
||||
self.enable(cfg.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
/// Declare a valid config for conditional compilation, without enabling it.
|
||||
///
|
||||
/// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid.
|
||||
pub fn declare(&mut self, cfg: impl AsRef<str>) {
|
||||
if self.declared.insert(cfg.as_ref().to_owned()) && self.emit_declared {
|
||||
println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn declare_all(&mut self, cfgs: &[impl AsRef<str>]) {
|
||||
for cfg in cfgs.iter() {
|
||||
self.declare(cfg.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set(&mut self, cfg: impl Into<String>, enable: bool) {
|
||||
let cfg = cfg.into();
|
||||
if enable {
|
||||
self.enable(cfg.clone());
|
||||
}
|
||||
self.declare(cfg);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_rustc_nightly() -> bool {
|
||||
let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
|
||||
|
||||
let output = Command::new(rustc)
|
||||
.arg("--version")
|
||||
.output()
|
||||
.expect("failed to run `rustc --version`");
|
||||
|
||||
String::from_utf8_lossy(&output.stdout).contains("nightly")
|
||||
}
|
||||
|
||||
/// Sets configs that describe the target platform.
|
||||
pub fn set_target_cfgs(cfgs: &mut CfgSet) {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
|
||||
if target.starts_with("thumbv6m-") {
|
||||
cfgs.enable_all(&["cortex_m", "armv6m"]);
|
||||
} else if target.starts_with("thumbv7m-") {
|
||||
cfgs.enable_all(&["cortex_m", "armv7m"]);
|
||||
} else if target.starts_with("thumbv7em-") {
|
||||
cfgs.enable_all(&["cortex_m", "armv7m", "armv7em"]);
|
||||
} else if target.starts_with("thumbv8m.base") {
|
||||
cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_base"]);
|
||||
} else if target.starts_with("thumbv8m.main") {
|
||||
cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_main"]);
|
||||
}
|
||||
cfgs.declare_all(&[
|
||||
"cortex_m",
|
||||
"armv6m",
|
||||
"armv7m",
|
||||
"armv7em",
|
||||
"armv8m",
|
||||
"armv8m_base",
|
||||
"armv8m_main",
|
||||
]);
|
||||
|
||||
cfgs.set("has_fpu", target.ends_with("-eabihf"));
|
||||
}
|
@ -1,29 +1,7 @@
|
||||
use std::env;
|
||||
#[path = "./build_common.rs"]
|
||||
mod common;
|
||||
|
||||
fn main() {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
|
||||
if target.starts_with("thumbv6m-") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv6m");
|
||||
} else if target.starts_with("thumbv7m-") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv7m");
|
||||
} else if target.starts_with("thumbv7em-") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv7m");
|
||||
println!("cargo:rustc-cfg=armv7em"); // (not currently used)
|
||||
} else if target.starts_with("thumbv8m.base") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv8m");
|
||||
println!("cargo:rustc-cfg=armv8m_base");
|
||||
} else if target.starts_with("thumbv8m.main") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv8m");
|
||||
println!("cargo:rustc-cfg=armv8m_main");
|
||||
}
|
||||
|
||||
if target.ends_with("-eabihf") {
|
||||
println!("cargo:rustc-cfg=has_fpu");
|
||||
}
|
||||
let mut cfgs = common::CfgSet::new();
|
||||
common::set_target_cfgs(&mut cfgs);
|
||||
}
|
||||
|
109
embassy-hal-internal/build_common.rs
Normal file
109
embassy-hal-internal/build_common.rs
Normal file
@ -0,0 +1,109 @@
|
||||
// NOTE: this file is copy-pasted between several Embassy crates, because there is no
|
||||
// straightforward way to share this code:
|
||||
// - it cannot be placed into the root of the repo and linked from each build.rs using `#[path =
|
||||
// "../build_common.rs"]`, because `cargo publish` requires that all files published with a crate
|
||||
// reside in the crate's directory,
|
||||
// - it cannot be symlinked from `embassy-xxx/build_common.rs` to `../build_common.rs`, because
|
||||
// symlinks don't work on Windows.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::process::Command;
|
||||
|
||||
/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring
|
||||
/// them (`cargo:rust-check-cfg=cfg(X)`).
|
||||
#[derive(Debug)]
|
||||
pub struct CfgSet {
|
||||
enabled: HashSet<String>,
|
||||
declared: HashSet<String>,
|
||||
emit_declared: bool,
|
||||
}
|
||||
|
||||
impl CfgSet {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
enabled: HashSet::new(),
|
||||
declared: HashSet::new(),
|
||||
emit_declared: is_rustc_nightly(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable a config, which can then be used in `#[cfg(...)]` for conditional compilation.
|
||||
///
|
||||
/// All configs that can potentially be enabled should be unconditionally declared using
|
||||
/// [`Self::declare()`].
|
||||
pub fn enable(&mut self, cfg: impl AsRef<str>) {
|
||||
if self.enabled.insert(cfg.as_ref().to_owned()) {
|
||||
println!("cargo:rustc-cfg={}", cfg.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enable_all(&mut self, cfgs: &[impl AsRef<str>]) {
|
||||
for cfg in cfgs.iter() {
|
||||
self.enable(cfg.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
/// Declare a valid config for conditional compilation, without enabling it.
|
||||
///
|
||||
/// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid.
|
||||
pub fn declare(&mut self, cfg: impl AsRef<str>) {
|
||||
if self.declared.insert(cfg.as_ref().to_owned()) && self.emit_declared {
|
||||
println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn declare_all(&mut self, cfgs: &[impl AsRef<str>]) {
|
||||
for cfg in cfgs.iter() {
|
||||
self.declare(cfg.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set(&mut self, cfg: impl Into<String>, enable: bool) {
|
||||
let cfg = cfg.into();
|
||||
if enable {
|
||||
self.enable(cfg.clone());
|
||||
}
|
||||
self.declare(cfg);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_rustc_nightly() -> bool {
|
||||
let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
|
||||
|
||||
let output = Command::new(rustc)
|
||||
.arg("--version")
|
||||
.output()
|
||||
.expect("failed to run `rustc --version`");
|
||||
|
||||
String::from_utf8_lossy(&output.stdout).contains("nightly")
|
||||
}
|
||||
|
||||
/// Sets configs that describe the target platform.
|
||||
pub fn set_target_cfgs(cfgs: &mut CfgSet) {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
|
||||
if target.starts_with("thumbv6m-") {
|
||||
cfgs.enable_all(&["cortex_m", "armv6m"]);
|
||||
} else if target.starts_with("thumbv7m-") {
|
||||
cfgs.enable_all(&["cortex_m", "armv7m"]);
|
||||
} else if target.starts_with("thumbv7em-") {
|
||||
cfgs.enable_all(&["cortex_m", "armv7m", "armv7em"]);
|
||||
} else if target.starts_with("thumbv8m.base") {
|
||||
cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_base"]);
|
||||
} else if target.starts_with("thumbv8m.main") {
|
||||
cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_main"]);
|
||||
}
|
||||
cfgs.declare_all(&[
|
||||
"cortex_m",
|
||||
"armv6m",
|
||||
"armv7m",
|
||||
"armv7em",
|
||||
"armv8m",
|
||||
"armv8m_base",
|
||||
"armv8m_main",
|
||||
]);
|
||||
|
||||
cfgs.set("has_fpu", target.ends_with("-eabihf"));
|
||||
}
|
@ -29,7 +29,6 @@ critical-section = { version = "1.1.2", features = ["std"] }
|
||||
futures-test = "0.3.28"
|
||||
|
||||
[features]
|
||||
default = [ ]
|
||||
defmt = [ "dep:defmt", "embedded-hal-1/defmt-03" ]
|
||||
log = ["dep:log"]
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
#![cfg_attr(not(test), no_std)]
|
||||
#![deny(clippy::pedantic)]
|
||||
#![allow(async_fn_in_trait)]
|
||||
#![cfg_attr(not(any(test, feature = "std")), no_std)]
|
||||
#![allow(clippy::module_name_repetitions)]
|
||||
#![allow(clippy::missing_errors_doc)]
|
||||
#![allow(clippy::missing_panics_doc)]
|
||||
|
@ -166,7 +166,7 @@ impl<'d, T: Instance> Qspi<'d, T> {
|
||||
$pin.conf().write(|w| {
|
||||
w.dir().output();
|
||||
w.drive().h0h1();
|
||||
#[cfg(feature = "_nrf5340-s")]
|
||||
#[cfg(all(feature = "_nrf5340", feature = "_s"))]
|
||||
w.mcusel().peripheral();
|
||||
w
|
||||
});
|
||||
|
@ -28,6 +28,8 @@ embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" }
|
||||
embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver", optional=true }
|
||||
|
||||
defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.17", optional = true }
|
||||
|
||||
cortex-m = "0.7.6"
|
||||
heapless = "0.8"
|
||||
aligned = "0.4.1"
|
||||
|
@ -72,7 +72,7 @@ rand_core = "0.6.3"
|
||||
sdio-host = "0.5.0"
|
||||
critical-section = "1.1"
|
||||
#stm32-metapac = { version = "15" }
|
||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-34c0188a682b32c32ff147d377e0629b1ebe8318" }
|
||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-59b1f65bd109c3ef35782e6c44062208d0ef3d0e" }
|
||||
|
||||
vcell = "0.1.3"
|
||||
nb = "1.0.0"
|
||||
@ -97,7 +97,7 @@ proc-macro2 = "1.0.36"
|
||||
quote = "1.0.15"
|
||||
|
||||
#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
|
||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-34c0188a682b32c32ff147d377e0629b1ebe8318", default-features = false, features = ["metadata"]}
|
||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-59b1f65bd109c3ef35782e6c44062208d0ef3d0e", default-features = false, features = ["metadata"] }
|
||||
|
||||
[features]
|
||||
default = ["rt"]
|
||||
|
@ -9,35 +9,16 @@ use proc_macro2::{Ident, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
use stm32_metapac::metadata::ir::BitOffset;
|
||||
use stm32_metapac::metadata::{
|
||||
MemoryRegionKind, PeripheralRccKernelClock, PeripheralRccRegister, PeripheralRegisters, StopMode, METADATA,
|
||||
MemoryRegionKind, PeripheralRccKernelClock, PeripheralRccRegister, PeripheralRegisters, StopMode, ALL_CHIPS,
|
||||
ALL_PERIPHERAL_VERSIONS, METADATA,
|
||||
};
|
||||
|
||||
#[path = "./build_common.rs"]
|
||||
mod common;
|
||||
|
||||
fn main() {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
|
||||
if target.starts_with("thumbv6m-") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv6m");
|
||||
} else if target.starts_with("thumbv7m-") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv7m");
|
||||
} else if target.starts_with("thumbv7em-") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv7m");
|
||||
println!("cargo:rustc-cfg=armv7em"); // (not currently used)
|
||||
} else if target.starts_with("thumbv8m.base") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv8m");
|
||||
println!("cargo:rustc-cfg=armv8m_base");
|
||||
} else if target.starts_with("thumbv8m.main") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv8m");
|
||||
println!("cargo:rustc-cfg=armv8m_main");
|
||||
}
|
||||
|
||||
if target.ends_with("-eabihf") {
|
||||
println!("cargo:rustc-cfg=has_fpu");
|
||||
}
|
||||
let mut cfgs = common::CfgSet::new();
|
||||
common::set_target_cfgs(&mut cfgs);
|
||||
|
||||
let chip_name = match env::vars()
|
||||
.map(|(a, _)| a)
|
||||
@ -56,8 +37,15 @@ fn main() {
|
||||
|
||||
for p in METADATA.peripherals {
|
||||
if let Some(r) = &p.registers {
|
||||
println!("cargo:rustc-cfg={}", r.kind);
|
||||
println!("cargo:rustc-cfg={}_{}", r.kind, r.version);
|
||||
cfgs.enable(r.kind);
|
||||
cfgs.enable(format!("{}_{}", r.kind, r.version));
|
||||
}
|
||||
}
|
||||
|
||||
for &(kind, versions) in ALL_PERIPHERAL_VERSIONS.iter() {
|
||||
cfgs.declare(kind);
|
||||
for &version in versions.iter() {
|
||||
cfgs.declare(format!("{}_{}", kind, version));
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,7 +55,13 @@ fn main() {
|
||||
let mut singletons: Vec<String> = Vec::new();
|
||||
for p in METADATA.peripherals {
|
||||
if let Some(r) = &p.registers {
|
||||
println!("cargo:rustc-cfg=peri_{}", p.name.to_ascii_lowercase());
|
||||
if r.kind == "adccommon" || r.kind == "sai" || r.kind == "ucpd" {
|
||||
// TODO: should we emit this for all peripherals? if so, we will need a list of all
|
||||
// possible peripherals across all chips, so that we can declare the configs
|
||||
// (replacing the hard-coded list of `peri_*` cfgs below)
|
||||
cfgs.enable(format!("peri_{}", p.name.to_ascii_lowercase()));
|
||||
}
|
||||
|
||||
match r.kind {
|
||||
// Generate singletons per pin, not per port
|
||||
"gpio" => {
|
||||
@ -87,7 +81,7 @@ fn main() {
|
||||
if pin.signal.starts_with("MCO") {
|
||||
let name = pin.signal.replace('_', "").to_string();
|
||||
if !singletons.contains(&name) {
|
||||
println!("cargo:rustc-cfg={}", name.to_ascii_lowercase());
|
||||
cfgs.enable(name.to_ascii_lowercase());
|
||||
singletons.push(name);
|
||||
}
|
||||
}
|
||||
@ -106,6 +100,20 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
cfgs.declare_all(&[
|
||||
"peri_adc1_common",
|
||||
"peri_adc3_common",
|
||||
"peri_adc12_common",
|
||||
"peri_adc34_common",
|
||||
"peri_sai1",
|
||||
"peri_sai2",
|
||||
"peri_sai3",
|
||||
"peri_sai4",
|
||||
"peri_ucpd1",
|
||||
"peri_ucpd2",
|
||||
]);
|
||||
cfgs.declare_all(&["mco", "mco1", "mco2"]);
|
||||
|
||||
// One singleton per EXTI line
|
||||
for pin_num in 0..16 {
|
||||
singletons.push(format!("EXTI{}", pin_num));
|
||||
@ -221,7 +229,13 @@ fn main() {
|
||||
};
|
||||
|
||||
if !time_driver_singleton.is_empty() {
|
||||
println!("cargo:rustc-cfg=time_driver_{}", time_driver_singleton.to_lowercase());
|
||||
cfgs.enable(format!("time_driver_{}", time_driver_singleton.to_lowercase()));
|
||||
}
|
||||
for tim in [
|
||||
"tim1", "tim2", "tim3", "tim4", "tim5", "tim8", "tim9", "tim12", "tim15", "tim20", "tim21", "tim22", "tim23",
|
||||
"tim24",
|
||||
] {
|
||||
cfgs.declare(format!("time_driver_{}", tim));
|
||||
}
|
||||
|
||||
// ========
|
||||
@ -367,9 +381,6 @@ fn main() {
|
||||
.filter_map(|p| p.registers.as_ref())
|
||||
.find(|r| r.kind == "rcc")
|
||||
.unwrap();
|
||||
for b in rcc_registers.ir.blocks {
|
||||
eprintln!("{}", b.name);
|
||||
}
|
||||
let rcc_block = rcc_registers.ir.blocks.iter().find(|b| b.name == "Rcc").unwrap();
|
||||
|
||||
// ========
|
||||
@ -388,7 +399,6 @@ fn main() {
|
||||
rcc_registers: &'a PeripheralRegisters,
|
||||
chained_muxes: HashMap<&'a str, &'a PeripheralRccRegister>,
|
||||
|
||||
refcount_statics: BTreeSet<Ident>,
|
||||
clock_names: BTreeSet<String>,
|
||||
muxes: BTreeSet<(Ident, Ident, Ident)>,
|
||||
}
|
||||
@ -397,7 +407,6 @@ fn main() {
|
||||
rcc_registers,
|
||||
chained_muxes: HashMap::new(),
|
||||
|
||||
refcount_statics: BTreeSet::new(),
|
||||
clock_names: BTreeSet::new(),
|
||||
muxes: BTreeSet::new(),
|
||||
};
|
||||
@ -516,80 +525,64 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let mut refcount_idxs = HashMap::new();
|
||||
|
||||
for p in METADATA.peripherals {
|
||||
if !singletons.contains(&p.name.to_string()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(rcc) = &p.rcc {
|
||||
let en = rcc.enable.as_ref().unwrap();
|
||||
|
||||
let (start_rst, end_rst) = match &rcc.reset {
|
||||
Some(rst) => {
|
||||
let rst_reg = format_ident!("{}", rst.register.to_ascii_lowercase());
|
||||
let set_rst_field = format_ident!("set_{}", rst.field.to_ascii_lowercase());
|
||||
(
|
||||
quote! {
|
||||
crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(true));
|
||||
},
|
||||
quote! {
|
||||
crate::pac::RCC.#rst_reg().modify(|w| w.#set_rst_field(false));
|
||||
},
|
||||
)
|
||||
}
|
||||
None => (TokenStream::new(), TokenStream::new()),
|
||||
};
|
||||
|
||||
let rst_reg = rcc.reset.as_ref();
|
||||
let en_reg = rcc.enable.as_ref().unwrap();
|
||||
let pname = format_ident!("{}", p.name);
|
||||
let en_reg = format_ident!("{}", en.register.to_ascii_lowercase());
|
||||
let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase());
|
||||
let en_reg_offs = rcc_block
|
||||
.items
|
||||
.iter()
|
||||
.find(|i| i.name.eq_ignore_ascii_case(en.register))
|
||||
.unwrap()
|
||||
.byte_offset;
|
||||
let en_reg_offs: u8 = (en_reg_offs / 4).try_into().unwrap();
|
||||
|
||||
let en_bit_offs = &rcc_registers
|
||||
.ir
|
||||
.fieldsets
|
||||
.iter()
|
||||
.find(|i| i.name.eq_ignore_ascii_case(en.register))
|
||||
.unwrap()
|
||||
.fields
|
||||
.iter()
|
||||
.find(|i| i.name.eq_ignore_ascii_case(en.field))
|
||||
.unwrap()
|
||||
.bit_offset;
|
||||
let BitOffset::Regular(en_bit_offs) = en_bit_offs else {
|
||||
panic!("cursed bit offset")
|
||||
let get_offset_and_bit = |reg: &PeripheralRccRegister| -> TokenStream {
|
||||
let reg_offset = rcc_block
|
||||
.items
|
||||
.iter()
|
||||
.find(|i| i.name.eq_ignore_ascii_case(reg.register))
|
||||
.unwrap()
|
||||
.byte_offset;
|
||||
let reg_offset: u8 = (reg_offset / 4).try_into().unwrap();
|
||||
|
||||
let bit_offset = &rcc_registers
|
||||
.ir
|
||||
.fieldsets
|
||||
.iter()
|
||||
.find(|i| i.name.eq_ignore_ascii_case(reg.register))
|
||||
.unwrap()
|
||||
.fields
|
||||
.iter()
|
||||
.find(|i| i.name.eq_ignore_ascii_case(reg.field))
|
||||
.unwrap()
|
||||
.bit_offset;
|
||||
let BitOffset::Regular(bit_offset) = bit_offset else {
|
||||
panic!("cursed bit offset")
|
||||
};
|
||||
let bit_offset: u8 = bit_offset.offset.try_into().unwrap();
|
||||
|
||||
quote! { (#reg_offset, #bit_offset) }
|
||||
};
|
||||
let en_bit_offs: u8 = en_bit_offs.offset.try_into().unwrap();
|
||||
|
||||
let refcount = *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1;
|
||||
let (before_enable, before_disable) = if refcount {
|
||||
let refcount_static =
|
||||
format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase());
|
||||
let reset_offset_and_bit = match rst_reg {
|
||||
Some(rst_reg) => {
|
||||
let reset_offset_and_bit = get_offset_and_bit(rst_reg);
|
||||
quote! { Some(#reset_offset_and_bit) }
|
||||
}
|
||||
None => quote! { None },
|
||||
};
|
||||
let enable_offset_and_bit = get_offset_and_bit(en_reg);
|
||||
|
||||
clock_gen.refcount_statics.insert(refcount_static.clone());
|
||||
|
||||
(
|
||||
quote! {
|
||||
unsafe { refcount_statics::#refcount_static += 1 };
|
||||
if unsafe { refcount_statics::#refcount_static } > 1 {
|
||||
return;
|
||||
}
|
||||
},
|
||||
quote! {
|
||||
unsafe { refcount_statics::#refcount_static -= 1 };
|
||||
if unsafe { refcount_statics::#refcount_static } > 0 {
|
||||
return;
|
||||
}
|
||||
},
|
||||
)
|
||||
let needs_refcount = *rcc_field_count.get(&(en_reg.register, en_reg.field)).unwrap() > 1;
|
||||
let refcount_idx = if needs_refcount {
|
||||
let next_refcount_idx = refcount_idxs.len() as u8;
|
||||
let refcount_idx = *refcount_idxs
|
||||
.entry((en_reg.register, en_reg.field))
|
||||
.or_insert(next_refcount_idx);
|
||||
quote! { Some(#refcount_idx) }
|
||||
} else {
|
||||
(TokenStream::new(), TokenStream::new())
|
||||
quote! { None }
|
||||
};
|
||||
|
||||
let clock_frequency = match &rcc.kernel_clock {
|
||||
@ -599,24 +592,10 @@ fn main() {
|
||||
|
||||
// A refcount leak can result if the same field is shared by peripherals with different stop modes
|
||||
// This condition should be checked in stm32-data
|
||||
let stop_refcount = match rcc.stop_mode {
|
||||
StopMode::Standby => None,
|
||||
StopMode::Stop2 => Some(quote! { REFCOUNT_STOP2 }),
|
||||
StopMode::Stop1 => Some(quote! { REFCOUNT_STOP1 }),
|
||||
};
|
||||
|
||||
let (incr_stop_refcount, decr_stop_refcount) = match stop_refcount {
|
||||
Some(stop_refcount) => (
|
||||
quote! {
|
||||
#[cfg(feature = "low-power")]
|
||||
unsafe { crate::rcc::#stop_refcount += 1 };
|
||||
},
|
||||
quote! {
|
||||
#[cfg(feature = "low-power")]
|
||||
unsafe { crate::rcc::#stop_refcount -= 1 };
|
||||
},
|
||||
),
|
||||
None => (TokenStream::new(), TokenStream::new()),
|
||||
let stop_mode = match rcc.stop_mode {
|
||||
StopMode::Standby => quote! { crate::rcc::StopMode::Standby },
|
||||
StopMode::Stop2 => quote! { crate::rcc::StopMode::Stop2 },
|
||||
StopMode::Stop1 => quote! { crate::rcc::StopMode::Stop1 },
|
||||
};
|
||||
|
||||
g.extend(quote! {
|
||||
@ -624,34 +603,16 @@ fn main() {
|
||||
fn frequency() -> crate::time::Hertz {
|
||||
#clock_frequency
|
||||
}
|
||||
fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) {
|
||||
#before_enable
|
||||
#incr_stop_refcount
|
||||
|
||||
#start_rst
|
||||
|
||||
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(true));
|
||||
|
||||
// we must wait two peripheral clock cycles before the clock is active
|
||||
// this seems to work, but might be incorrect
|
||||
// see http://efton.sk/STM32/gotcha/g183.html
|
||||
|
||||
// dummy read (like in the ST HALs)
|
||||
let _ = crate::pac::RCC.#en_reg().read();
|
||||
|
||||
// DSB for good measure
|
||||
cortex_m::asm::dsb();
|
||||
|
||||
#end_rst
|
||||
}
|
||||
fn disable_with_cs(_cs: critical_section::CriticalSection) {
|
||||
#before_disable
|
||||
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false));
|
||||
#decr_stop_refcount
|
||||
}
|
||||
|
||||
const ENABLE_BIT: crate::rcc::ClockEnableBit =
|
||||
unsafe { crate::rcc::ClockEnableBit::new(#en_reg_offs, #en_bit_offs) };
|
||||
const RCC_INFO: crate::rcc::RccInfo = unsafe {
|
||||
crate::rcc::RccInfo::new(
|
||||
#reset_offset_and_bit,
|
||||
#enable_offset_and_bit,
|
||||
#refcount_idx,
|
||||
#[cfg(feature = "low-power")]
|
||||
#stop_mode,
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
impl crate::rcc::RccPeripheral for peripherals::#pname {}
|
||||
@ -659,6 +620,14 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
g.extend({
|
||||
let refcounts_len = refcount_idxs.len();
|
||||
let refcount_zeros: TokenStream = refcount_idxs.iter().map(|_| quote! { 0u8, }).collect();
|
||||
quote! {
|
||||
pub(crate) static mut REFCOUNTS: [u8; #refcounts_len] = [#refcount_zeros];
|
||||
}
|
||||
});
|
||||
|
||||
let struct_fields: Vec<_> = clock_gen
|
||||
.muxes
|
||||
.iter()
|
||||
@ -762,22 +731,6 @@ fn main() {
|
||||
}
|
||||
);
|
||||
|
||||
let refcount_mod: TokenStream = clock_gen
|
||||
.refcount_statics
|
||||
.iter()
|
||||
.map(|refcount_static| {
|
||||
quote! {
|
||||
pub(crate) static mut #refcount_static: u8 = 0;
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
g.extend(quote! {
|
||||
mod refcount_statics {
|
||||
#refcount_mod
|
||||
}
|
||||
});
|
||||
|
||||
// ========
|
||||
// Generate fns to enable GPIO, DMA in RCC
|
||||
|
||||
@ -1654,54 +1607,65 @@ fn main() {
|
||||
rustfmt(&out_file);
|
||||
|
||||
// ========
|
||||
// Multicore
|
||||
// Configs for multicore and for targeting groups of chips
|
||||
|
||||
let mut s = chip_name.split('_');
|
||||
let mut chip_name: String = s.next().unwrap().to_string();
|
||||
let core_name = if let Some(c) = s.next() {
|
||||
if !c.starts_with("CM") {
|
||||
chip_name.push('_');
|
||||
chip_name.push_str(c);
|
||||
fn get_chip_cfgs(chip_name: &str) -> Vec<String> {
|
||||
let mut cfgs = Vec::new();
|
||||
|
||||
// Multicore
|
||||
|
||||
let mut s = chip_name.split('_');
|
||||
let mut chip_name: String = s.next().unwrap().to_string();
|
||||
let core_name = if let Some(c) = s.next() {
|
||||
if !c.starts_with("CM") {
|
||||
chip_name.push('_');
|
||||
chip_name.push_str(c);
|
||||
None
|
||||
} else {
|
||||
Some(c)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
} else {
|
||||
Some(c)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
};
|
||||
|
||||
if let Some(core) = core_name {
|
||||
println!("cargo:rustc-cfg={}_{}", &chip_name[..chip_name.len() - 2], core);
|
||||
if let Some(core) = core_name {
|
||||
cfgs.push(format!("{}_{}", &chip_name[..chip_name.len() - 2], core));
|
||||
}
|
||||
|
||||
// Configs for targeting groups of chips
|
||||
if &chip_name[..8] == "stm32wba" {
|
||||
cfgs.push(chip_name[..8].to_owned()); // stm32wba
|
||||
cfgs.push(chip_name[..10].to_owned()); // stm32wba52
|
||||
cfgs.push(format!("package_{}", &chip_name[10..11]));
|
||||
cfgs.push(format!("flashsize_{}", &chip_name[11..12]));
|
||||
} else {
|
||||
if &chip_name[..8] == "stm32h7r" || &chip_name[..8] == "stm32h7s" {
|
||||
cfgs.push("stm32h7rs".to_owned());
|
||||
} else {
|
||||
cfgs.push(chip_name[..7].to_owned()); // stm32f4
|
||||
}
|
||||
cfgs.push(chip_name[..9].to_owned()); // stm32f429
|
||||
cfgs.push(format!("{}x", &chip_name[..8])); // stm32f42x
|
||||
cfgs.push(format!("{}x{}", &chip_name[..7], &chip_name[8..9])); // stm32f4x9
|
||||
cfgs.push(format!("package_{}", &chip_name[9..10]));
|
||||
cfgs.push(format!("flashsize_{}", &chip_name[10..11]));
|
||||
}
|
||||
|
||||
// Mark the L4+ chips as they have many differences to regular L4.
|
||||
if &chip_name[..7] == "stm32l4" {
|
||||
if "pqrs".contains(&chip_name[7..8]) {
|
||||
cfgs.push("stm32l4_plus".to_owned());
|
||||
} else {
|
||||
cfgs.push("stm32l4_nonplus".to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
cfgs
|
||||
}
|
||||
|
||||
// =======
|
||||
// Features for targeting groups of chips
|
||||
|
||||
if &chip_name[..8] == "stm32wba" {
|
||||
println!("cargo:rustc-cfg={}", &chip_name[..8]); // stm32wba
|
||||
println!("cargo:rustc-cfg={}", &chip_name[..10]); // stm32wba52
|
||||
println!("cargo:rustc-cfg=package_{}", &chip_name[10..11]);
|
||||
println!("cargo:rustc-cfg=flashsize_{}", &chip_name[11..12]);
|
||||
} else {
|
||||
if &chip_name[..8] == "stm32h7r" || &chip_name[..8] == "stm32h7s" {
|
||||
println!("cargo:rustc-cfg=stm32h7rs");
|
||||
} else {
|
||||
println!("cargo:rustc-cfg={}", &chip_name[..7]); // stm32f4
|
||||
}
|
||||
println!("cargo:rustc-cfg={}", &chip_name[..9]); // stm32f429
|
||||
println!("cargo:rustc-cfg={}x", &chip_name[..8]); // stm32f42x
|
||||
println!("cargo:rustc-cfg={}x{}", &chip_name[..7], &chip_name[8..9]); // stm32f4x9
|
||||
println!("cargo:rustc-cfg=package_{}", &chip_name[9..10]);
|
||||
println!("cargo:rustc-cfg=flashsize_{}", &chip_name[10..11]);
|
||||
}
|
||||
|
||||
// Mark the L4+ chips as they have many differences to regular L4.
|
||||
if &chip_name[..7] == "stm32l4" {
|
||||
if "pqrs".contains(&chip_name[7..8]) {
|
||||
println!("cargo:rustc-cfg=stm32l4_plus");
|
||||
} else {
|
||||
println!("cargo:rustc-cfg=stm32l4_nonplus");
|
||||
}
|
||||
cfgs.enable_all(&get_chip_cfgs(&chip_name));
|
||||
for &chip_name in ALL_CHIPS.iter() {
|
||||
cfgs.declare_all(&get_chip_cfgs(&chip_name.to_ascii_lowercase()));
|
||||
}
|
||||
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
|
109
embassy-stm32/build_common.rs
Normal file
109
embassy-stm32/build_common.rs
Normal file
@ -0,0 +1,109 @@
|
||||
// NOTE: this file is copy-pasted between several Embassy crates, because there is no
|
||||
// straightforward way to share this code:
|
||||
// - it cannot be placed into the root of the repo and linked from each build.rs using `#[path =
|
||||
// "../build_common.rs"]`, because `cargo publish` requires that all files published with a crate
|
||||
// reside in the crate's directory,
|
||||
// - it cannot be symlinked from `embassy-xxx/build_common.rs` to `../build_common.rs`, because
|
||||
// symlinks don't work on Windows.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::process::Command;
|
||||
|
||||
/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring
|
||||
/// them (`cargo:rust-check-cfg=cfg(X)`).
|
||||
#[derive(Debug)]
|
||||
pub struct CfgSet {
|
||||
enabled: HashSet<String>,
|
||||
declared: HashSet<String>,
|
||||
emit_declared: bool,
|
||||
}
|
||||
|
||||
impl CfgSet {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
enabled: HashSet::new(),
|
||||
declared: HashSet::new(),
|
||||
emit_declared: is_rustc_nightly(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable a config, which can then be used in `#[cfg(...)]` for conditional compilation.
|
||||
///
|
||||
/// All configs that can potentially be enabled should be unconditionally declared using
|
||||
/// [`Self::declare()`].
|
||||
pub fn enable(&mut self, cfg: impl AsRef<str>) {
|
||||
if self.enabled.insert(cfg.as_ref().to_owned()) {
|
||||
println!("cargo:rustc-cfg={}", cfg.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enable_all(&mut self, cfgs: &[impl AsRef<str>]) {
|
||||
for cfg in cfgs.iter() {
|
||||
self.enable(cfg.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
/// Declare a valid config for conditional compilation, without enabling it.
|
||||
///
|
||||
/// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid.
|
||||
pub fn declare(&mut self, cfg: impl AsRef<str>) {
|
||||
if self.declared.insert(cfg.as_ref().to_owned()) && self.emit_declared {
|
||||
println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn declare_all(&mut self, cfgs: &[impl AsRef<str>]) {
|
||||
for cfg in cfgs.iter() {
|
||||
self.declare(cfg.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set(&mut self, cfg: impl Into<String>, enable: bool) {
|
||||
let cfg = cfg.into();
|
||||
if enable {
|
||||
self.enable(cfg.clone());
|
||||
}
|
||||
self.declare(cfg);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_rustc_nightly() -> bool {
|
||||
let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
|
||||
|
||||
let output = Command::new(rustc)
|
||||
.arg("--version")
|
||||
.output()
|
||||
.expect("failed to run `rustc --version`");
|
||||
|
||||
String::from_utf8_lossy(&output.stdout).contains("nightly")
|
||||
}
|
||||
|
||||
/// Sets configs that describe the target platform.
|
||||
pub fn set_target_cfgs(cfgs: &mut CfgSet) {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
|
||||
if target.starts_with("thumbv6m-") {
|
||||
cfgs.enable_all(&["cortex_m", "armv6m"]);
|
||||
} else if target.starts_with("thumbv7m-") {
|
||||
cfgs.enable_all(&["cortex_m", "armv7m"]);
|
||||
} else if target.starts_with("thumbv7em-") {
|
||||
cfgs.enable_all(&["cortex_m", "armv7m", "armv7em"]);
|
||||
} else if target.starts_with("thumbv8m.base") {
|
||||
cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_base"]);
|
||||
} else if target.starts_with("thumbv8m.main") {
|
||||
cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_main"]);
|
||||
}
|
||||
cfgs.declare_all(&[
|
||||
"cortex_m",
|
||||
"armv6m",
|
||||
"armv7m",
|
||||
"armv7em",
|
||||
"armv8m",
|
||||
"armv8m_base",
|
||||
"armv8m_main",
|
||||
]);
|
||||
|
||||
cfgs.set("has_fpu", target.ends_with("-eabihf"));
|
||||
}
|
@ -7,7 +7,7 @@ use embassy_hal_internal::into_ref;
|
||||
use super::blocking_delay_us;
|
||||
use crate::adc::{Adc, AdcChannel, Instance, SampleTime};
|
||||
use crate::time::Hertz;
|
||||
use crate::{interrupt, Peripheral};
|
||||
use crate::{interrupt, rcc, Peripheral};
|
||||
|
||||
pub const VDDA_CALIB_MV: u32 = 3300;
|
||||
pub const ADC_MAX: u32 = (1 << 12) - 1;
|
||||
@ -50,7 +50,7 @@ impl<T: Instance> super::SealedAdcChannel<T> for Temperature {
|
||||
impl<'d, T: Instance> Adc<'d, T> {
|
||||
pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
|
||||
into_ref!(adc);
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
T::regs().cr2().modify(|reg| reg.set_adon(true));
|
||||
|
||||
// 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’)
|
||||
@ -169,6 +169,6 @@ impl<'d, T: Instance> Drop for Adc<'d, T> {
|
||||
fn drop(&mut self) {
|
||||
T::regs().cr2().modify(|reg| reg.set_adon(false));
|
||||
|
||||
T::disable();
|
||||
rcc::disable::<T>();
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use super::blocking_delay_us;
|
||||
use crate::adc::{Adc, AdcChannel, Instance, SampleTime};
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::time::Hertz;
|
||||
use crate::{interrupt, Peripheral};
|
||||
use crate::{interrupt, rcc, Peripheral};
|
||||
|
||||
pub const VDDA_CALIB_MV: u32 = 3300;
|
||||
pub const ADC_MAX: u32 = (1 << 12) - 1;
|
||||
@ -63,7 +63,7 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
|
||||
into_ref!(adc);
|
||||
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
|
||||
// Enable the adc regulator
|
||||
T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE));
|
||||
@ -188,6 +188,6 @@ impl<'d, T: Instance> Drop for Adc<'d, T> {
|
||||
T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::INTERMEDIATE));
|
||||
T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::DISABLED));
|
||||
|
||||
T::disable();
|
||||
rcc::disable::<T>();
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use super::Resolution;
|
||||
use crate::adc::{Adc, AdcChannel, Instance, SampleTime};
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::time::Hertz;
|
||||
use crate::{interrupt, Peripheral};
|
||||
use crate::{interrupt, rcc, Peripheral};
|
||||
|
||||
const ADC_FREQ: Hertz = crate::rcc::HSI_FREQ;
|
||||
|
||||
@ -143,7 +143,7 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
) -> Self {
|
||||
into_ref!(adc);
|
||||
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
|
||||
//let r = T::regs();
|
||||
//r.cr2().write(|w| w.set_align(true));
|
||||
@ -403,6 +403,6 @@ impl<'d, T: Instance> Drop for Adc<'d, T> {
|
||||
|
||||
T::regs().cr2().modify(|w| w.set_adon(false));
|
||||
|
||||
T::disable();
|
||||
rcc::disable::<T>();
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use pac::adccommon::vals::Presc;
|
||||
|
||||
use super::{blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime};
|
||||
use crate::time::Hertz;
|
||||
use crate::{pac, Peripheral};
|
||||
use crate::{pac, rcc, Peripheral};
|
||||
|
||||
/// Default VREF voltage used for sample conversion to millivolts.
|
||||
pub const VREF_DEFAULT_MV: u32 = 3300;
|
||||
@ -130,7 +130,7 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
/// Create a new ADC driver.
|
||||
pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
|
||||
embassy_hal_internal::into_ref!(adc);
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
|
||||
let prescaler = Prescaler::from_ker_ck(T::frequency());
|
||||
|
||||
|
@ -71,9 +71,9 @@ pub(crate) trait SealedAdcChannel<T> {
|
||||
/// Performs a busy-wait delay for a specified number of microseconds.
|
||||
#[allow(unused)]
|
||||
pub(crate) fn blocking_delay_us(us: u32) {
|
||||
#[cfg(time)]
|
||||
embassy_time::block_for(embassy_time::Duration::from_micros(us));
|
||||
#[cfg(not(time))]
|
||||
#[cfg(feature = "time")]
|
||||
embassy_time::block_for(embassy_time::Duration::from_micros(us as u64));
|
||||
#[cfg(not(feature = "time"))]
|
||||
{
|
||||
let freq = unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 as u64;
|
||||
let us = us as u64;
|
||||
|
@ -10,7 +10,7 @@ use super::blocking_delay_us;
|
||||
use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime};
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::peripherals::ADC1;
|
||||
use crate::{interrupt, Peripheral};
|
||||
use crate::{interrupt, rcc, Peripheral};
|
||||
|
||||
pub const VDDA_CALIB_MV: u32 = 3300;
|
||||
pub const VREF_INT: u32 = 1230;
|
||||
@ -67,7 +67,7 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
) -> Self {
|
||||
into_ref!(adc);
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
|
||||
// Delay 1μs when using HSI14 as the ADC clock.
|
||||
//
|
||||
@ -199,6 +199,6 @@ impl<'d, T: Instance> Drop for Adc<'d, T> {
|
||||
T::regs().cr().modify(|reg| reg.set_addis(true));
|
||||
while T::regs().cr().read().aden() {}
|
||||
|
||||
T::disable();
|
||||
rcc::disable::<T>();
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use super::blocking_delay_us;
|
||||
use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime};
|
||||
use crate::peripherals::ADC1;
|
||||
use crate::time::Hertz;
|
||||
use crate::Peripheral;
|
||||
use crate::{rcc, Peripheral};
|
||||
|
||||
/// Default VREF voltage used for sample conversion to millivolts.
|
||||
pub const VREF_DEFAULT_MV: u32 = 3300;
|
||||
@ -31,7 +31,7 @@ impl AdcChannel<ADC1> for Temperature {}
|
||||
impl super::SealedAdcChannel<ADC1> for Temperature {
|
||||
fn channel(&self) -> u8 {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(stm32f2, stm32f40, stm32f41))] {
|
||||
if #[cfg(any(stm32f2, stm32f40x, stm32f41x))] {
|
||||
16
|
||||
} else {
|
||||
18
|
||||
@ -96,7 +96,7 @@ where
|
||||
{
|
||||
pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
|
||||
into_ref!(adc);
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
|
||||
let presc = Prescaler::from_pclk2(T::frequency());
|
||||
T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre()));
|
||||
@ -206,6 +206,6 @@ impl<'d, T: Instance> Drop for Adc<'d, T> {
|
||||
reg.set_adon(false);
|
||||
});
|
||||
|
||||
T::disable();
|
||||
rcc::disable::<T>();
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use embassy_hal_internal::into_ref;
|
||||
|
||||
use super::blocking_delay_us;
|
||||
use crate::adc::{Adc, AdcChannel, Instance, Resolution, SampleTime};
|
||||
use crate::Peripheral;
|
||||
use crate::{rcc, Peripheral};
|
||||
|
||||
/// Default VREF voltage used for sample conversion to millivolts.
|
||||
pub const VREF_DEFAULT_MV: u32 = 3300;
|
||||
@ -94,7 +94,7 @@ cfg_if! {
|
||||
impl<'d, T: Instance> Adc<'d, T> {
|
||||
pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
|
||||
into_ref!(adc);
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
T::regs().cr().modify(|reg| {
|
||||
#[cfg(not(any(adc_g0, adc_u0)))]
|
||||
reg.set_deeppwd(false);
|
||||
|
@ -4,7 +4,7 @@ use pac::adccommon::vals::Presc;
|
||||
|
||||
use super::{blocking_delay_us, Adc, AdcChannel, Instance, Resolution, SampleTime};
|
||||
use crate::time::Hertz;
|
||||
use crate::{pac, Peripheral};
|
||||
use crate::{pac, rcc, Peripheral};
|
||||
|
||||
/// Default VREF voltage used for sample conversion to millivolts.
|
||||
pub const VREF_DEFAULT_MV: u32 = 3300;
|
||||
@ -130,7 +130,7 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
/// Create a new ADC driver.
|
||||
pub fn new(adc: impl Peripheral<P = T> + 'd) -> Self {
|
||||
embassy_hal_internal::into_ref!(adc);
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
|
||||
let prescaler = Prescaler::from_ker_ck(T::frequency());
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use super::{ExtendedId, Fifo, FilterOwner, Id, Instance, MasterInstance, StandardId};
|
||||
use super::{ExtendedId, Fifo, Id, StandardId};
|
||||
|
||||
const F32_RTR: u32 = 0b010; // set the RTR bit to match remote frames
|
||||
const F32_IDE: u32 = 0b100; // set the IDE bit to match extended identifiers
|
||||
@ -210,24 +210,24 @@ impl From<Mask32> for BankConfig {
|
||||
}
|
||||
|
||||
/// Interface to the filter banks of a CAN peripheral.
|
||||
pub struct MasterFilters<'a, I: FilterOwner> {
|
||||
pub struct MasterFilters<'a> {
|
||||
/// Number of assigned filter banks.
|
||||
///
|
||||
/// On chips with splittable filter banks, this value can be dynamic.
|
||||
bank_count: u8,
|
||||
_can: PhantomData<&'a mut I>,
|
||||
canregs: crate::pac::can::Can,
|
||||
_phantom: PhantomData<&'a ()>,
|
||||
info: &'static crate::can::Info,
|
||||
}
|
||||
|
||||
// NOTE: This type mutably borrows the CAN instance and has unique access to the registers while it
|
||||
// exists.
|
||||
impl<I: FilterOwner> MasterFilters<'_, I> {
|
||||
pub(crate) unsafe fn new(canregs: crate::pac::can::Can) -> Self {
|
||||
impl MasterFilters<'_> {
|
||||
pub(crate) unsafe fn new(info: &'static crate::can::Info) -> Self {
|
||||
// Enable initialization mode.
|
||||
canregs.fmr().modify(|reg| reg.set_finit(true));
|
||||
info.regs.0.fmr().modify(|reg| reg.set_finit(true));
|
||||
|
||||
// Read the filter split value.
|
||||
let bank_count = canregs.fmr().read().can2sb();
|
||||
let bank_count = info.regs.0.fmr().read().can2sb();
|
||||
|
||||
// (Reset value of CAN2SB is 0x0E, 14, which, in devices with 14 filter banks, assigns all
|
||||
// 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> {
|
||||
|
||||
Self {
|
||||
bank_count,
|
||||
_can: PhantomData,
|
||||
canregs,
|
||||
_phantom: PhantomData,
|
||||
info,
|
||||
}
|
||||
}
|
||||
|
||||
@ -244,7 +244,7 @@ impl<I: FilterOwner> MasterFilters<'_, I> {
|
||||
FilterBanks {
|
||||
start_idx: 0,
|
||||
bank_count: self.bank_count,
|
||||
canregs: self.canregs,
|
||||
info: self.info,
|
||||
}
|
||||
}
|
||||
|
||||
@ -291,49 +291,49 @@ impl<I: FilterOwner> MasterFilters<'_, I> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: MasterInstance> MasterFilters<'_, I> {
|
||||
impl MasterFilters<'_> {
|
||||
/// Sets the index at which the filter banks owned by the slave peripheral start.
|
||||
pub fn set_split(&mut self, split_index: u8) -> &mut Self {
|
||||
assert!(split_index <= I::NUM_FILTER_BANKS);
|
||||
self.canregs.fmr().modify(|reg| reg.set_can2sb(split_index));
|
||||
assert!(split_index <= self.info.num_filter_banks);
|
||||
self.info.regs.0.fmr().modify(|reg| reg.set_can2sb(split_index));
|
||||
self.bank_count = split_index;
|
||||
self
|
||||
}
|
||||
|
||||
/// Accesses the filters assigned to the slave peripheral.
|
||||
pub fn slave_filters(&mut self) -> SlaveFilters<'_, I> {
|
||||
pub fn slave_filters(&mut self) -> SlaveFilters<'_> {
|
||||
// NB: This mutably borrows `self`, so it has full access to the filter bank registers.
|
||||
SlaveFilters {
|
||||
start_idx: self.bank_count,
|
||||
bank_count: I::NUM_FILTER_BANKS - self.bank_count,
|
||||
_can: PhantomData,
|
||||
canregs: self.canregs,
|
||||
bank_count: self.info.num_filter_banks - self.bank_count,
|
||||
_phantom: PhantomData,
|
||||
info: self.info,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: FilterOwner> Drop for MasterFilters<'_, I> {
|
||||
impl Drop for MasterFilters<'_> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
// Leave initialization mode.
|
||||
self.canregs.fmr().modify(|regs| regs.set_finit(false));
|
||||
self.info.regs.0.fmr().modify(|regs| regs.set_finit(false));
|
||||
}
|
||||
}
|
||||
|
||||
/// Interface to the filter banks assigned to a slave peripheral.
|
||||
pub struct SlaveFilters<'a, I: Instance> {
|
||||
pub struct SlaveFilters<'a> {
|
||||
start_idx: u8,
|
||||
bank_count: u8,
|
||||
_can: PhantomData<&'a mut I>,
|
||||
canregs: crate::pac::can::Can,
|
||||
_phantom: PhantomData<&'a ()>,
|
||||
info: &'static crate::can::Info,
|
||||
}
|
||||
|
||||
impl<I: Instance> SlaveFilters<'_, I> {
|
||||
impl SlaveFilters<'_> {
|
||||
fn banks_imm(&self) -> FilterBanks {
|
||||
FilterBanks {
|
||||
start_idx: self.start_idx,
|
||||
bank_count: self.bank_count,
|
||||
canregs: self.canregs,
|
||||
info: self.info,
|
||||
}
|
||||
}
|
||||
|
||||
@ -377,14 +377,14 @@ impl<I: Instance> SlaveFilters<'_, I> {
|
||||
struct FilterBanks {
|
||||
start_idx: u8,
|
||||
bank_count: u8,
|
||||
canregs: crate::pac::can::Can,
|
||||
info: &'static crate::can::Info,
|
||||
}
|
||||
|
||||
impl FilterBanks {
|
||||
fn clear(&mut self) {
|
||||
let mask = filter_bitmask(self.start_idx, self.bank_count);
|
||||
|
||||
self.canregs.fa1r().modify(|reg| {
|
||||
self.info.regs.0.fa1r().modify(|reg| {
|
||||
for i in 0..28usize {
|
||||
if (0x01u32 << i) & mask != 0 {
|
||||
reg.set_fact(i, false);
|
||||
@ -399,7 +399,11 @@ impl FilterBanks {
|
||||
|
||||
fn disable(&mut self, index: u8) {
|
||||
self.assert_bank_index(index);
|
||||
self.canregs.fa1r().modify(|reg| reg.set_fact(index as usize, false))
|
||||
self.info
|
||||
.regs
|
||||
.0
|
||||
.fa1r()
|
||||
.modify(|reg| reg.set_fact(index as usize, false))
|
||||
}
|
||||
|
||||
fn enable(&mut self, index: u8, fifo: Fifo, config: BankConfig) {
|
||||
@ -407,11 +411,11 @@ impl FilterBanks {
|
||||
|
||||
// Configure mode.
|
||||
let mode = matches!(config, BankConfig::List16(_) | BankConfig::List32(_));
|
||||
self.canregs.fm1r().modify(|reg| reg.set_fbm(index as usize, mode));
|
||||
self.info.regs.0.fm1r().modify(|reg| reg.set_fbm(index as usize, mode));
|
||||
|
||||
// Configure scale.
|
||||
let scale = matches!(config, BankConfig::List32(_) | BankConfig::Mask32(_));
|
||||
self.canregs.fs1r().modify(|reg| reg.set_fsc(index as usize, scale));
|
||||
self.info.regs.0.fs1r().modify(|reg| reg.set_fsc(index as usize, scale));
|
||||
|
||||
// Configure filter register.
|
||||
let (fxr1, fxr2);
|
||||
@ -433,12 +437,12 @@ impl FilterBanks {
|
||||
fxr2 = a.mask;
|
||||
}
|
||||
};
|
||||
let bank = self.canregs.fb(index as usize);
|
||||
let bank = self.info.regs.0.fb(index as usize);
|
||||
bank.fr1().write(|w| w.0 = fxr1);
|
||||
bank.fr2().write(|w| w.0 = fxr2);
|
||||
|
||||
// Assign to the right FIFO
|
||||
self.canregs.ffa1r().modify(|reg| {
|
||||
self.info.regs.0.ffa1r().modify(|reg| {
|
||||
reg.set_ffa(
|
||||
index as usize,
|
||||
match fifo {
|
||||
@ -449,7 +453,7 @@ impl FilterBanks {
|
||||
});
|
||||
|
||||
// Set active.
|
||||
self.canregs.fa1r().modify(|reg| reg.set_fact(index as usize, true))
|
||||
self.info.regs.0.fa1r().modify(|reg| reg.set_fact(index as usize, true))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,8 @@ use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use embassy_hal_internal::interrupt::InterruptExt;
|
||||
use embassy_hal_internal::into_ref;
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::channel::Channel;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
@ -19,7 +20,7 @@ use super::util;
|
||||
use crate::can::enums::{BusError, TryReadError};
|
||||
use crate::gpio::AFType;
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::rcc::RccPeripheral;
|
||||
use crate::rcc::{self, RccPeripheral};
|
||||
use crate::{interrupt, peripherals, Peripheral};
|
||||
|
||||
/// Interrupt handler.
|
||||
@ -90,11 +91,13 @@ impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterrup
|
||||
}
|
||||
|
||||
/// Configuration proxy returned by [`Can::modify_config`].
|
||||
pub struct CanConfig<'a, T: Instance> {
|
||||
can: PhantomData<&'a mut T>,
|
||||
pub struct CanConfig<'a> {
|
||||
phantom: PhantomData<&'a ()>,
|
||||
info: &'static Info,
|
||||
periph_clock: crate::time::Hertz,
|
||||
}
|
||||
|
||||
impl<T: Instance> CanConfig<'_, T> {
|
||||
impl CanConfig<'_> {
|
||||
/// Configures the bit timings.
|
||||
///
|
||||
/// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter
|
||||
@ -108,7 +111,7 @@ impl<T: Instance> CanConfig<'_, T> {
|
||||
/// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr`
|
||||
/// parameter to this method.
|
||||
pub fn set_bit_timing(self, bt: crate::can::util::NominalBitTiming) -> Self {
|
||||
Registers(T::regs()).set_bit_timing(bt);
|
||||
self.info.regs.set_bit_timing(bt);
|
||||
self
|
||||
}
|
||||
|
||||
@ -116,20 +119,20 @@ impl<T: Instance> CanConfig<'_, T> {
|
||||
///
|
||||
/// This is a helper that internally calls `set_bit_timing()`[Self::set_bit_timing].
|
||||
pub fn set_bitrate(self, bitrate: u32) -> Self {
|
||||
let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap();
|
||||
let bit_timing = util::calc_can_timings(self.periph_clock, bitrate).unwrap();
|
||||
self.set_bit_timing(bit_timing)
|
||||
}
|
||||
|
||||
/// Enables or disables loopback mode: Internally connects the TX and RX
|
||||
/// signals together.
|
||||
pub fn set_loopback(self, enabled: bool) -> Self {
|
||||
Registers(T::regs()).set_loopback(enabled);
|
||||
self.info.regs.set_loopback(enabled);
|
||||
self
|
||||
}
|
||||
|
||||
/// Enables or disables silent mode: Disconnects the TX signal from the pin.
|
||||
pub fn set_silent(self, enabled: bool) -> Self {
|
||||
Registers(T::regs()).set_silent(enabled);
|
||||
self.info.regs.set_silent(enabled);
|
||||
self
|
||||
}
|
||||
|
||||
@ -140,21 +143,24 @@ impl<T: Instance> CanConfig<'_, T> {
|
||||
///
|
||||
/// Automatic retransmission is enabled by default.
|
||||
pub fn set_automatic_retransmit(self, enabled: bool) -> Self {
|
||||
Registers(T::regs()).set_automatic_retransmit(enabled);
|
||||
self.info.regs.set_automatic_retransmit(enabled);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Instance> Drop for CanConfig<'_, T> {
|
||||
impl Drop for CanConfig<'_> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
Registers(T::regs()).leave_init_mode();
|
||||
self.info.regs.leave_init_mode();
|
||||
}
|
||||
}
|
||||
|
||||
/// CAN driver
|
||||
pub struct Can<'d, T: Instance> {
|
||||
peri: PeripheralRef<'d, T>,
|
||||
pub struct Can<'d> {
|
||||
phantom: PhantomData<&'d ()>,
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
periph_clock: crate::time::Hertz,
|
||||
}
|
||||
|
||||
/// Error returned by `try_write`
|
||||
@ -165,11 +171,11 @@ pub enum TryWriteError {
|
||||
Full,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Can<'d, T> {
|
||||
impl<'d> Can<'d> {
|
||||
/// Creates a new Bxcan instance, keeping the peripheral in sleep mode.
|
||||
/// You must call [Can::enable_non_blocking] to use the peripheral.
|
||||
pub fn new(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
pub fn new<T: Instance>(
|
||||
_peri: impl Peripheral<P = T> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
_irqs: impl interrupt::typelevel::Binding<T::TXInterrupt, TxInterruptHandler<T>>
|
||||
@ -178,15 +184,17 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
+ interrupt::typelevel::Binding<T::SCEInterrupt, SceInterruptHandler<T>>
|
||||
+ 'd,
|
||||
) -> Self {
|
||||
into_ref!(peri, rx, tx);
|
||||
into_ref!(_peri, rx, tx);
|
||||
let info = T::info();
|
||||
let regs = &T::info().regs;
|
||||
|
||||
rx.set_as_af(rx.af_num(), AFType::Input);
|
||||
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
||||
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
|
||||
{
|
||||
T::regs().ier().write(|w| {
|
||||
regs.0.ier().write(|w| {
|
||||
w.set_errie(true);
|
||||
w.set_fmpie(0, true);
|
||||
w.set_fmpie(1, true);
|
||||
@ -197,7 +205,7 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
w.set_lecie(true);
|
||||
});
|
||||
|
||||
T::regs().mcr().write(|w| {
|
||||
regs.0.mcr().write(|w| {
|
||||
// Enable timestamps on rx messages
|
||||
|
||||
w.set_ttcm(true);
|
||||
@ -205,17 +213,14 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
}
|
||||
|
||||
unsafe {
|
||||
T::TXInterrupt::unpend();
|
||||
T::TXInterrupt::enable();
|
||||
|
||||
T::RX0Interrupt::unpend();
|
||||
T::RX0Interrupt::enable();
|
||||
|
||||
T::RX1Interrupt::unpend();
|
||||
T::RX1Interrupt::enable();
|
||||
|
||||
T::SCEInterrupt::unpend();
|
||||
T::SCEInterrupt::enable();
|
||||
info.tx_interrupt.unpend();
|
||||
info.tx_interrupt.enable();
|
||||
info.rx0_interrupt.unpend();
|
||||
info.rx0_interrupt.enable();
|
||||
info.rx1_interrupt.unpend();
|
||||
info.rx1_interrupt.enable();
|
||||
info.sce_interrupt.unpend();
|
||||
info.sce_interrupt.enable();
|
||||
}
|
||||
|
||||
rx.set_as_af(rx.af_num(), AFType::Input);
|
||||
@ -223,12 +228,17 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
|
||||
Registers(T::regs()).leave_init_mode();
|
||||
|
||||
Self { peri }
|
||||
Self {
|
||||
phantom: PhantomData,
|
||||
info: T::info(),
|
||||
state: T::state(),
|
||||
periph_clock: T::frequency(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set CAN bit rate.
|
||||
pub fn set_bitrate(&mut self, bitrate: u32) {
|
||||
let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap();
|
||||
let bit_timing = util::calc_can_timings(self.periph_clock, bitrate).unwrap();
|
||||
self.modify_config().set_bit_timing(bit_timing);
|
||||
}
|
||||
|
||||
@ -236,10 +246,14 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
///
|
||||
/// Calling this method will enter initialization mode. You must enable the peripheral
|
||||
/// again afterwards with [`enable`](Self::enable).
|
||||
pub fn modify_config(&mut self) -> CanConfig<'_, T> {
|
||||
Registers(T::regs()).enter_init_mode();
|
||||
pub fn modify_config(&mut self) -> CanConfig<'_> {
|
||||
self.info.regs.enter_init_mode();
|
||||
|
||||
CanConfig { can: PhantomData }
|
||||
CanConfig {
|
||||
phantom: self.phantom,
|
||||
info: self.info,
|
||||
periph_clock: self.periph_clock,
|
||||
}
|
||||
}
|
||||
|
||||
/// Enables the peripheral and synchronizes with the bus.
|
||||
@ -247,7 +261,7 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
/// This will wait for 11 consecutive recessive bits (bus idle state).
|
||||
/// Contrary to enable method from bxcan library, this will not freeze the executor while waiting.
|
||||
pub async fn enable(&mut self) {
|
||||
while Registers(T::regs()).enable_non_blocking().is_err() {
|
||||
while self.info.regs.enable_non_blocking().is_err() {
|
||||
// SCE interrupt is only generated for entering sleep mode, but not leaving.
|
||||
// Yield to allow other tasks to execute while can bus is initializing.
|
||||
embassy_futures::yield_now().await;
|
||||
@ -257,7 +271,7 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
/// Enables or disables the peripheral from automatically wakeup when a SOF is detected on the bus
|
||||
/// while the peripheral is in sleep mode
|
||||
pub fn set_automatic_wakeup(&mut self, enabled: bool) {
|
||||
Registers(T::regs()).set_automatic_wakeup(enabled);
|
||||
self.info.regs.set_automatic_wakeup(enabled);
|
||||
}
|
||||
|
||||
/// Manually wake the peripheral from sleep mode.
|
||||
@ -265,12 +279,12 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
/// Waking the peripheral manually does not trigger a wake-up interrupt.
|
||||
/// This will wait until the peripheral has acknowledged it has awoken from sleep mode
|
||||
pub fn wakeup(&mut self) {
|
||||
Registers(T::regs()).wakeup()
|
||||
self.info.regs.wakeup()
|
||||
}
|
||||
|
||||
/// Check if the peripheral is currently in sleep mode
|
||||
pub fn is_sleeping(&self) -> bool {
|
||||
T::regs().msr().read().slak()
|
||||
self.info.regs.0.msr().read().slak()
|
||||
}
|
||||
|
||||
/// Put the peripheral in sleep mode
|
||||
@ -282,11 +296,11 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
/// If the peripheral has automatic wakeup enabled, when a Start-of-Frame is detected
|
||||
/// the peripheral will automatically wake and receive the incoming message.
|
||||
pub async fn sleep(&mut self) {
|
||||
T::regs().ier().modify(|i| i.set_slkie(true));
|
||||
T::regs().mcr().modify(|m| m.set_sleep(true));
|
||||
self.info.regs.0.ier().modify(|i| i.set_slkie(true));
|
||||
self.info.regs.0.mcr().modify(|m| m.set_sleep(true));
|
||||
|
||||
poll_fn(|cx| {
|
||||
T::state().err_waker.register(cx.waker());
|
||||
self.state.err_waker.register(cx.waker());
|
||||
if self.is_sleeping() {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
@ -295,7 +309,7 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
})
|
||||
.await;
|
||||
|
||||
T::regs().ier().modify(|i| i.set_slkie(false));
|
||||
self.info.regs.0.ier().modify(|i| i.set_slkie(false));
|
||||
}
|
||||
|
||||
/// Enable FIFO scheduling of outgoing frames.
|
||||
@ -307,12 +321,12 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
///
|
||||
/// FIFO scheduling is disabled by default.
|
||||
pub fn set_tx_fifo_scheduling(&mut self, enabled: bool) {
|
||||
Registers(T::regs()).set_tx_fifo_scheduling(enabled)
|
||||
self.info.regs.set_tx_fifo_scheduling(enabled)
|
||||
}
|
||||
|
||||
/// Checks if FIFO scheduling of outgoing frames is enabled.
|
||||
pub fn tx_fifo_scheduling_enabled(&self) -> bool {
|
||||
Registers(T::regs()).tx_fifo_scheduling_enabled()
|
||||
self.info.regs.tx_fifo_scheduling_enabled()
|
||||
}
|
||||
|
||||
/// Queues the message to be sent.
|
||||
@ -337,7 +351,13 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
|
||||
/// Waits for a specific transmit mailbox to become empty
|
||||
pub async fn flush(&self, mb: Mailbox) {
|
||||
CanTx::<T>::flush_inner(mb).await
|
||||
CanTx {
|
||||
_phantom: PhantomData,
|
||||
info: self.info,
|
||||
state: self.state,
|
||||
}
|
||||
.flush_inner(mb)
|
||||
.await;
|
||||
}
|
||||
|
||||
/// Waits until any of the transmit mailboxes become empty
|
||||
@ -347,12 +367,24 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
/// This will happen if FIFO scheduling of outgoing frames is not enabled,
|
||||
/// and a frame with equal priority is already queued for transmission.
|
||||
pub async fn flush_any(&self) {
|
||||
CanTx::<T>::flush_any_inner().await
|
||||
CanTx {
|
||||
_phantom: PhantomData,
|
||||
info: self.info,
|
||||
state: self.state,
|
||||
}
|
||||
.flush_any_inner()
|
||||
.await
|
||||
}
|
||||
|
||||
/// Waits until all of the transmit mailboxes become empty
|
||||
pub async fn flush_all(&self) {
|
||||
CanTx::<T>::flush_all_inner().await
|
||||
CanTx {
|
||||
_phantom: PhantomData,
|
||||
info: self.info,
|
||||
state: self.state,
|
||||
}
|
||||
.flush_all_inner()
|
||||
.await
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
/// If there is a frame in the provided mailbox, and it is canceled successfully, this function
|
||||
/// returns `true`.
|
||||
pub fn abort(&mut self, mailbox: Mailbox) -> bool {
|
||||
Registers(T::regs()).abort(mailbox)
|
||||
self.info.regs.abort(mailbox)
|
||||
}
|
||||
|
||||
/// Returns `true` if no frame is pending for transmission.
|
||||
pub fn is_transmitter_idle(&self) -> bool {
|
||||
Registers(T::regs()).is_idle()
|
||||
self.info.regs.is_idle()
|
||||
}
|
||||
|
||||
/// Read a CAN frame.
|
||||
@ -377,31 +409,35 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
///
|
||||
/// Returns a tuple of the time the message was received and the message frame
|
||||
pub async fn read(&mut self) -> Result<Envelope, BusError> {
|
||||
T::state().rx_mode.read::<T>().await
|
||||
self.state.rx_mode.read(self.info, self.state).await
|
||||
}
|
||||
|
||||
/// Attempts to read a CAN frame without blocking.
|
||||
///
|
||||
/// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
|
||||
pub fn try_read(&mut self) -> Result<Envelope, TryReadError> {
|
||||
T::state().rx_mode.try_read::<T>()
|
||||
self.state.rx_mode.try_read(self.info)
|
||||
}
|
||||
|
||||
/// Waits while receive queue is empty.
|
||||
pub async fn wait_not_empty(&mut self) {
|
||||
T::state().rx_mode.wait_not_empty::<T>().await
|
||||
self.state.rx_mode.wait_not_empty(self.info, self.state).await
|
||||
}
|
||||
|
||||
/// Split the CAN driver into transmit and receive halves.
|
||||
///
|
||||
/// Useful for doing separate transmit/receive tasks.
|
||||
pub fn split<'c>(&'c mut self) -> (CanTx<'d, T>, CanRx<'d, T>) {
|
||||
pub fn split<'c>(&'c mut self) -> (CanTx<'d>, CanRx<'d>) {
|
||||
(
|
||||
CanTx {
|
||||
_peri: unsafe { self.peri.clone_unchecked() },
|
||||
_phantom: PhantomData,
|
||||
info: self.info,
|
||||
state: self.state,
|
||||
},
|
||||
CanRx {
|
||||
peri: unsafe { self.peri.clone_unchecked() },
|
||||
_phantom: PhantomData,
|
||||
info: self.info,
|
||||
state: self.state,
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -411,7 +447,7 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
&'c mut self,
|
||||
txb: &'static mut TxBuf<TX_BUF_SIZE>,
|
||||
rxb: &'static mut RxBuf<RX_BUF_SIZE>,
|
||||
) -> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> {
|
||||
) -> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
|
||||
let (tx, rx) = self.split();
|
||||
BufferedCan {
|
||||
tx: tx.buffered(txb),
|
||||
@ -420,23 +456,23 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: FilterOwner> Can<'d, T> {
|
||||
impl<'d> Can<'d> {
|
||||
/// Accesses the filter banks owned by this CAN peripheral.
|
||||
///
|
||||
/// To modify filters of a slave peripheral, `modify_filters` has to be called on the master
|
||||
/// peripheral instead.
|
||||
pub fn modify_filters(&mut self) -> MasterFilters<'_, T> {
|
||||
unsafe { MasterFilters::new(T::regs()) }
|
||||
pub fn modify_filters(&mut self) -> MasterFilters<'_> {
|
||||
unsafe { MasterFilters::new(self.info) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Buffered CAN driver.
|
||||
pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
|
||||
tx: BufferedCanTx<'d, T, TX_BUF_SIZE>,
|
||||
rx: BufferedCanRx<'d, T, RX_BUF_SIZE>,
|
||||
pub struct BufferedCan<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
|
||||
tx: BufferedCanTx<'d, TX_BUF_SIZE>,
|
||||
rx: BufferedCanRx<'d, RX_BUF_SIZE>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> {
|
||||
impl<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
|
||||
/// Async write frame to TX buffer.
|
||||
pub async fn write(&mut self, frame: &Frame) {
|
||||
self.tx.write(frame).await
|
||||
@ -471,18 +507,20 @@ impl<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Buffer
|
||||
}
|
||||
|
||||
/// CAN driver, transmit half.
|
||||
pub struct CanTx<'d, T: Instance> {
|
||||
_peri: PeripheralRef<'d, T>,
|
||||
pub struct CanTx<'d> {
|
||||
_phantom: PhantomData<&'d ()>,
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> CanTx<'d, T> {
|
||||
impl<'d> CanTx<'d> {
|
||||
/// Queues the message to be sent.
|
||||
///
|
||||
/// If the TX queue is full, this will wait until there is space, therefore exerting backpressure.
|
||||
pub async fn write(&mut self, frame: &Frame) -> TransmitStatus {
|
||||
poll_fn(|cx| {
|
||||
T::state().tx_mode.register(cx.waker());
|
||||
if let Ok(status) = Registers(T::regs()).transmit(frame) {
|
||||
self.state.tx_mode.register(cx.waker());
|
||||
if let Ok(status) = self.info.regs.transmit(frame) {
|
||||
return Poll::Ready(status);
|
||||
}
|
||||
|
||||
@ -501,13 +539,13 @@ impl<'d, T: Instance> CanTx<'d, T> {
|
||||
/// This is done to work around a hardware limitation that could lead to out-of-order delivery
|
||||
/// of frames with the same priority.
|
||||
pub fn try_write(&mut self, frame: &Frame) -> Result<TransmitStatus, TryWriteError> {
|
||||
Registers(T::regs()).transmit(frame).map_err(|_| TryWriteError::Full)
|
||||
self.info.regs.transmit(frame).map_err(|_| TryWriteError::Full)
|
||||
}
|
||||
|
||||
async fn flush_inner(mb: Mailbox) {
|
||||
async fn flush_inner(&self, mb: Mailbox) {
|
||||
poll_fn(|cx| {
|
||||
T::state().tx_mode.register(cx.waker());
|
||||
if T::regs().tsr().read().tme(mb.index()) {
|
||||
self.state.tx_mode.register(cx.waker());
|
||||
if self.info.regs.0.tsr().read().tme(mb.index()) {
|
||||
return Poll::Ready(());
|
||||
}
|
||||
|
||||
@ -518,14 +556,14 @@ impl<'d, T: Instance> CanTx<'d, T> {
|
||||
|
||||
/// Waits for a specific transmit mailbox to become empty
|
||||
pub async fn flush(&self, mb: Mailbox) {
|
||||
Self::flush_inner(mb).await
|
||||
self.flush_inner(mb).await
|
||||
}
|
||||
|
||||
async fn flush_any_inner() {
|
||||
async fn flush_any_inner(&self) {
|
||||
poll_fn(|cx| {
|
||||
T::state().tx_mode.register(cx.waker());
|
||||
self.state.tx_mode.register(cx.waker());
|
||||
|
||||
let tsr = T::regs().tsr().read();
|
||||
let tsr = self.info.regs.0.tsr().read();
|
||||
if tsr.tme(Mailbox::Mailbox0.index())
|
||||
|| tsr.tme(Mailbox::Mailbox1.index())
|
||||
|| tsr.tme(Mailbox::Mailbox2.index())
|
||||
@ -545,14 +583,14 @@ impl<'d, T: Instance> CanTx<'d, T> {
|
||||
/// This will happen if FIFO scheduling of outgoing frames is not enabled,
|
||||
/// and a frame with equal priority is already queued for transmission.
|
||||
pub async fn flush_any(&self) {
|
||||
Self::flush_any_inner().await
|
||||
self.flush_any_inner().await
|
||||
}
|
||||
|
||||
async fn flush_all_inner() {
|
||||
async fn flush_all_inner(&self) {
|
||||
poll_fn(|cx| {
|
||||
T::state().tx_mode.register(cx.waker());
|
||||
self.state.tx_mode.register(cx.waker());
|
||||
|
||||
let tsr = T::regs().tsr().read();
|
||||
let tsr = self.info.regs.0.tsr().read();
|
||||
if tsr.tme(Mailbox::Mailbox0.index())
|
||||
&& tsr.tme(Mailbox::Mailbox1.index())
|
||||
&& tsr.tme(Mailbox::Mailbox2.index())
|
||||
@ -567,7 +605,7 @@ impl<'d, T: Instance> CanTx<'d, T> {
|
||||
|
||||
/// Waits until all of the transmit mailboxes become empty
|
||||
pub async fn flush_all(&self) {
|
||||
Self::flush_all_inner().await
|
||||
self.flush_all_inner().await
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
/// If there is a frame in the provided mailbox, and it is canceled successfully, this function
|
||||
/// returns `true`.
|
||||
pub fn abort(&mut self, mailbox: Mailbox) -> bool {
|
||||
Registers(T::regs()).abort(mailbox)
|
||||
self.info.regs.abort(mailbox)
|
||||
}
|
||||
|
||||
/// Returns `true` if no frame is pending for transmission.
|
||||
pub fn is_idle(&self) -> bool {
|
||||
Registers(T::regs()).is_idle()
|
||||
self.info.regs.is_idle()
|
||||
}
|
||||
|
||||
/// Return a buffered instance of driver. User must supply Buffers
|
||||
pub fn buffered<const TX_BUF_SIZE: usize>(
|
||||
self,
|
||||
txb: &'static mut TxBuf<TX_BUF_SIZE>,
|
||||
) -> BufferedCanTx<'d, T, TX_BUF_SIZE> {
|
||||
BufferedCanTx::new(self, txb)
|
||||
) -> BufferedCanTx<'d, TX_BUF_SIZE> {
|
||||
BufferedCanTx::new(self.info, self.state, self, txb)
|
||||
}
|
||||
}
|
||||
|
||||
@ -599,23 +637,35 @@ impl<'d, T: Instance> CanTx<'d, T> {
|
||||
pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>;
|
||||
|
||||
/// Buffered CAN driver, transmit half.
|
||||
pub struct BufferedCanTx<'d, T: Instance, const TX_BUF_SIZE: usize> {
|
||||
_tx: CanTx<'d, T>,
|
||||
pub struct BufferedCanTx<'d, const TX_BUF_SIZE: usize> {
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
_tx: CanTx<'d>,
|
||||
tx_buf: &'static TxBuf<TX_BUF_SIZE>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, const TX_BUF_SIZE: usize> BufferedCanTx<'d, T, TX_BUF_SIZE> {
|
||||
fn new(_tx: CanTx<'d, T>, tx_buf: &'static TxBuf<TX_BUF_SIZE>) -> Self {
|
||||
Self { _tx, tx_buf }.setup()
|
||||
impl<'d, const TX_BUF_SIZE: usize> BufferedCanTx<'d, TX_BUF_SIZE> {
|
||||
fn new(info: &'static Info, state: &'static State, _tx: CanTx<'d>, tx_buf: &'static TxBuf<TX_BUF_SIZE>) -> Self {
|
||||
Self {
|
||||
info,
|
||||
state,
|
||||
_tx,
|
||||
tx_buf,
|
||||
}
|
||||
.setup()
|
||||
}
|
||||
|
||||
fn setup(self) -> Self {
|
||||
// We don't want interrupts being processed while we change modes.
|
||||
critical_section::with(|_| unsafe {
|
||||
critical_section::with(|_| {
|
||||
let tx_inner = super::common::ClassicBufferedTxInner {
|
||||
tx_receiver: self.tx_buf.receiver().into(),
|
||||
};
|
||||
T::mut_state().tx_mode = TxMode::Buffered(tx_inner);
|
||||
let state = self.state as *const State;
|
||||
unsafe {
|
||||
let mut_state = state as *mut State;
|
||||
(*mut_state).tx_mode = TxMode::Buffered(tx_inner);
|
||||
}
|
||||
});
|
||||
self
|
||||
}
|
||||
@ -623,60 +673,67 @@ impl<'d, T: Instance, const TX_BUF_SIZE: usize> BufferedCanTx<'d, T, TX_BUF_SIZE
|
||||
/// Async write frame to TX buffer.
|
||||
pub async fn write(&mut self, frame: &Frame) {
|
||||
self.tx_buf.send(*frame).await;
|
||||
T::TXInterrupt::pend(); // Wake for Tx
|
||||
let waker = self.info.tx_waker;
|
||||
waker(); // Wake for Tx
|
||||
}
|
||||
|
||||
/// Returns a sender that can be used for sending CAN frames.
|
||||
pub fn writer(&self) -> BufferedCanSender {
|
||||
BufferedCanSender {
|
||||
tx_buf: self.tx_buf.sender().into(),
|
||||
waker: T::TXInterrupt::pend,
|
||||
waker: self.info.tx_waker,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, T, TX_BUF_SIZE> {
|
||||
impl<'d, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, TX_BUF_SIZE> {
|
||||
fn drop(&mut self) {
|
||||
critical_section::with(|_| unsafe {
|
||||
T::mut_state().tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
|
||||
critical_section::with(|_| {
|
||||
let state = self.state as *const State;
|
||||
unsafe {
|
||||
let mut_state = state as *mut State;
|
||||
(*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// CAN driver, receive half.
|
||||
#[allow(dead_code)]
|
||||
pub struct CanRx<'d, T: Instance> {
|
||||
peri: PeripheralRef<'d, T>,
|
||||
pub struct CanRx<'d> {
|
||||
_phantom: PhantomData<&'d ()>,
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> CanRx<'d, T> {
|
||||
impl<'d> CanRx<'d> {
|
||||
/// Read a CAN frame.
|
||||
///
|
||||
/// If no CAN frame is in the RX buffer, this will wait until there is one.
|
||||
///
|
||||
/// Returns a tuple of the time the message was received and the message frame
|
||||
pub async fn read(&mut self) -> Result<Envelope, BusError> {
|
||||
T::state().rx_mode.read::<T>().await
|
||||
self.state.rx_mode.read(self.info, self.state).await
|
||||
}
|
||||
|
||||
/// Attempts to read a CAN frame without blocking.
|
||||
///
|
||||
/// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
|
||||
pub fn try_read(&mut self) -> Result<Envelope, TryReadError> {
|
||||
T::state().rx_mode.try_read::<T>()
|
||||
self.state.rx_mode.try_read(self.info)
|
||||
}
|
||||
|
||||
/// Waits while receive queue is empty.
|
||||
pub async fn wait_not_empty(&mut self) {
|
||||
T::state().rx_mode.wait_not_empty::<T>().await
|
||||
self.state.rx_mode.wait_not_empty(self.info, self.state).await
|
||||
}
|
||||
|
||||
/// Return a buffered instance of driver. User must supply Buffers
|
||||
pub fn buffered<const RX_BUF_SIZE: usize>(
|
||||
self,
|
||||
rxb: &'static mut RxBuf<RX_BUF_SIZE>,
|
||||
) -> BufferedCanRx<'d, T, RX_BUF_SIZE> {
|
||||
BufferedCanRx::new(self, rxb)
|
||||
) -> BufferedCanRx<'d, RX_BUF_SIZE> {
|
||||
BufferedCanRx::new(self.info, self.state, self, rxb)
|
||||
}
|
||||
}
|
||||
|
||||
@ -684,23 +741,35 @@ impl<'d, T: Instance> CanRx<'d, T> {
|
||||
pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<Envelope, BusError>, BUF_SIZE>;
|
||||
|
||||
/// CAN driver, receive half in Buffered mode.
|
||||
pub struct BufferedCanRx<'d, T: Instance, const RX_BUF_SIZE: usize> {
|
||||
_rx: CanRx<'d, T>,
|
||||
pub struct BufferedCanRx<'d, const RX_BUF_SIZE: usize> {
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
_rx: CanRx<'d>,
|
||||
rx_buf: &'static RxBuf<RX_BUF_SIZE>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE> {
|
||||
fn new(_rx: CanRx<'d, T>, rx_buf: &'static RxBuf<RX_BUF_SIZE>) -> Self {
|
||||
BufferedCanRx { _rx, rx_buf }.setup()
|
||||
impl<'d, const RX_BUF_SIZE: usize> BufferedCanRx<'d, RX_BUF_SIZE> {
|
||||
fn new(info: &'static Info, state: &'static State, _rx: CanRx<'d>, rx_buf: &'static RxBuf<RX_BUF_SIZE>) -> Self {
|
||||
BufferedCanRx {
|
||||
info,
|
||||
state,
|
||||
_rx,
|
||||
rx_buf,
|
||||
}
|
||||
.setup()
|
||||
}
|
||||
|
||||
fn setup(self) -> Self {
|
||||
// We don't want interrupts being processed while we change modes.
|
||||
critical_section::with(|_| unsafe {
|
||||
critical_section::with(|_| {
|
||||
let rx_inner = super::common::ClassicBufferedRxInner {
|
||||
rx_sender: self.rx_buf.sender().into(),
|
||||
};
|
||||
T::mut_state().rx_mode = RxMode::Buffered(rx_inner);
|
||||
let state = self.state as *const State;
|
||||
unsafe {
|
||||
let mut_state = state as *mut State;
|
||||
(*mut_state).rx_mode = RxMode::Buffered(rx_inner);
|
||||
}
|
||||
});
|
||||
self
|
||||
}
|
||||
@ -714,7 +783,7 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE
|
||||
///
|
||||
/// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
|
||||
pub fn try_read(&mut self) -> Result<Envelope, TryReadError> {
|
||||
match &T::state().rx_mode {
|
||||
match &self.state.rx_mode {
|
||||
RxMode::Buffered(_) => {
|
||||
if let Ok(result) = self.rx_buf.try_receive() {
|
||||
match result {
|
||||
@ -722,7 +791,7 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE
|
||||
Err(e) => Err(TryReadError::BusError(e)),
|
||||
}
|
||||
} else {
|
||||
if let Some(err) = Registers(T::regs()).curr_error() {
|
||||
if let Some(err) = self.info.regs.curr_error() {
|
||||
return Err(TryReadError::BusError(err));
|
||||
} else {
|
||||
Err(TryReadError::Empty)
|
||||
@ -746,20 +815,26 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, T, RX_BUF_SIZE> {
|
||||
impl<'d, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, RX_BUF_SIZE> {
|
||||
fn drop(&mut self) {
|
||||
critical_section::with(|_| unsafe {
|
||||
T::mut_state().rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
|
||||
critical_section::with(|_| {
|
||||
let state = self.state as *const State;
|
||||
unsafe {
|
||||
let mut_state = state as *mut State;
|
||||
(*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Drop for Can<'d, T> {
|
||||
impl Drop for Can<'_> {
|
||||
fn drop(&mut self) {
|
||||
// Cannot call `free()` because it moves the instance.
|
||||
// Manually reset the peripheral.
|
||||
T::regs().mcr().write(|w| w.set_reset(true));
|
||||
T::disable();
|
||||
self.info.regs.0.mcr().write(|w| w.set_reset(true));
|
||||
self.info.regs.enter_init_mode();
|
||||
self.info.regs.leave_init_mode();
|
||||
//rcc::disable::<T>();
|
||||
}
|
||||
}
|
||||
|
||||
@ -839,13 +914,13 @@ impl RxMode {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn read<T: Instance>(&self) -> Result<Envelope, BusError> {
|
||||
pub(crate) async fn read(&self, info: &Info, state: &State) -> Result<Envelope, BusError> {
|
||||
match self {
|
||||
Self::NonBuffered(waker) => {
|
||||
poll_fn(|cx| {
|
||||
T::state().err_waker.register(cx.waker());
|
||||
state.err_waker.register(cx.waker());
|
||||
waker.register(cx.waker());
|
||||
match self.try_read::<T>() {
|
||||
match self.try_read(info) {
|
||||
Ok(result) => Poll::Ready(Ok(result)),
|
||||
Err(TryReadError::Empty) => Poll::Pending,
|
||||
Err(TryReadError::BusError(be)) => Poll::Ready(Err(be)),
|
||||
@ -858,17 +933,17 @@ impl RxMode {
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn try_read<T: Instance>(&self) -> Result<Envelope, TryReadError> {
|
||||
pub(crate) fn try_read(&self, info: &Info) -> Result<Envelope, TryReadError> {
|
||||
match self {
|
||||
Self::NonBuffered(_) => {
|
||||
let registers = Registers(T::regs());
|
||||
let registers = &info.regs;
|
||||
if let Some(msg) = registers.receive_fifo(RxFifo::Fifo0) {
|
||||
T::regs().ier().write(|w| {
|
||||
registers.0.ier().write(|w| {
|
||||
w.set_fmpie(0, true);
|
||||
});
|
||||
Ok(msg)
|
||||
} else if let Some(msg) = registers.receive_fifo(RxFifo::Fifo1) {
|
||||
T::regs().ier().write(|w| {
|
||||
registers.0.ier().write(|w| {
|
||||
w.set_fmpie(1, true);
|
||||
});
|
||||
Ok(msg)
|
||||
@ -883,12 +958,12 @@ impl RxMode {
|
||||
}
|
||||
}
|
||||
}
|
||||
pub async fn wait_not_empty<T: Instance>(&self) {
|
||||
match &T::state().rx_mode {
|
||||
pub(crate) async fn wait_not_empty(&self, info: &Info, state: &State) {
|
||||
match &state.rx_mode {
|
||||
Self::NonBuffered(waker) => {
|
||||
poll_fn(|cx| {
|
||||
waker.register(cx.waker());
|
||||
if Registers(T::regs()).receive_frame_available() {
|
||||
if info.regs.receive_frame_available() {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
Poll::Pending
|
||||
@ -903,7 +978,7 @@ impl RxMode {
|
||||
}
|
||||
}
|
||||
|
||||
enum TxMode {
|
||||
pub(crate) enum TxMode {
|
||||
NonBuffered(AtomicWaker),
|
||||
Buffered(super::common::ClassicBufferedTxInner),
|
||||
}
|
||||
@ -943,7 +1018,7 @@ impl TxMode {
|
||||
}
|
||||
}
|
||||
|
||||
struct State {
|
||||
pub(crate) struct State {
|
||||
pub(crate) rx_mode: RxMode,
|
||||
pub(crate) tx_mode: TxMode,
|
||||
pub err_waker: AtomicWaker,
|
||||
@ -959,7 +1034,22 @@ impl State {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Info {
|
||||
regs: Registers,
|
||||
tx_interrupt: crate::interrupt::Interrupt,
|
||||
rx0_interrupt: crate::interrupt::Interrupt,
|
||||
rx1_interrupt: crate::interrupt::Interrupt,
|
||||
sce_interrupt: crate::interrupt::Interrupt,
|
||||
tx_waker: fn(),
|
||||
|
||||
/// The total number of filter banks available to the instance.
|
||||
///
|
||||
/// This is usually either 14 or 28, and should be specified in the chip's reference manual or datasheet.
|
||||
num_filter_banks: u8,
|
||||
}
|
||||
|
||||
trait SealedInstance {
|
||||
fn info() -> &'static Info;
|
||||
fn regs() -> crate::pac::can::Can;
|
||||
fn state() -> &'static State;
|
||||
unsafe fn mut_state() -> &'static mut State;
|
||||
@ -1012,6 +1102,18 @@ foreach_peripheral!(
|
||||
(can, $inst:ident) => {
|
||||
impl SealedInstance for peripherals::$inst {
|
||||
|
||||
fn info() -> &'static Info {
|
||||
static INFO: Info = Info {
|
||||
regs: Registers(crate::pac::$inst),
|
||||
tx_interrupt: crate::_generated::peripheral_interrupts::$inst::TX::IRQ,
|
||||
rx0_interrupt: crate::_generated::peripheral_interrupts::$inst::RX0::IRQ,
|
||||
rx1_interrupt: crate::_generated::peripheral_interrupts::$inst::RX1::IRQ,
|
||||
sce_interrupt: crate::_generated::peripheral_interrupts::$inst::SCE::IRQ,
|
||||
tx_waker: crate::_generated::peripheral_interrupts::$inst::TX::pend,
|
||||
num_filter_banks: peripherals::$inst::NUM_FILTER_BANKS,
|
||||
};
|
||||
&INFO
|
||||
}
|
||||
fn regs() -> crate::pac::can::Can {
|
||||
crate::pac::$inst
|
||||
}
|
||||
@ -1046,8 +1148,8 @@ foreach_peripheral!(
|
||||
(can, CAN1) => {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(all(
|
||||
any(stm32l4, stm32f72, stm32f73),
|
||||
not(any(stm32l49, stm32l4a))
|
||||
any(stm32l4, stm32f72x, stm32f73x),
|
||||
not(any(stm32l49x, stm32l4ax))
|
||||
))] {
|
||||
// Most L4 devices and some F7 devices use the name "CAN1"
|
||||
// even if there is no "CAN2" peripheral.
|
||||
@ -1062,6 +1164,11 @@ foreach_peripheral!(
|
||||
}
|
||||
}
|
||||
};
|
||||
(can, CAN2) => {
|
||||
unsafe impl FilterOwner for peripherals::CAN2 {
|
||||
const NUM_FILTER_BANKS: u8 = 0;
|
||||
}
|
||||
};
|
||||
(can, CAN3) => {
|
||||
unsafe impl FilterOwner for peripherals::CAN3 {
|
||||
const NUM_FILTER_BANKS: u8 = 14;
|
||||
|
@ -11,7 +11,7 @@ use crate::can::frame::{Envelope, Frame, Header};
|
||||
pub(crate) struct Registers(pub crate::pac::can::Can);
|
||||
|
||||
impl Registers {
|
||||
pub fn enter_init_mode(&mut self) {
|
||||
pub fn enter_init_mode(&self) {
|
||||
self.0.mcr().modify(|reg| {
|
||||
reg.set_sleep(false);
|
||||
reg.set_inrq(true);
|
||||
@ -25,7 +25,7 @@ impl Registers {
|
||||
}
|
||||
|
||||
// Leaves initialization mode, enters sleep mode.
|
||||
pub fn leave_init_mode(&mut self) {
|
||||
pub fn leave_init_mode(&self) {
|
||||
self.0.mcr().modify(|reg| {
|
||||
reg.set_sleep(true);
|
||||
reg.set_inrq(false);
|
||||
@ -38,7 +38,7 @@ impl Registers {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_bit_timing(&mut self, bt: crate::can::util::NominalBitTiming) {
|
||||
pub fn set_bit_timing(&self, bt: crate::can::util::NominalBitTiming) {
|
||||
let prescaler = u16::from(bt.prescaler) & 0x1FF;
|
||||
let seg1 = u8::from(bt.seg1);
|
||||
let seg2 = u8::from(bt.seg2) & 0x7F;
|
||||
@ -84,7 +84,7 @@ impl Registers {
|
||||
/// receive the frame. If enabled, [`Interrupt::Wakeup`] will also be triggered by the incoming
|
||||
/// frame.
|
||||
#[allow(dead_code)]
|
||||
pub fn set_automatic_wakeup(&mut self, enabled: bool) {
|
||||
pub fn set_automatic_wakeup(&self, enabled: bool) {
|
||||
self.0.mcr().modify(|reg| reg.set_awum(enabled));
|
||||
}
|
||||
|
||||
@ -96,7 +96,7 @@ impl Registers {
|
||||
/// If this returns [`WouldBlock`][nb::Error::WouldBlock], the peripheral will enable itself
|
||||
/// in the background. The peripheral is enabled and ready to use when this method returns
|
||||
/// successfully.
|
||||
pub fn enable_non_blocking(&mut self) -> nb::Result<(), Infallible> {
|
||||
pub fn enable_non_blocking(&self) -> nb::Result<(), Infallible> {
|
||||
let msr = self.0.msr().read();
|
||||
if msr.slak() {
|
||||
self.0.mcr().modify(|reg| {
|
||||
@ -131,7 +131,7 @@ impl Registers {
|
||||
/// Note that this will not trigger [`Interrupt::Wakeup`], only reception of an incoming CAN
|
||||
/// frame will cause that interrupt.
|
||||
#[allow(dead_code)]
|
||||
pub fn wakeup(&mut self) {
|
||||
pub fn wakeup(&self) {
|
||||
self.0.mcr().modify(|reg| {
|
||||
reg.set_sleep(false);
|
||||
reg.set_inrq(false);
|
||||
@ -186,7 +186,7 @@ impl Registers {
|
||||
/// If this is enabled, mailboxes are scheduled based on the time when the transmit request bit of the mailbox was set.
|
||||
///
|
||||
/// If this is disabled, mailboxes are scheduled based on the priority of the frame in the mailbox.
|
||||
pub fn set_tx_fifo_scheduling(&mut self, enabled: bool) {
|
||||
pub fn set_tx_fifo_scheduling(&self, enabled: bool) {
|
||||
self.0.mcr().modify(|w| w.set_txfp(enabled))
|
||||
}
|
||||
|
||||
@ -216,7 +216,7 @@ impl Registers {
|
||||
/// If FIFO scheduling is enabled, frames are transmitted in the order that they are passed to this function.
|
||||
///
|
||||
/// If all transmit mailboxes are full, this function returns [`nb::Error::WouldBlock`].
|
||||
pub fn transmit(&mut self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> {
|
||||
pub fn transmit(&self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> {
|
||||
// Check if FIFO scheduling is enabled.
|
||||
let fifo_scheduling = self.0.mcr().read().txfp();
|
||||
|
||||
@ -292,7 +292,7 @@ impl Registers {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_mailbox(&mut self, idx: usize, frame: &Frame) {
|
||||
fn write_mailbox(&self, idx: usize, frame: &Frame) {
|
||||
debug_assert!(idx < 3);
|
||||
|
||||
let mb = self.0.tx(idx);
|
||||
@ -309,7 +309,7 @@ impl Registers {
|
||||
});
|
||||
}
|
||||
|
||||
fn read_pending_mailbox(&mut self, idx: usize) -> Option<Frame> {
|
||||
fn read_pending_mailbox(&self, idx: usize) -> Option<Frame> {
|
||||
if self.abort_by_index(idx) {
|
||||
debug_assert!(idx < 3);
|
||||
|
||||
@ -332,7 +332,7 @@ impl Registers {
|
||||
}
|
||||
|
||||
/// Tries to abort a pending frame. Returns `true` when aborted.
|
||||
fn abort_by_index(&mut self, idx: usize) -> bool {
|
||||
fn abort_by_index(&self, idx: usize) -> bool {
|
||||
self.0.tsr().write(|reg| reg.set_abrq(idx, true));
|
||||
|
||||
// Wait for the abort request to be finished.
|
||||
@ -351,7 +351,7 @@ impl Registers {
|
||||
///
|
||||
/// If there is a frame in the provided mailbox, and it is canceled successfully, this function
|
||||
/// returns `true`.
|
||||
pub fn abort(&mut self, mailbox: Mailbox) -> bool {
|
||||
pub fn abort(&self, mailbox: Mailbox) -> bool {
|
||||
// If the mailbox is empty, the value of TXOKx depends on what happened with the previous
|
||||
// frame in that mailbox. Only call abort_by_index() if the mailbox is not empty.
|
||||
let tsr = self.0.tsr().read();
|
||||
|
@ -20,8 +20,9 @@ enum LoopbackMode {
|
||||
}
|
||||
|
||||
pub struct Registers {
|
||||
pub regs: &'static crate::pac::can::Fdcan,
|
||||
pub msgram: &'static crate::pac::fdcanram::Fdcanram,
|
||||
pub regs: crate::pac::can::Fdcan,
|
||||
pub msgram: crate::pac::fdcanram::Fdcanram,
|
||||
#[allow(dead_code)]
|
||||
pub msg_ram_offset: usize,
|
||||
}
|
||||
|
||||
@ -72,7 +73,6 @@ impl Registers {
|
||||
|
||||
pub fn put_tx_frame(&self, bufidx: usize, header: &Header, buffer: &[u8]) {
|
||||
let mailbox = self.tx_buffer_element(bufidx);
|
||||
|
||||
mailbox.reset();
|
||||
put_tx_header(mailbox, header);
|
||||
put_tx_data(mailbox, &buffer[..header.len() as usize]);
|
||||
@ -244,12 +244,12 @@ impl Registers {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn reset_msg_ram(&mut self) {
|
||||
fn reset_msg_ram(&self) {
|
||||
self.msg_ram_mut().reset();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn enter_init_mode(&mut self) {
|
||||
fn enter_init_mode(&self) {
|
||||
self.regs.cccr().modify(|w| w.set_init(true));
|
||||
while false == self.regs.cccr().read().init() {}
|
||||
self.regs.cccr().modify(|w| w.set_cce(true));
|
||||
@ -258,7 +258,7 @@ impl Registers {
|
||||
/// Enables or disables loopback mode: Internally connects the TX and RX
|
||||
/// signals together.
|
||||
#[inline]
|
||||
fn set_loopback_mode(&mut self, mode: LoopbackMode) {
|
||||
fn set_loopback_mode(&self, mode: LoopbackMode) {
|
||||
let (test, mon, lbck) = match mode {
|
||||
LoopbackMode::None => (false, false, false),
|
||||
LoopbackMode::Internal => (true, true, true),
|
||||
@ -273,34 +273,34 @@ impl Registers {
|
||||
|
||||
/// Enables or disables silent mode: Disconnects the TX signal from the pin.
|
||||
#[inline]
|
||||
fn set_bus_monitoring_mode(&mut self, enabled: bool) {
|
||||
fn set_bus_monitoring_mode(&self, enabled: bool) {
|
||||
self.regs.cccr().modify(|w| w.set_mon(enabled));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_restricted_operations(&mut self, enabled: bool) {
|
||||
fn set_restricted_operations(&self, enabled: bool) {
|
||||
self.regs.cccr().modify(|w| w.set_asm(enabled));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_normal_operations(&mut self, _enabled: bool) {
|
||||
fn set_normal_operations(&self, _enabled: bool) {
|
||||
self.set_loopback_mode(LoopbackMode::None);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_test_mode(&mut self, enabled: bool) {
|
||||
fn set_test_mode(&self, enabled: bool) {
|
||||
self.regs.cccr().modify(|w| w.set_test(enabled));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_power_down_mode(&mut self, enabled: bool) {
|
||||
fn set_power_down_mode(&self, enabled: bool) {
|
||||
self.regs.cccr().modify(|w| w.set_csr(enabled));
|
||||
while self.regs.cccr().read().csa() != enabled {}
|
||||
}
|
||||
|
||||
/// Moves out of PoweredDownMode and into ConfigMode
|
||||
#[inline]
|
||||
pub fn into_config_mode(mut self, _config: FdCanConfig) {
|
||||
pub fn into_config_mode(self, _config: FdCanConfig) {
|
||||
self.set_power_down_mode(false);
|
||||
self.enter_init_mode();
|
||||
self.reset_msg_ram();
|
||||
@ -327,7 +327,7 @@ impl Registers {
|
||||
|
||||
/// Applies the settings of a new FdCanConfig See [`FdCanConfig`]
|
||||
#[inline]
|
||||
pub fn apply_config(&mut self, config: FdCanConfig) {
|
||||
pub fn apply_config(&self, config: FdCanConfig) {
|
||||
self.set_tx_buffer_mode(config.tx_buffer_mode);
|
||||
|
||||
// set standard filters list size to 28
|
||||
@ -388,7 +388,7 @@ impl Registers {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn leave_init_mode(&mut self, config: FdCanConfig) {
|
||||
fn leave_init_mode(&self, config: FdCanConfig) {
|
||||
self.apply_config(config);
|
||||
|
||||
self.regs.cccr().modify(|w| w.set_cce(false));
|
||||
@ -398,7 +398,7 @@ impl Registers {
|
||||
|
||||
/// Moves out of ConfigMode and into specified mode
|
||||
#[inline]
|
||||
pub fn into_mode(mut self, config: FdCanConfig, mode: crate::can::_version::OperatingMode) {
|
||||
pub fn into_mode(&self, config: FdCanConfig, mode: crate::can::_version::OperatingMode) {
|
||||
match mode {
|
||||
crate::can::OperatingMode::InternalLoopbackMode => self.set_loopback_mode(LoopbackMode::Internal),
|
||||
crate::can::OperatingMode::ExternalLoopbackMode => self.set_loopback_mode(LoopbackMode::External),
|
||||
@ -422,7 +422,7 @@ impl Registers {
|
||||
/// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr`
|
||||
/// parameter to this method.
|
||||
#[inline]
|
||||
pub fn set_nominal_bit_timing(&mut self, btr: NominalBitTiming) {
|
||||
pub fn set_nominal_bit_timing(&self, btr: NominalBitTiming) {
|
||||
self.regs.nbtp().write(|w| {
|
||||
w.set_nbrp(btr.nbrp() - 1);
|
||||
w.set_ntseg1(btr.ntseg1() - 1);
|
||||
@ -434,7 +434,7 @@ impl Registers {
|
||||
/// Configures the data bit timings for the FdCan Variable Bitrates.
|
||||
/// This is not used when frame_transmit is set to anything other than AllowFdCanAndBRS.
|
||||
#[inline]
|
||||
pub fn set_data_bit_timing(&mut self, btr: DataBitTiming) {
|
||||
pub fn set_data_bit_timing(&self, btr: DataBitTiming) {
|
||||
self.regs.dbtp().write(|w| {
|
||||
w.set_dbrp(btr.dbrp() - 1);
|
||||
w.set_dtseg1(btr.dtseg1() - 1);
|
||||
@ -450,39 +450,39 @@ impl Registers {
|
||||
///
|
||||
/// Automatic retransmission is enabled by default.
|
||||
#[inline]
|
||||
pub fn set_automatic_retransmit(&mut self, enabled: bool) {
|
||||
pub fn set_automatic_retransmit(&self, enabled: bool) {
|
||||
self.regs.cccr().modify(|w| w.set_dar(!enabled));
|
||||
}
|
||||
|
||||
/// Configures the transmit pause feature. See
|
||||
/// [`FdCanConfig::set_transmit_pause`]
|
||||
#[inline]
|
||||
pub fn set_transmit_pause(&mut self, enabled: bool) {
|
||||
pub fn set_transmit_pause(&self, enabled: bool) {
|
||||
self.regs.cccr().modify(|w| w.set_txp(!enabled));
|
||||
}
|
||||
|
||||
/// Configures non-iso mode. See [`FdCanConfig::set_non_iso_mode`]
|
||||
#[inline]
|
||||
pub fn set_non_iso_mode(&mut self, enabled: bool) {
|
||||
pub fn set_non_iso_mode(&self, enabled: bool) {
|
||||
self.regs.cccr().modify(|w| w.set_niso(enabled));
|
||||
}
|
||||
|
||||
/// Configures edge filtering. See [`FdCanConfig::set_edge_filtering`]
|
||||
#[inline]
|
||||
pub fn set_edge_filtering(&mut self, enabled: bool) {
|
||||
pub fn set_edge_filtering(&self, enabled: bool) {
|
||||
self.regs.cccr().modify(|w| w.set_efbi(enabled));
|
||||
}
|
||||
|
||||
/// Configures TX Buffer Mode
|
||||
#[inline]
|
||||
pub fn set_tx_buffer_mode(&mut self, tbm: TxBufferMode) {
|
||||
pub fn set_tx_buffer_mode(&self, tbm: TxBufferMode) {
|
||||
self.regs.txbc().write(|w| w.set_tfqm(tbm.into()));
|
||||
}
|
||||
|
||||
/// Configures frame transmission mode. See
|
||||
/// [`FdCanConfig::set_frame_transmit`]
|
||||
#[inline]
|
||||
pub fn set_frame_transmit(&mut self, fts: FrameTransmissionConfig) {
|
||||
pub fn set_frame_transmit(&self, fts: FrameTransmissionConfig) {
|
||||
let (fdoe, brse) = match fts {
|
||||
FrameTransmissionConfig::ClassicCanOnly => (false, false),
|
||||
FrameTransmissionConfig::AllowFdCan => (true, false),
|
||||
@ -500,14 +500,14 @@ impl Registers {
|
||||
|
||||
/// Sets the protocol exception handling on/off
|
||||
#[inline]
|
||||
pub fn set_protocol_exception_handling(&mut self, enabled: bool) {
|
||||
pub fn set_protocol_exception_handling(&self, enabled: bool) {
|
||||
self.regs.cccr().modify(|w| w.set_pxhd(!enabled));
|
||||
}
|
||||
|
||||
/// Configures and resets the timestamp counter
|
||||
#[inline]
|
||||
#[allow(unused)]
|
||||
pub fn set_timestamp_counter_source(&mut self, select: TimestampSource) {
|
||||
pub fn set_timestamp_counter_source(&self, select: TimestampSource) {
|
||||
#[cfg(can_fdcan_h7)]
|
||||
let (tcp, tss) = match select {
|
||||
TimestampSource::None => (0, 0),
|
||||
@ -531,7 +531,7 @@ impl Registers {
|
||||
#[cfg(not(can_fdcan_h7))]
|
||||
/// Configures the global filter settings
|
||||
#[inline]
|
||||
pub fn set_global_filter(&mut self, filter: GlobalFilter) {
|
||||
pub fn set_global_filter(&self, filter: GlobalFilter) {
|
||||
let anfs = match filter.handle_standard_frames {
|
||||
crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => stm32_metapac::can::vals::Anfs::ACCEPT_FIFO_0,
|
||||
crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => stm32_metapac::can::vals::Anfs::ACCEPT_FIFO_1,
|
||||
@ -554,7 +554,7 @@ impl Registers {
|
||||
#[cfg(can_fdcan_h7)]
|
||||
/// Configures the global filter settings
|
||||
#[inline]
|
||||
pub fn set_global_filter(&mut self, filter: GlobalFilter) {
|
||||
pub fn set_global_filter(&self, filter: GlobalFilter) {
|
||||
let anfs = match filter.handle_standard_frames {
|
||||
crate::can::fd::config::NonMatchingFilter::IntoRxFifo0 => 0,
|
||||
crate::can::fd::config::NonMatchingFilter::IntoRxFifo1 => 1,
|
||||
@ -576,10 +576,10 @@ impl Registers {
|
||||
}
|
||||
|
||||
#[cfg(not(can_fdcan_h7))]
|
||||
fn configure_msg_ram(&mut self) {}
|
||||
fn configure_msg_ram(&self) {}
|
||||
|
||||
#[cfg(can_fdcan_h7)]
|
||||
fn configure_msg_ram(&mut self) {
|
||||
fn configure_msg_ram(&self) {
|
||||
let r = self.regs;
|
||||
|
||||
use crate::can::fd::message_ram::*;
|
||||
|
@ -3,6 +3,7 @@ use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_hal_internal::interrupt::InterruptExt;
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::channel::{Channel, DynamicReceiver, DynamicSender};
|
||||
@ -11,7 +12,7 @@ use embassy_sync::waitqueue::AtomicWaker;
|
||||
use crate::can::fd::peripheral::Registers;
|
||||
use crate::gpio::AFType;
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::rcc::RccPeripheral;
|
||||
use crate::rcc::{self, RccPeripheral};
|
||||
use crate::{interrupt, peripherals, Peripheral};
|
||||
|
||||
pub(crate) mod fd;
|
||||
@ -40,7 +41,7 @@ pub struct IT0InterruptHandler<T: Instance> {
|
||||
// We use IT0 for everything currently
|
||||
impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
let regs = T::regs();
|
||||
let regs = T::registers().regs;
|
||||
|
||||
let ir = regs.ir().read();
|
||||
|
||||
@ -140,22 +141,16 @@ pub enum OperatingMode {
|
||||
//TestMode,
|
||||
}
|
||||
|
||||
/// FDCAN Configuration instance instance
|
||||
/// Create instance of this first
|
||||
pub struct CanConfigurator<'d, T: Instance> {
|
||||
config: crate::can::fd::config::FdCanConfig,
|
||||
/// Reference to internals.
|
||||
instance: FdcanInstance<'d, T>,
|
||||
properties: Properties<T>,
|
||||
}
|
||||
|
||||
fn calc_ns_per_timer_tick<T: Instance>(mode: crate::can::fd::config::FrameTransmissionConfig) -> u64 {
|
||||
fn calc_ns_per_timer_tick(
|
||||
info: &'static Info,
|
||||
freq: crate::time::Hertz,
|
||||
mode: crate::can::fd::config::FrameTransmissionConfig,
|
||||
) -> u64 {
|
||||
match mode {
|
||||
// Use timestamp from Rx FIFO to adjust timestamp reported to user
|
||||
crate::can::fd::config::FrameTransmissionConfig::ClassicCanOnly => {
|
||||
let freq = T::frequency();
|
||||
let prescale: u64 =
|
||||
({ T::regs().nbtp().read().nbrp() } + 1) as u64 * ({ T::regs().tscc().read().tcp() } + 1) as u64;
|
||||
let prescale: u64 = ({ info.regs.regs.nbtp().read().nbrp() } + 1) as u64
|
||||
* ({ info.regs.regs.tscc().read().tcp() } + 1) as u64;
|
||||
1_000_000_000 as u64 / (freq.0 as u64 * prescale)
|
||||
}
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> CanConfigurator<'d, T> {
|
||||
/// FDCAN Configuration instance instance
|
||||
/// Create instance of this first
|
||||
pub struct CanConfigurator<'d> {
|
||||
_phantom: PhantomData<&'d ()>,
|
||||
config: crate::can::fd::config::FdCanConfig,
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
/// Reference to internals.
|
||||
properties: Properties,
|
||||
periph_clock: crate::time::Hertz,
|
||||
}
|
||||
|
||||
impl<'d> CanConfigurator<'d> {
|
||||
/// Creates a new Fdcan instance, keeping the peripheral in sleep mode.
|
||||
/// You must call [Fdcan::enable_non_blocking] to use the peripheral.
|
||||
pub fn new(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
pub fn new<T: Instance>(
|
||||
_peri: impl Peripheral<P = T> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
_irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>>
|
||||
+ interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>>
|
||||
+ 'd,
|
||||
) -> CanConfigurator<'d, T> {
|
||||
into_ref!(peri, rx, tx);
|
||||
) -> CanConfigurator<'d> {
|
||||
into_ref!(_peri, rx, tx);
|
||||
|
||||
rx.set_as_af(rx.af_num(), AFType::Input);
|
||||
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
||||
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
|
||||
let mut config = crate::can::fd::config::FdCanConfig::default();
|
||||
config.timestamp_source = TimestampSource::Prescaler(TimestampPrescaler::_1);
|
||||
@ -196,16 +203,18 @@ impl<'d, T: Instance> CanConfigurator<'d, T> {
|
||||
T::IT1Interrupt::unpend(); // Not unsafe
|
||||
T::IT1Interrupt::enable();
|
||||
}
|
||||
|
||||
Self {
|
||||
_phantom: PhantomData,
|
||||
config,
|
||||
instance: FdcanInstance(peri),
|
||||
properties: Properties::new(),
|
||||
info: T::info(),
|
||||
state: T::state(),
|
||||
properties: Properties::new(T::info()),
|
||||
periph_clock: T::frequency(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get driver properties
|
||||
pub fn properties(&self) -> &Properties<T> {
|
||||
pub fn properties(&self) -> &Properties {
|
||||
&self.properties
|
||||
}
|
||||
|
||||
@ -221,7 +230,7 @@ impl<'d, T: Instance> CanConfigurator<'d, T> {
|
||||
|
||||
/// Configures the bit timings calculated from supplied bitrate.
|
||||
pub fn set_bitrate(&mut self, bitrate: u32) {
|
||||
let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap();
|
||||
let bit_timing = util::calc_can_timings(self.periph_clock, bitrate).unwrap();
|
||||
|
||||
let nbtr = crate::can::fd::config::NominalBitTiming {
|
||||
sync_jump_width: bit_timing.sync_jump_width,
|
||||
@ -234,7 +243,7 @@ impl<'d, T: Instance> CanConfigurator<'d, T> {
|
||||
|
||||
/// Configures the bit timings for VBR data calculated from supplied bitrate. This also sets confit to allow can FD and VBR
|
||||
pub fn set_fd_data_bitrate(&mut self, bitrate: u32, transceiver_delay_compensation: bool) {
|
||||
let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap();
|
||||
let bit_timing = util::calc_can_timings(self.periph_clock, bitrate).unwrap();
|
||||
// Note, used existing calcluation for normal(non-VBR) bitrate, appears to work for 250k/1M
|
||||
let nbtr = crate::can::fd::config::DataBitTiming {
|
||||
transceiver_delay_compensation,
|
||||
@ -248,62 +257,68 @@ impl<'d, T: Instance> CanConfigurator<'d, T> {
|
||||
}
|
||||
|
||||
/// Start in mode.
|
||||
pub fn start(self, mode: OperatingMode) -> Can<'d, T> {
|
||||
let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.config.frame_transmit);
|
||||
critical_section::with(|_| unsafe {
|
||||
T::mut_state().ns_per_timer_tick = ns_per_timer_tick;
|
||||
pub fn start(self, mode: OperatingMode) -> Can<'d> {
|
||||
let ns_per_timer_tick = calc_ns_per_timer_tick(self.info, self.periph_clock, self.config.frame_transmit);
|
||||
critical_section::with(|_| {
|
||||
let state = self.state as *const State;
|
||||
unsafe {
|
||||
let mut_state = state as *mut State;
|
||||
(*mut_state).ns_per_timer_tick = ns_per_timer_tick;
|
||||
}
|
||||
});
|
||||
T::registers().into_mode(self.config, mode);
|
||||
let ret = Can {
|
||||
self.info.regs.into_mode(self.config, mode);
|
||||
Can {
|
||||
_phantom: PhantomData,
|
||||
config: self.config,
|
||||
instance: self.instance,
|
||||
info: self.info,
|
||||
state: self.state,
|
||||
_mode: mode,
|
||||
properties: self.properties,
|
||||
};
|
||||
ret
|
||||
properties: Properties::new(self.info),
|
||||
}
|
||||
}
|
||||
|
||||
/// Start, entering mode. Does same as start(mode)
|
||||
pub fn into_normal_mode(self) -> Can<'d, T> {
|
||||
pub fn into_normal_mode(self) -> Can<'d> {
|
||||
self.start(OperatingMode::NormalOperationMode)
|
||||
}
|
||||
|
||||
/// Start, entering mode. Does same as start(mode)
|
||||
pub fn into_internal_loopback_mode(self) -> Can<'d, T> {
|
||||
pub fn into_internal_loopback_mode(self) -> Can<'d> {
|
||||
self.start(OperatingMode::InternalLoopbackMode)
|
||||
}
|
||||
|
||||
/// Start, entering mode. Does same as start(mode)
|
||||
pub fn into_external_loopback_mode(self) -> Can<'d, T> {
|
||||
pub fn into_external_loopback_mode(self) -> Can<'d> {
|
||||
self.start(OperatingMode::ExternalLoopbackMode)
|
||||
}
|
||||
}
|
||||
|
||||
/// FDCAN Instance
|
||||
pub struct Can<'d, T: Instance> {
|
||||
pub struct Can<'d> {
|
||||
_phantom: PhantomData<&'d ()>,
|
||||
config: crate::can::fd::config::FdCanConfig,
|
||||
/// Reference to internals.
|
||||
instance: FdcanInstance<'d, T>,
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
_mode: OperatingMode,
|
||||
properties: Properties<T>,
|
||||
properties: Properties,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Can<'d, T> {
|
||||
impl<'d> Can<'d> {
|
||||
/// Get driver properties
|
||||
pub fn properties(&self) -> &Properties<T> {
|
||||
pub fn properties(&self) -> &Properties {
|
||||
&self.properties
|
||||
}
|
||||
|
||||
/// Flush one of the TX mailboxes.
|
||||
pub async fn flush(&self, idx: usize) {
|
||||
poll_fn(|cx| {
|
||||
T::state().tx_mode.register(cx.waker());
|
||||
self.state.tx_mode.register(cx.waker());
|
||||
|
||||
if idx > 3 {
|
||||
panic!("Bad mailbox");
|
||||
}
|
||||
let idx = 1 << idx;
|
||||
if !T::regs().txbrp().read().trp(idx) {
|
||||
if !self.info.regs.regs.txbrp().read().trp(idx) {
|
||||
return Poll::Ready(());
|
||||
}
|
||||
|
||||
@ -317,12 +332,12 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
/// can be replaced, this call asynchronously waits for a frame to be successfully
|
||||
/// transmitted, then tries again.
|
||||
pub async fn write(&mut self, frame: &Frame) -> Option<Frame> {
|
||||
T::state().tx_mode.write::<T>(frame).await
|
||||
self.state.tx_mode.write(self.info, frame).await
|
||||
}
|
||||
|
||||
/// Returns the next received message frame
|
||||
pub async fn read(&mut self) -> Result<Envelope, BusError> {
|
||||
T::state().rx_mode.read_classic::<T>().await
|
||||
self.state.rx_mode.read_classic(self.info, self.state).await
|
||||
}
|
||||
|
||||
/// Queues the message to be sent but exerts backpressure. If a lower-priority
|
||||
@ -330,58 +345,61 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
/// can be replaced, this call asynchronously waits for a frame to be successfully
|
||||
/// transmitted, then tries again.
|
||||
pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> {
|
||||
T::state().tx_mode.write_fd::<T>(frame).await
|
||||
self.state.tx_mode.write_fd(self.info, frame).await
|
||||
}
|
||||
|
||||
/// Returns the next received message frame
|
||||
pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> {
|
||||
T::state().rx_mode.read_fd::<T>().await
|
||||
self.state.rx_mode.read_fd(self.info, self.state).await
|
||||
}
|
||||
|
||||
/// Split instance into separate portions: Tx(write), Rx(read), common properties
|
||||
pub fn split(self) -> (CanTx<'d, T>, CanRx<'d, T>, Properties<T>) {
|
||||
pub fn split(self) -> (CanTx<'d>, CanRx<'d>, Properties) {
|
||||
(
|
||||
CanTx {
|
||||
_phantom: PhantomData,
|
||||
info: self.info,
|
||||
state: self.state,
|
||||
config: self.config,
|
||||
_instance: self.instance,
|
||||
_mode: self._mode,
|
||||
},
|
||||
CanRx {
|
||||
_instance1: PhantomData::<T>,
|
||||
_instance2: T::regs(),
|
||||
_phantom: PhantomData,
|
||||
info: self.info,
|
||||
state: self.state,
|
||||
_mode: self._mode,
|
||||
},
|
||||
self.properties,
|
||||
)
|
||||
}
|
||||
|
||||
/// Join split rx and tx portions back together
|
||||
pub fn join(tx: CanTx<'d, T>, rx: CanRx<'d, T>) -> Self {
|
||||
pub fn join(tx: CanTx<'d>, rx: CanRx<'d>) -> Self {
|
||||
Can {
|
||||
_phantom: PhantomData,
|
||||
config: tx.config,
|
||||
//_instance2: T::regs(),
|
||||
instance: tx._instance,
|
||||
info: tx.info,
|
||||
state: tx.state,
|
||||
_mode: rx._mode,
|
||||
properties: Properties::new(),
|
||||
properties: Properties::new(tx.info),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a buffered instance of driver without CAN FD support. User must supply Buffers
|
||||
pub fn buffered<const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>(
|
||||
&self,
|
||||
self,
|
||||
tx_buf: &'static mut TxBuf<TX_BUF_SIZE>,
|
||||
rxb: &'static mut RxBuf<RX_BUF_SIZE>,
|
||||
) -> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> {
|
||||
BufferedCan::new(PhantomData::<T>, T::regs(), self._mode, tx_buf, rxb)
|
||||
) -> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
|
||||
BufferedCan::new(self.info, self.state, self._mode, tx_buf, rxb)
|
||||
}
|
||||
|
||||
/// Return a buffered instance of driver with CAN FD support. User must supply Buffers
|
||||
pub fn buffered_fd<const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>(
|
||||
&self,
|
||||
self,
|
||||
tx_buf: &'static mut TxFdBuf<TX_BUF_SIZE>,
|
||||
rxb: &'static mut RxFdBuf<RX_BUF_SIZE>,
|
||||
) -> BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> {
|
||||
BufferedCanFd::new(PhantomData::<T>, T::regs(), self._mode, tx_buf, rxb)
|
||||
) -> BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
|
||||
BufferedCanFd::new(self.info, self.state, self._mode, tx_buf, rxb)
|
||||
}
|
||||
}
|
||||
|
||||
@ -392,52 +410,56 @@ pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<
|
||||
pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>;
|
||||
|
||||
/// Buffered FDCAN Instance
|
||||
pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
|
||||
_instance1: PhantomData<T>,
|
||||
_instance2: &'d crate::pac::can::Fdcan,
|
||||
pub struct BufferedCan<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
|
||||
_phantom: PhantomData<&'d ()>,
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
_mode: OperatingMode,
|
||||
tx_buf: &'static TxBuf<TX_BUF_SIZE>,
|
||||
rx_buf: &'static RxBuf<RX_BUF_SIZE>,
|
||||
properties: Properties<T>,
|
||||
properties: Properties,
|
||||
}
|
||||
|
||||
impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
|
||||
BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE>
|
||||
{
|
||||
impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
|
||||
fn new(
|
||||
_instance1: PhantomData<T>,
|
||||
_instance2: &'d crate::pac::can::Fdcan,
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
_mode: OperatingMode,
|
||||
tx_buf: &'static TxBuf<TX_BUF_SIZE>,
|
||||
rx_buf: &'static RxBuf<RX_BUF_SIZE>,
|
||||
) -> Self {
|
||||
BufferedCan {
|
||||
_instance1,
|
||||
_instance2,
|
||||
_phantom: PhantomData,
|
||||
info,
|
||||
state,
|
||||
_mode,
|
||||
tx_buf,
|
||||
rx_buf,
|
||||
properties: Properties::new(),
|
||||
properties: Properties::new(info),
|
||||
}
|
||||
.setup()
|
||||
}
|
||||
|
||||
/// Get driver properties
|
||||
pub fn properties(&self) -> &Properties<T> {
|
||||
pub fn properties(&self) -> &Properties {
|
||||
&self.properties
|
||||
}
|
||||
|
||||
fn setup(self) -> Self {
|
||||
// We don't want interrupts being processed while we change modes.
|
||||
critical_section::with(|_| unsafe {
|
||||
critical_section::with(|_| {
|
||||
let rx_inner = super::common::ClassicBufferedRxInner {
|
||||
rx_sender: self.rx_buf.sender().into(),
|
||||
};
|
||||
let tx_inner = super::common::ClassicBufferedTxInner {
|
||||
tx_receiver: self.tx_buf.receiver().into(),
|
||||
};
|
||||
T::mut_state().rx_mode = RxMode::ClassicBuffered(rx_inner);
|
||||
T::mut_state().tx_mode = TxMode::ClassicBuffered(tx_inner);
|
||||
let state = self.state as *const State;
|
||||
unsafe {
|
||||
let mut_state = state as *mut State;
|
||||
(*mut_state).rx_mode = RxMode::ClassicBuffered(rx_inner);
|
||||
(*mut_state).tx_mode = TxMode::ClassicBuffered(tx_inner);
|
||||
}
|
||||
});
|
||||
self
|
||||
}
|
||||
@ -445,7 +467,8 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
|
||||
/// Async write frame to TX buffer.
|
||||
pub async fn write(&mut self, frame: Frame) {
|
||||
self.tx_buf.send(frame).await;
|
||||
T::IT0Interrupt::pend(); // Wake for Tx
|
||||
self.info.interrupt0.pend(); // Wake for Tx
|
||||
//T::IT0Interrupt::pend(); // Wake for Tx
|
||||
}
|
||||
|
||||
/// 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>
|
||||
pub fn writer(&self) -> BufferedCanSender {
|
||||
BufferedCanSender {
|
||||
tx_buf: self.tx_buf.sender().into(),
|
||||
waker: T::IT0Interrupt::pend,
|
||||
waker: self.info.tx_waker,
|
||||
}
|
||||
}
|
||||
|
||||
@ -467,13 +490,15 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
|
||||
}
|
||||
}
|
||||
|
||||
impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop
|
||||
for BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE>
|
||||
{
|
||||
impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop for BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
|
||||
fn drop(&mut self) {
|
||||
critical_section::with(|_| unsafe {
|
||||
T::mut_state().rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
|
||||
T::mut_state().tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
|
||||
critical_section::with(|_| {
|
||||
let state = self.state as *const State;
|
||||
unsafe {
|
||||
let mut_state = state as *mut State;
|
||||
(*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
|
||||
(*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -484,16 +509,6 @@ pub type RxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Resul
|
||||
/// User supplied buffer for TX buffering
|
||||
pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFrame, BUF_SIZE>;
|
||||
|
||||
/// Buffered FDCAN Instance
|
||||
pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
|
||||
_instance1: PhantomData<T>,
|
||||
_instance2: &'d crate::pac::can::Fdcan,
|
||||
_mode: OperatingMode,
|
||||
tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
|
||||
rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
|
||||
properties: Properties<T>,
|
||||
}
|
||||
|
||||
/// Sender that can be used for sending CAN frames.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct BufferedFdCanSender {
|
||||
@ -524,43 +539,57 @@ impl BufferedFdCanSender {
|
||||
/// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
|
||||
pub type BufferedFdCanReceiver = DynamicReceiver<'static, Result<FdEnvelope, BusError>>;
|
||||
|
||||
impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
|
||||
BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE>
|
||||
{
|
||||
/// Buffered FDCAN Instance
|
||||
pub struct BufferedCanFd<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
|
||||
_phantom: PhantomData<&'d ()>,
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
_mode: OperatingMode,
|
||||
tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
|
||||
rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
|
||||
properties: Properties,
|
||||
}
|
||||
|
||||
impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
|
||||
fn new(
|
||||
_instance1: PhantomData<T>,
|
||||
_instance2: &'d crate::pac::can::Fdcan,
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
_mode: OperatingMode,
|
||||
tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
|
||||
rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
|
||||
) -> Self {
|
||||
BufferedCanFd {
|
||||
_instance1,
|
||||
_instance2,
|
||||
_phantom: PhantomData,
|
||||
info,
|
||||
state,
|
||||
_mode,
|
||||
tx_buf,
|
||||
rx_buf,
|
||||
properties: Properties::new(),
|
||||
properties: Properties::new(info),
|
||||
}
|
||||
.setup()
|
||||
}
|
||||
|
||||
/// Get driver properties
|
||||
pub fn properties(&self) -> &Properties<T> {
|
||||
pub fn properties(&self) -> &Properties {
|
||||
&self.properties
|
||||
}
|
||||
|
||||
fn setup(self) -> Self {
|
||||
// We don't want interrupts being processed while we change modes.
|
||||
critical_section::with(|_| unsafe {
|
||||
critical_section::with(|_| {
|
||||
let rx_inner = super::common::FdBufferedRxInner {
|
||||
rx_sender: self.rx_buf.sender().into(),
|
||||
};
|
||||
let tx_inner = super::common::FdBufferedTxInner {
|
||||
tx_receiver: self.tx_buf.receiver().into(),
|
||||
};
|
||||
T::mut_state().rx_mode = RxMode::FdBuffered(rx_inner);
|
||||
T::mut_state().tx_mode = TxMode::FdBuffered(tx_inner);
|
||||
let state = self.state as *const State;
|
||||
unsafe {
|
||||
let mut_state = state as *mut State;
|
||||
(*mut_state).rx_mode = RxMode::FdBuffered(rx_inner);
|
||||
(*mut_state).tx_mode = TxMode::FdBuffered(tx_inner);
|
||||
}
|
||||
});
|
||||
self
|
||||
}
|
||||
@ -568,7 +597,8 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
|
||||
/// Async write frame to TX buffer.
|
||||
pub async fn write(&mut self, frame: FdFrame) {
|
||||
self.tx_buf.send(frame).await;
|
||||
T::IT0Interrupt::pend(); // Wake for Tx
|
||||
self.info.interrupt0.pend(); // Wake for Tx
|
||||
//T::IT0Interrupt::pend(); // Wake for Tx
|
||||
}
|
||||
|
||||
/// 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>
|
||||
pub fn writer(&self) -> BufferedFdCanSender {
|
||||
BufferedFdCanSender {
|
||||
tx_buf: self.tx_buf.sender().into(),
|
||||
waker: T::IT0Interrupt::pend,
|
||||
waker: self.info.tx_waker,
|
||||
}
|
||||
}
|
||||
|
||||
@ -590,38 +620,55 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
|
||||
}
|
||||
}
|
||||
|
||||
impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop
|
||||
for BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE>
|
||||
{
|
||||
impl<'c, 'd, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop for BufferedCanFd<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
|
||||
fn drop(&mut self) {
|
||||
critical_section::with(|_| unsafe {
|
||||
T::mut_state().rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
|
||||
T::mut_state().tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
|
||||
critical_section::with(|_| {
|
||||
let state = self.state as *const State;
|
||||
unsafe {
|
||||
let mut_state = state as *mut State;
|
||||
(*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
|
||||
(*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// FDCAN Rx only Instance
|
||||
pub struct CanRx<'d, T: Instance> {
|
||||
_instance1: PhantomData<T>,
|
||||
_instance2: &'d crate::pac::can::Fdcan,
|
||||
pub struct CanRx<'d> {
|
||||
_phantom: PhantomData<&'d ()>,
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
_mode: OperatingMode,
|
||||
}
|
||||
|
||||
impl<'d> CanRx<'d> {
|
||||
/// Returns the next received message frame
|
||||
pub async fn read(&mut self) -> Result<Envelope, BusError> {
|
||||
self.state.rx_mode.read_classic(&self.info, &self.state).await
|
||||
}
|
||||
|
||||
/// Returns the next received message frame
|
||||
pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> {
|
||||
self.state.rx_mode.read_fd(&self.info, &self.state).await
|
||||
}
|
||||
}
|
||||
|
||||
/// FDCAN Tx only Instance
|
||||
pub struct CanTx<'d, T: Instance> {
|
||||
pub struct CanTx<'d> {
|
||||
_phantom: PhantomData<&'d ()>,
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
config: crate::can::fd::config::FdCanConfig,
|
||||
_instance: FdcanInstance<'d, T>, //(PeripheralRef<'a, T>);
|
||||
_mode: OperatingMode,
|
||||
}
|
||||
|
||||
impl<'c, 'd, T: Instance> CanTx<'d, T> {
|
||||
impl<'c, 'd> CanTx<'d> {
|
||||
/// Queues the message to be sent but exerts backpressure. If a lower-priority
|
||||
/// frame is dropped from the mailbox, it is returned. If no lower-priority frames
|
||||
/// can be replaced, this call asynchronously waits for a frame to be successfully
|
||||
/// transmitted, then tries again.
|
||||
pub async fn write(&mut self, frame: &Frame) -> Option<Frame> {
|
||||
T::state().tx_mode.write::<T>(frame).await
|
||||
self.state.tx_mode.write(self.info, frame).await
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
/// can be replaced, this call asynchronously waits for a frame to be successfully
|
||||
/// transmitted, then tries again.
|
||||
pub async fn write_fd(&mut self, frame: &FdFrame) -> Option<FdFrame> {
|
||||
T::state().tx_mode.write_fd::<T>(frame).await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'c, 'd, T: Instance> CanRx<'d, T> {
|
||||
/// Returns the next received message frame
|
||||
pub async fn read(&mut self) -> Result<Envelope, BusError> {
|
||||
T::state().rx_mode.read_classic::<T>().await
|
||||
}
|
||||
|
||||
/// Returns the next received message frame
|
||||
pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> {
|
||||
T::state().rx_mode.read_fd::<T>().await
|
||||
self.state.tx_mode.write_fd(self.info, frame).await
|
||||
}
|
||||
}
|
||||
|
||||
@ -662,7 +697,7 @@ impl RxMode {
|
||||
}
|
||||
|
||||
fn on_interrupt<T: Instance>(&self, fifonr: usize) {
|
||||
T::regs().ir().write(|w| w.set_rfn(fifonr, true));
|
||||
T::registers().regs.ir().write(|w| w.set_rfn(fifonr, true));
|
||||
match self {
|
||||
RxMode::NonBuffered(waker) => {
|
||||
waker.wake();
|
||||
@ -696,7 +731,6 @@ impl RxMode {
|
||||
}
|
||||
}
|
||||
|
||||
//async fn read_classic<T: Instance>(&self) -> Result<Envelope, BusError> {
|
||||
fn try_read_fd<T: Instance>(&self) -> Option<Result<FdEnvelope, BusError>> {
|
||||
if let Some((frame, ts)) = T::registers().read(0) {
|
||||
let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
|
||||
@ -712,14 +746,18 @@ impl RxMode {
|
||||
}
|
||||
}
|
||||
|
||||
fn read<T: Instance, F: CanHeader>(&self) -> Option<Result<(F, Timestamp), BusError>> {
|
||||
if let Some((msg, ts)) = T::registers().read(0) {
|
||||
let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
|
||||
fn read<F: CanHeader>(
|
||||
&self,
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
) -> Option<Result<(F, Timestamp), BusError>> {
|
||||
if let Some((msg, ts)) = info.regs.read(0) {
|
||||
let ts = info.calc_timestamp(state.ns_per_timer_tick, ts);
|
||||
Some(Ok((msg, ts)))
|
||||
} else if let Some((msg, ts)) = T::registers().read(1) {
|
||||
let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
|
||||
} else if let Some((msg, ts)) = info.regs.read(1) {
|
||||
let ts = info.calc_timestamp(state.ns_per_timer_tick, ts);
|
||||
Some(Ok((msg, ts)))
|
||||
} else if let Some(err) = T::registers().curr_error() {
|
||||
} else if let Some(err) = info.regs.curr_error() {
|
||||
// TODO: this is probably wrong
|
||||
Some(Err(err))
|
||||
} else {
|
||||
@ -727,11 +765,16 @@ impl RxMode {
|
||||
}
|
||||
}
|
||||
|
||||
async fn read_async<T: Instance, F: CanHeader>(&self) -> Result<(F, Timestamp), BusError> {
|
||||
poll_fn(|cx| {
|
||||
T::state().err_waker.register(cx.waker());
|
||||
async fn read_async<F: CanHeader>(
|
||||
&self,
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
) -> Result<(F, Timestamp), BusError> {
|
||||
//let _ = self.read::<F>(info, state);
|
||||
poll_fn(move |cx| {
|
||||
state.err_waker.register(cx.waker());
|
||||
self.register(cx.waker());
|
||||
match self.read::<T, _>() {
|
||||
match self.read::<_>(info, state) {
|
||||
Some(result) => Poll::Ready(result),
|
||||
None => Poll::Pending,
|
||||
}
|
||||
@ -739,15 +782,15 @@ impl RxMode {
|
||||
.await
|
||||
}
|
||||
|
||||
async fn read_classic<T: Instance>(&self) -> Result<Envelope, BusError> {
|
||||
match self.read_async::<T, _>().await {
|
||||
async fn read_classic(&self, info: &'static Info, state: &'static State) -> Result<Envelope, BusError> {
|
||||
match self.read_async::<_>(info, state).await {
|
||||
Ok((frame, ts)) => Ok(Envelope { ts, frame }),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
async fn read_fd<T: Instance>(&self) -> Result<FdEnvelope, BusError> {
|
||||
match self.read_async::<T, _>().await {
|
||||
async fn read_fd(&self, info: &'static Info, state: &'static State) -> Result<FdEnvelope, BusError> {
|
||||
match self.read_async::<_>(info, state).await {
|
||||
Ok((frame, ts)) => Ok(FdEnvelope { ts, frame }),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
@ -776,11 +819,11 @@ impl TxMode {
|
||||
/// frame is dropped from the mailbox, it is returned. If no lower-priority frames
|
||||
/// can be replaced, this call asynchronously waits for a frame to be successfully
|
||||
/// transmitted, then tries again.
|
||||
async fn write_generic<T: Instance, F: embedded_can::Frame + CanHeader>(&self, frame: &F) -> Option<F> {
|
||||
async fn write_generic<F: embedded_can::Frame + CanHeader>(&self, info: &'static Info, frame: &F) -> Option<F> {
|
||||
poll_fn(|cx| {
|
||||
self.register(cx.waker());
|
||||
|
||||
if let Ok(dropped) = T::registers().write(frame) {
|
||||
if let Ok(dropped) = info.regs.write(frame) {
|
||||
return Poll::Ready(dropped);
|
||||
}
|
||||
|
||||
@ -795,68 +838,70 @@ impl TxMode {
|
||||
/// frame is dropped from the mailbox, it is returned. If no lower-priority frames
|
||||
/// can be replaced, this call asynchronously waits for a frame to be successfully
|
||||
/// transmitted, then tries again.
|
||||
async fn write<T: Instance>(&self, frame: &Frame) -> Option<Frame> {
|
||||
self.write_generic::<T, _>(frame).await
|
||||
async fn write(&self, info: &'static Info, frame: &Frame) -> Option<Frame> {
|
||||
self.write_generic::<_>(info, frame).await
|
||||
}
|
||||
|
||||
/// Queues the message to be sent but exerts backpressure. If a lower-priority
|
||||
/// frame is dropped from the mailbox, it is returned. If no lower-priority frames
|
||||
/// can be replaced, this call asynchronously waits for a frame to be successfully
|
||||
/// transmitted, then tries again.
|
||||
async fn write_fd<T: Instance>(&self, frame: &FdFrame) -> Option<FdFrame> {
|
||||
self.write_generic::<T, _>(frame).await
|
||||
async fn write_fd(&self, info: &'static Info, frame: &FdFrame) -> Option<FdFrame> {
|
||||
self.write_generic::<_>(info, frame).await
|
||||
}
|
||||
}
|
||||
|
||||
/// Common driver properties, including filters and error counters
|
||||
pub struct Properties<T> {
|
||||
pub struct Properties {
|
||||
info: &'static Info,
|
||||
// phantom pointer to ensure !Sync
|
||||
instance: PhantomData<*const T>,
|
||||
//instance: PhantomData<*const T>,
|
||||
}
|
||||
|
||||
impl<T: Instance> Properties<T> {
|
||||
fn new() -> Self {
|
||||
impl Properties {
|
||||
fn new(info: &'static Info) -> Self {
|
||||
Self {
|
||||
instance: Default::default(),
|
||||
info,
|
||||
//instance: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set a standard address CAN filter in the specified slot in FDCAN memory.
|
||||
#[inline]
|
||||
pub fn set_standard_filter(&self, slot: StandardFilterSlot, filter: StandardFilter) {
|
||||
T::registers().msg_ram_mut().filters.flssa[slot as usize].activate(filter);
|
||||
self.info.regs.msg_ram_mut().filters.flssa[slot as usize].activate(filter);
|
||||
}
|
||||
|
||||
/// Set the full array of standard address CAN filters in FDCAN memory.
|
||||
/// Overwrites all standard address filters in memory.
|
||||
pub fn set_standard_filters(&self, filters: &[StandardFilter; STANDARD_FILTER_MAX as usize]) {
|
||||
for (i, f) in filters.iter().enumerate() {
|
||||
T::registers().msg_ram_mut().filters.flssa[i].activate(*f);
|
||||
self.info.regs.msg_ram_mut().filters.flssa[i].activate(*f);
|
||||
}
|
||||
}
|
||||
|
||||
/// Set an extended address CAN filter in the specified slot in FDCAN memory.
|
||||
#[inline]
|
||||
pub fn set_extended_filter(&self, slot: ExtendedFilterSlot, filter: ExtendedFilter) {
|
||||
T::registers().msg_ram_mut().filters.flesa[slot as usize].activate(filter);
|
||||
self.info.regs.msg_ram_mut().filters.flesa[slot as usize].activate(filter);
|
||||
}
|
||||
|
||||
/// Set the full array of extended address CAN filters in FDCAN memory.
|
||||
/// Overwrites all extended address filters in memory.
|
||||
pub fn set_extended_filters(&self, filters: &[ExtendedFilter; EXTENDED_FILTER_MAX as usize]) {
|
||||
for (i, f) in filters.iter().enumerate() {
|
||||
T::registers().msg_ram_mut().filters.flesa[i].activate(*f);
|
||||
self.info.regs.msg_ram_mut().filters.flesa[i].activate(*f);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the CAN RX error counter
|
||||
pub fn rx_error_count(&self) -> u8 {
|
||||
T::regs().ecr().read().rec()
|
||||
self.info.regs.regs.ecr().read().rec()
|
||||
}
|
||||
|
||||
/// Get the CAN TX error counter
|
||||
pub fn tx_error_count(&self) -> u8 {
|
||||
T::regs().ecr().read().tec()
|
||||
self.info.regs.regs.ecr().read().tec()
|
||||
}
|
||||
|
||||
/// Get the current bus error mode
|
||||
@ -864,7 +909,7 @@ impl<T: Instance> Properties<T> {
|
||||
// This read will clear LEC and DLEC. This is not ideal, but protocol
|
||||
// error reporting in this driver should have a big ol' FIXME on it
|
||||
// anyway!
|
||||
let psr = T::regs().psr().read();
|
||||
let psr = self.info.regs.regs.psr().read();
|
||||
match (psr.bo(), psr.ep()) {
|
||||
(false, false) => BusErrorMode::ErrorActive,
|
||||
(false, true) => BusErrorMode::ErrorPassive,
|
||||
@ -892,10 +937,36 @@ impl State {
|
||||
}
|
||||
}
|
||||
|
||||
struct Info {
|
||||
regs: Registers,
|
||||
interrupt0: crate::interrupt::Interrupt,
|
||||
_interrupt1: crate::interrupt::Interrupt,
|
||||
tx_waker: fn(),
|
||||
}
|
||||
|
||||
impl Info {
|
||||
#[cfg(feature = "time")]
|
||||
fn calc_timestamp(&self, ns_per_timer_tick: u64, ts_val: u16) -> Timestamp {
|
||||
let now_embassy = embassy_time::Instant::now();
|
||||
if ns_per_timer_tick == 0 {
|
||||
return now_embassy;
|
||||
}
|
||||
let cantime = { self.regs.regs.tscv().read().tsc() };
|
||||
let delta = cantime.overflowing_sub(ts_val).0 as u64;
|
||||
let ns = ns_per_timer_tick * delta as u64;
|
||||
now_embassy - embassy_time::Duration::from_nanos(ns)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "time"))]
|
||||
fn calc_timestamp(&self, _ns_per_timer_tick: u64, ts_val: u16) -> Timestamp {
|
||||
ts_val
|
||||
}
|
||||
}
|
||||
|
||||
trait SealedInstance {
|
||||
const MSG_RAM_OFFSET: usize;
|
||||
|
||||
fn regs() -> &'static crate::pac::can::Fdcan;
|
||||
fn info() -> &'static Info;
|
||||
fn registers() -> crate::can::fd::peripheral::Registers;
|
||||
fn state() -> &'static State;
|
||||
unsafe fn mut_state() -> &'static mut State;
|
||||
@ -915,15 +986,23 @@ pub trait Instance: SealedInstance + RccPeripheral + 'static {
|
||||
pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>);
|
||||
|
||||
macro_rules! impl_fdcan {
|
||||
($inst:ident, $msg_ram_inst:ident, $msg_ram_offset:literal) => {
|
||||
($inst:ident,
|
||||
//$irq0:ident, $irq1:ident,
|
||||
$msg_ram_inst:ident, $msg_ram_offset:literal) => {
|
||||
impl SealedInstance for peripherals::$inst {
|
||||
const MSG_RAM_OFFSET: usize = $msg_ram_offset;
|
||||
|
||||
fn regs() -> &'static crate::pac::can::Fdcan {
|
||||
&crate::pac::$inst
|
||||
fn info() -> &'static Info {
|
||||
static INFO: Info = Info {
|
||||
regs: Registers{regs: crate::pac::$inst, msgram: crate::pac::$msg_ram_inst, msg_ram_offset: $msg_ram_offset},
|
||||
interrupt0: crate::_generated::peripheral_interrupts::$inst::IT0::IRQ,
|
||||
_interrupt1: crate::_generated::peripheral_interrupts::$inst::IT1::IRQ,
|
||||
tx_waker: crate::_generated::peripheral_interrupts::$inst::IT0::pend,
|
||||
};
|
||||
&INFO
|
||||
}
|
||||
fn registers() -> Registers {
|
||||
Registers{regs: &crate::pac::$inst, msgram: &crate::pac::$msg_ram_inst, msg_ram_offset: Self::MSG_RAM_OFFSET}
|
||||
Registers{regs: crate::pac::$inst, msgram: crate::pac::$msg_ram_inst, msg_ram_offset: Self::MSG_RAM_OFFSET}
|
||||
}
|
||||
unsafe fn mut_state() -> &'static mut State {
|
||||
static mut STATE: State = State::new();
|
||||
@ -939,7 +1018,7 @@ macro_rules! impl_fdcan {
|
||||
if ns_per_timer_tick == 0 {
|
||||
return now_embassy;
|
||||
}
|
||||
let cantime = { Self::regs().tscv().read().tsc() };
|
||||
let cantime = { Self::registers().regs.tscv().read().tsc() };
|
||||
let delta = cantime.overflowing_sub(ts_val).0 as u64;
|
||||
let ns = ns_per_timer_tick * delta as u64;
|
||||
now_embassy - embassy_time::Duration::from_nanos(ns)
|
||||
|
@ -4,7 +4,7 @@ use embassy_hal_internal::drop::OnDrop;
|
||||
use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
|
||||
|
||||
use crate::pac::cordic::vals;
|
||||
use crate::{dma, peripherals};
|
||||
use crate::{dma, peripherals, rcc};
|
||||
|
||||
mod enums;
|
||||
pub use enums::*;
|
||||
@ -199,7 +199,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
|
||||
/// If you need a peripheral -> CORDIC -> peripheral mode,
|
||||
/// you may want to set Cordic into [Mode::ZeroOverhead] mode, and add extra arguments with [Self::extra_config]
|
||||
pub fn new(peri: impl Peripheral<P = T> + 'd, config: Config) -> Self {
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
|
||||
into_ref!(peri);
|
||||
|
||||
@ -259,7 +259,7 @@ impl<'d, T: Instance> Cordic<'d, T> {
|
||||
|
||||
impl<'d, T: Instance> Drop for Cordic<'d, T> {
|
||||
fn drop(&mut self) {
|
||||
T::disable();
|
||||
rcc::disable::<T>();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
|
||||
use crate::pac::CRC as PAC_CRC;
|
||||
use crate::peripherals::CRC;
|
||||
use crate::rcc::SealedRccPeripheral;
|
||||
use crate::Peripheral;
|
||||
use crate::{rcc, Peripheral};
|
||||
|
||||
/// CRC driver.
|
||||
pub struct Crc<'d> {
|
||||
@ -17,7 +16,7 @@ impl<'d> Crc<'d> {
|
||||
|
||||
// Note: enable and reset come from RccPeripheral.
|
||||
// enable CRC clock in RCC.
|
||||
CRC::enable_and_reset();
|
||||
rcc::enable_and_reset::<CRC>();
|
||||
// Peripheral the peripheral
|
||||
let mut instance = Self { _peri: peripheral };
|
||||
instance.reset();
|
||||
|
@ -3,8 +3,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use crate::pac::crc::vals;
|
||||
use crate::pac::CRC as PAC_CRC;
|
||||
use crate::peripherals::CRC;
|
||||
use crate::rcc::SealedRccPeripheral;
|
||||
use crate::Peripheral;
|
||||
use crate::{rcc, Peripheral};
|
||||
|
||||
/// CRC driver.
|
||||
pub struct Crc<'d> {
|
||||
@ -84,7 +83,7 @@ impl<'d> Crc<'d> {
|
||||
pub fn new(peripheral: impl Peripheral<P = CRC> + 'd, config: Config) -> Self {
|
||||
// Note: enable and reset come from RccPeripheral.
|
||||
// reset to default values and enable CRC clock in RCC.
|
||||
CRC::enable_and_reset();
|
||||
rcc::enable_and_reset::<CRC>();
|
||||
into_ref!(peripheral);
|
||||
let mut instance = Self {
|
||||
_peripheral: peripheral,
|
||||
|
@ -9,7 +9,7 @@ use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use crate::dma::{NoDma, Transfer, TransferOptions};
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::{interrupt, pac, peripherals, Peripheral};
|
||||
use crate::{interrupt, pac, peripherals, rcc, Peripheral};
|
||||
|
||||
const DES_BLOCK_SIZE: usize = 8; // 64 bits
|
||||
const AES_BLOCK_SIZE: usize = 16; // 128 bits
|
||||
@ -51,16 +51,16 @@ pub trait Cipher<'c> {
|
||||
fn iv(&self) -> &[u8];
|
||||
|
||||
/// Sets the processor algorithm mode according to the associated cipher.
|
||||
fn set_algomode(&self, p: &pac::cryp::Cryp);
|
||||
fn set_algomode(&self, p: pac::cryp::Cryp);
|
||||
|
||||
/// Performs any key preparation within the processor, if necessary.
|
||||
fn prepare_key(&self, _p: &pac::cryp::Cryp) {}
|
||||
fn prepare_key(&self, _p: pac::cryp::Cryp) {}
|
||||
|
||||
/// Performs any cipher-specific initialization.
|
||||
fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, _p: &pac::cryp::Cryp, _cryp: &Cryp<T, DmaIn, DmaOut>) {}
|
||||
fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, _p: pac::cryp::Cryp, _cryp: &Cryp<T, DmaIn, DmaOut>) {}
|
||||
|
||||
/// Performs any cipher-specific initialization.
|
||||
async fn init_phase<T: Instance, DmaIn, DmaOut>(&self, _p: &pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>)
|
||||
async fn init_phase<T: Instance, DmaIn, DmaOut>(&self, _p: pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>)
|
||||
where
|
||||
DmaIn: crate::cryp::DmaIn<T>,
|
||||
DmaOut: crate::cryp::DmaOut<T>,
|
||||
@ -68,14 +68,14 @@ pub trait Cipher<'c> {
|
||||
}
|
||||
|
||||
/// Called prior to processing the last data block for cipher-specific operations.
|
||||
fn pre_final(&self, _p: &pac::cryp::Cryp, _dir: Direction, _padding_len: usize) -> [u32; 4] {
|
||||
fn pre_final(&self, _p: pac::cryp::Cryp, _dir: Direction, _padding_len: usize) -> [u32; 4] {
|
||||
return [0; 4];
|
||||
}
|
||||
|
||||
/// Called after processing the last data block for cipher-specific operations.
|
||||
fn post_final_blocking<T: Instance, DmaIn, DmaOut>(
|
||||
&self,
|
||||
_p: &pac::cryp::Cryp,
|
||||
_p: pac::cryp::Cryp,
|
||||
_cryp: &Cryp<T, DmaIn, DmaOut>,
|
||||
_dir: Direction,
|
||||
_int_data: &mut [u8; AES_BLOCK_SIZE],
|
||||
@ -87,7 +87,7 @@ pub trait Cipher<'c> {
|
||||
/// Called after processing the last data block for cipher-specific operations.
|
||||
async fn post_final<T: Instance, DmaIn, DmaOut>(
|
||||
&self,
|
||||
_p: &pac::cryp::Cryp,
|
||||
_p: pac::cryp::Cryp,
|
||||
_cryp: &mut Cryp<'_, T, DmaIn, DmaOut>,
|
||||
_dir: Direction,
|
||||
_int_data: &mut [u8; AES_BLOCK_SIZE],
|
||||
@ -142,7 +142,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for TdesEcb<'c, KEY_SIZE> {
|
||||
self.iv
|
||||
}
|
||||
|
||||
fn set_algomode(&self, p: &pac::cryp::Cryp) {
|
||||
fn set_algomode(&self, p: pac::cryp::Cryp) {
|
||||
#[cfg(cryp_v1)]
|
||||
{
|
||||
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> {
|
||||
self.iv
|
||||
}
|
||||
|
||||
fn set_algomode(&self, p: &pac::cryp::Cryp) {
|
||||
fn set_algomode(&self, p: pac::cryp::Cryp) {
|
||||
#[cfg(cryp_v1)]
|
||||
{
|
||||
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> {
|
||||
self.iv
|
||||
}
|
||||
|
||||
fn set_algomode(&self, p: &pac::cryp::Cryp) {
|
||||
fn set_algomode(&self, p: pac::cryp::Cryp) {
|
||||
#[cfg(cryp_v1)]
|
||||
{
|
||||
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> {
|
||||
self.iv
|
||||
}
|
||||
|
||||
fn set_algomode(&self, p: &pac::cryp::Cryp) {
|
||||
fn set_algomode(&self, p: pac::cryp::Cryp) {
|
||||
#[cfg(cryp_v1)]
|
||||
{
|
||||
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> {
|
||||
self.iv
|
||||
}
|
||||
|
||||
fn prepare_key(&self, p: &pac::cryp::Cryp) {
|
||||
fn prepare_key(&self, p: pac::cryp::Cryp) {
|
||||
#[cfg(cryp_v1)]
|
||||
{
|
||||
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> {
|
||||
while p.sr().read().busy() {}
|
||||
}
|
||||
|
||||
fn set_algomode(&self, p: &pac::cryp::Cryp) {
|
||||
fn set_algomode(&self, p: pac::cryp::Cryp) {
|
||||
#[cfg(cryp_v1)]
|
||||
{
|
||||
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> {
|
||||
self.iv
|
||||
}
|
||||
|
||||
fn prepare_key(&self, p: &pac::cryp::Cryp) {
|
||||
fn prepare_key(&self, p: pac::cryp::Cryp) {
|
||||
#[cfg(cryp_v1)]
|
||||
{
|
||||
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> {
|
||||
while p.sr().read().busy() {}
|
||||
}
|
||||
|
||||
fn set_algomode(&self, p: &pac::cryp::Cryp) {
|
||||
fn set_algomode(&self, p: pac::cryp::Cryp) {
|
||||
#[cfg(cryp_v1)]
|
||||
{
|
||||
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> {
|
||||
self.iv
|
||||
}
|
||||
|
||||
fn set_algomode(&self, p: &pac::cryp::Cryp) {
|
||||
fn set_algomode(&self, p: pac::cryp::Cryp) {
|
||||
#[cfg(cryp_v1)]
|
||||
{
|
||||
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> {
|
||||
self.iv.as_slice()
|
||||
}
|
||||
|
||||
fn set_algomode(&self, p: &pac::cryp::Cryp) {
|
||||
fn set_algomode(&self, p: pac::cryp::Cryp) {
|
||||
p.cr().modify(|w| w.set_algomode0(0));
|
||||
p.cr().modify(|w| w.set_algomode3(true));
|
||||
}
|
||||
|
||||
fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, p: &pac::cryp::Cryp, _cryp: &Cryp<T, DmaIn, DmaOut>) {
|
||||
fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, p: pac::cryp::Cryp, _cryp: &Cryp<T, DmaIn, DmaOut>) {
|
||||
p.cr().modify(|w| w.set_gcm_ccmph(0));
|
||||
p.cr().modify(|w| w.set_crypen(true));
|
||||
while p.cr().read().crypen() {}
|
||||
}
|
||||
|
||||
async fn init_phase<T: Instance, DmaIn, DmaOut>(
|
||||
&self,
|
||||
p: &pac::cryp::Cryp,
|
||||
_cryp: &mut Cryp<'_, T, DmaIn, DmaOut>,
|
||||
) {
|
||||
async fn init_phase<T: Instance, DmaIn, DmaOut>(&self, p: pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) {
|
||||
p.cr().modify(|w| w.set_gcm_ccmph(0));
|
||||
p.cr().modify(|w| w.set_crypen(true));
|
||||
while p.cr().read().crypen() {}
|
||||
}
|
||||
|
||||
#[cfg(cryp_v2)]
|
||||
fn pre_final(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] {
|
||||
fn pre_final(&self, p: pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] {
|
||||
//Handle special GCM partial block process.
|
||||
if dir == Direction::Encrypt {
|
||||
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> {
|
||||
}
|
||||
|
||||
#[cfg(any(cryp_v3, cryp_v4))]
|
||||
fn pre_final(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] {
|
||||
fn pre_final(&self, p: pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] {
|
||||
//Handle special GCM partial block process.
|
||||
p.cr().modify(|w| w.set_npblb(padding_len as u8));
|
||||
[0; 4]
|
||||
@ -514,7 +510,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
|
||||
#[cfg(cryp_v2)]
|
||||
fn post_final_blocking<T: Instance, DmaIn, DmaOut>(
|
||||
&self,
|
||||
p: &pac::cryp::Cryp,
|
||||
p: pac::cryp::Cryp,
|
||||
cryp: &Cryp<T, DmaIn, DmaOut>,
|
||||
dir: Direction,
|
||||
int_data: &mut [u8; AES_BLOCK_SIZE],
|
||||
@ -540,7 +536,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGcm<'c, KEY_SIZE> {
|
||||
#[cfg(cryp_v2)]
|
||||
async fn post_final<T: Instance, DmaIn, DmaOut>(
|
||||
&self,
|
||||
p: &pac::cryp::Cryp,
|
||||
p: pac::cryp::Cryp,
|
||||
cryp: &mut Cryp<'_, T, DmaIn, DmaOut>,
|
||||
dir: Direction,
|
||||
int_data: &mut [u8; AES_BLOCK_SIZE],
|
||||
@ -614,29 +610,25 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
|
||||
self.iv.as_slice()
|
||||
}
|
||||
|
||||
fn set_algomode(&self, p: &pac::cryp::Cryp) {
|
||||
fn set_algomode(&self, p: pac::cryp::Cryp) {
|
||||
p.cr().modify(|w| w.set_algomode0(0));
|
||||
p.cr().modify(|w| w.set_algomode3(true));
|
||||
}
|
||||
|
||||
fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, p: &pac::cryp::Cryp, _cryp: &Cryp<T, DmaIn, DmaOut>) {
|
||||
fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, p: pac::cryp::Cryp, _cryp: &Cryp<T, DmaIn, DmaOut>) {
|
||||
p.cr().modify(|w| w.set_gcm_ccmph(0));
|
||||
p.cr().modify(|w| w.set_crypen(true));
|
||||
while p.cr().read().crypen() {}
|
||||
}
|
||||
|
||||
async fn init_phase<T: Instance, DmaIn, DmaOut>(
|
||||
&self,
|
||||
p: &pac::cryp::Cryp,
|
||||
_cryp: &mut Cryp<'_, T, DmaIn, DmaOut>,
|
||||
) {
|
||||
async fn init_phase<T: Instance, DmaIn, DmaOut>(&self, p: pac::cryp::Cryp, _cryp: &mut Cryp<'_, T, DmaIn, DmaOut>) {
|
||||
p.cr().modify(|w| w.set_gcm_ccmph(0));
|
||||
p.cr().modify(|w| w.set_crypen(true));
|
||||
while p.cr().read().crypen() {}
|
||||
}
|
||||
|
||||
#[cfg(cryp_v2)]
|
||||
fn pre_final(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] {
|
||||
fn pre_final(&self, p: pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] {
|
||||
//Handle special GCM partial block process.
|
||||
if dir == Direction::Encrypt {
|
||||
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> {
|
||||
}
|
||||
|
||||
#[cfg(any(cryp_v3, cryp_v4))]
|
||||
fn pre_final(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] {
|
||||
fn pre_final(&self, p: pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] {
|
||||
//Handle special GCM partial block process.
|
||||
p.cr().modify(|w| w.set_npblb(padding_len as u8));
|
||||
[0; 4]
|
||||
@ -659,7 +651,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
|
||||
#[cfg(cryp_v2)]
|
||||
fn post_final_blocking<T: Instance, DmaIn, DmaOut>(
|
||||
&self,
|
||||
p: &pac::cryp::Cryp,
|
||||
p: pac::cryp::Cryp,
|
||||
cryp: &Cryp<T, DmaIn, DmaOut>,
|
||||
dir: Direction,
|
||||
int_data: &mut [u8; AES_BLOCK_SIZE],
|
||||
@ -685,7 +677,7 @@ impl<'c, const KEY_SIZE: usize> Cipher<'c> for AesGmac<'c, KEY_SIZE> {
|
||||
#[cfg(cryp_v2)]
|
||||
async fn post_final<T: Instance, DmaIn, DmaOut>(
|
||||
&self,
|
||||
p: &pac::cryp::Cryp,
|
||||
p: pac::cryp::Cryp,
|
||||
cryp: &mut Cryp<'_, T, DmaIn, DmaOut>,
|
||||
dir: Direction,
|
||||
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
|
||||
} else {
|
||||
aad_header[0] = 0xFF;
|
||||
aad_header[1] = 0xFE;
|
||||
let aad_len_bytes: [u8; 4] = aad_len.to_be_bytes();
|
||||
let aad_len_bytes: [u8; 4] = (aad_len as u32).to_be_bytes();
|
||||
aad_header[2] = aad_len_bytes[0];
|
||||
aad_header[3] = aad_len_bytes[1];
|
||||
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
|
||||
block0[0] |= ((((TAG_SIZE as u8) - 2) >> 1) & 0x07) << 3;
|
||||
block0[0] |= ((15 - (iv.len() as u8)) - 1) & 0x07;
|
||||
block0[1..1 + iv.len()].copy_from_slice(iv);
|
||||
let payload_len_bytes: [u8; 4] = payload_len.to_be_bytes();
|
||||
let payload_len_bytes: [u8; 4] = (payload_len as u32).to_be_bytes();
|
||||
if iv.len() <= 11 {
|
||||
block0[12] = payload_len_bytes[0];
|
||||
} 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
|
||||
self.ctr.as_slice()
|
||||
}
|
||||
|
||||
fn set_algomode(&self, p: &pac::cryp::Cryp) {
|
||||
fn set_algomode(&self, p: pac::cryp::Cryp) {
|
||||
p.cr().modify(|w| w.set_algomode0(1));
|
||||
p.cr().modify(|w| w.set_algomode3(true));
|
||||
}
|
||||
|
||||
fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, p: &pac::cryp::Cryp, cryp: &Cryp<T, DmaIn, DmaOut>) {
|
||||
fn init_phase_blocking<T: Instance, DmaIn, DmaOut>(&self, p: pac::cryp::Cryp, cryp: &Cryp<T, DmaIn, DmaOut>) {
|
||||
p.cr().modify(|w| w.set_gcm_ccmph(0));
|
||||
|
||||
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
|
||||
while p.cr().read().crypen() {}
|
||||
}
|
||||
|
||||
async fn init_phase<T: Instance, DmaIn, DmaOut>(&self, p: &pac::cryp::Cryp, cryp: &mut Cryp<'_, T, DmaIn, DmaOut>)
|
||||
async fn init_phase<T: Instance, DmaIn, DmaOut>(&self, p: pac::cryp::Cryp, cryp: &mut Cryp<'_, T, DmaIn, DmaOut>)
|
||||
where
|
||||
DmaIn: crate::cryp::DmaIn<T>,
|
||||
DmaOut: crate::cryp::DmaOut<T>,
|
||||
@ -847,7 +839,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip
|
||||
}
|
||||
|
||||
#[cfg(cryp_v2)]
|
||||
fn pre_final(&self, p: &pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] {
|
||||
fn pre_final(&self, p: pac::cryp::Cryp, dir: Direction, _padding_len: usize) -> [u32; 4] {
|
||||
//Handle special CCM partial block process.
|
||||
let mut temp1 = [0; 4];
|
||||
if dir == Direction::Decrypt {
|
||||
@ -866,7 +858,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip
|
||||
}
|
||||
|
||||
#[cfg(any(cryp_v3, cryp_v4))]
|
||||
fn pre_final(&self, p: &pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] {
|
||||
fn pre_final(&self, p: pac::cryp::Cryp, _dir: Direction, padding_len: usize) -> [u32; 4] {
|
||||
//Handle special GCM partial block process.
|
||||
p.cr().modify(|w| w.set_npblb(padding_len as u8));
|
||||
[0; 4]
|
||||
@ -875,7 +867,7 @@ impl<'c, const KEY_SIZE: usize, const TAG_SIZE: usize, const IV_SIZE: usize> Cip
|
||||
#[cfg(cryp_v2)]
|
||||
fn post_final_blocking<T: Instance, DmaIn, DmaOut>(
|
||||
&self,
|
||||
p: &pac::cryp::Cryp,
|
||||
p: pac::cryp::Cryp,
|
||||
cryp: &Cryp<T, DmaIn, DmaOut>,
|
||||
dir: Direction,
|
||||
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
|
||||
#[cfg(cryp_v2)]
|
||||
async fn post_final<T: Instance, DmaIn, DmaOut>(
|
||||
&self,
|
||||
p: &pac::cryp::Cryp,
|
||||
p: pac::cryp::Cryp,
|
||||
cryp: &mut Cryp<'_, T, DmaIn, DmaOut>,
|
||||
dir: Direction,
|
||||
int_data: &mut [u8; AES_BLOCK_SIZE],
|
||||
@ -1029,7 +1021,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
|
||||
outdma: impl Peripheral<P = DmaOut> + 'd,
|
||||
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
) -> Self {
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
into_ref!(peri, indma, outdma);
|
||||
let instance = Self {
|
||||
_peripheral: peri,
|
||||
@ -1083,9 +1075,9 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
|
||||
// Set data type to 8-bit. This will match software implementations.
|
||||
T::regs().cr().modify(|w| w.set_datatype(2));
|
||||
|
||||
ctx.cipher.prepare_key(&T::regs());
|
||||
ctx.cipher.prepare_key(T::regs());
|
||||
|
||||
ctx.cipher.set_algomode(&T::regs());
|
||||
ctx.cipher.set_algomode(T::regs());
|
||||
|
||||
// Set encrypt/decrypt
|
||||
if dir == Direction::Encrypt {
|
||||
@ -1115,7 +1107,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
|
||||
// Flush in/out FIFOs
|
||||
T::regs().cr().modify(|w| w.fflush());
|
||||
|
||||
ctx.cipher.init_phase_blocking(&T::regs(), self);
|
||||
ctx.cipher.init_phase_blocking(T::regs(), self);
|
||||
|
||||
self.store_context(&mut ctx);
|
||||
|
||||
@ -1166,9 +1158,9 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
|
||||
// Set data type to 8-bit. This will match software implementations.
|
||||
T::regs().cr().modify(|w| w.set_datatype(2));
|
||||
|
||||
ctx.cipher.prepare_key(&T::regs());
|
||||
ctx.cipher.prepare_key(T::regs());
|
||||
|
||||
ctx.cipher.set_algomode(&T::regs());
|
||||
ctx.cipher.set_algomode(T::regs());
|
||||
|
||||
// Set encrypt/decrypt
|
||||
if dir == Direction::Encrypt {
|
||||
@ -1198,7 +1190,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
|
||||
// Flush in/out FIFOs
|
||||
T::regs().cr().modify(|w| w.fflush());
|
||||
|
||||
ctx.cipher.init_phase(&T::regs(), self).await;
|
||||
ctx.cipher.init_phase(T::regs(), self).await;
|
||||
|
||||
self.store_context(&mut ctx);
|
||||
|
||||
@ -1462,7 +1454,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
|
||||
// Handle the final block, which is incomplete.
|
||||
if last_block_remainder > 0 {
|
||||
let padding_len = C::BLOCK_SIZE - last_block_remainder;
|
||||
let temp1 = ctx.cipher.pre_final(&T::regs(), ctx.dir, padding_len);
|
||||
let temp1 = ctx.cipher.pre_final(T::regs(), ctx.dir, padding_len);
|
||||
|
||||
let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
|
||||
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> {
|
||||
let mut mask: [u8; 16] = [0; 16];
|
||||
mask[..last_block_remainder].fill(0xFF);
|
||||
ctx.cipher
|
||||
.post_final_blocking(&T::regs(), self, ctx.dir, &mut intermediate_data, temp1, mask);
|
||||
.post_final_blocking(T::regs(), self, ctx.dir, &mut intermediate_data, temp1, mask);
|
||||
}
|
||||
|
||||
ctx.payload_len += input.len() as u64;
|
||||
@ -1559,7 +1551,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
|
||||
// Handle the final block, which is incomplete.
|
||||
if last_block_remainder > 0 {
|
||||
let padding_len = C::BLOCK_SIZE - last_block_remainder;
|
||||
let temp1 = ctx.cipher.pre_final(&T::regs(), ctx.dir, padding_len);
|
||||
let temp1 = ctx.cipher.pre_final(T::regs(), ctx.dir, padding_len);
|
||||
|
||||
let mut intermediate_data: [u8; AES_BLOCK_SIZE] = [0; AES_BLOCK_SIZE];
|
||||
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> {
|
||||
let mut mask: [u8; 16] = [0; 16];
|
||||
mask[..last_block_remainder].fill(0xFF);
|
||||
ctx.cipher
|
||||
.post_final(&T::regs(), self, ctx.dir, &mut intermediate_data, temp1, mask)
|
||||
.post_final(T::regs(), self, ctx.dir, &mut intermediate_data, temp1, mask)
|
||||
.await;
|
||||
}
|
||||
|
||||
@ -1758,7 +1750,7 @@ impl<'d, T: Instance, DmaIn, DmaOut> Cryp<'d, T, DmaIn, DmaOut> {
|
||||
self.load_key(ctx.cipher.key());
|
||||
|
||||
// Prepare key if applicable.
|
||||
ctx.cipher.prepare_key(&T::regs());
|
||||
ctx.cipher.prepare_key(T::regs());
|
||||
T::regs().cr().write(|w| w.0 = ctx.cr);
|
||||
|
||||
// Enable crypto processor.
|
||||
|
@ -8,7 +8,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use crate::dma::NoDma;
|
||||
#[cfg(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7))]
|
||||
use crate::pac::dac;
|
||||
use crate::rcc::RccPeripheral;
|
||||
use crate::rcc::{self, RccPeripheral};
|
||||
use crate::{peripherals, Peripheral};
|
||||
|
||||
mod tsel;
|
||||
@ -131,7 +131,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
|
||||
) -> Self {
|
||||
into_ref!(dma, pin);
|
||||
pin.set_as_analog();
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
let mut dac = Self {
|
||||
phantom: PhantomData,
|
||||
dma,
|
||||
@ -157,7 +157,7 @@ impl<'d, T: Instance, const N: u8, DMA> DacChannel<'d, T, N, DMA> {
|
||||
#[cfg(all(any(dac_v3, dac_v4, dac_v5, dac_v6, dac_v7), not(any(stm32h56x, stm32h57x))))]
|
||||
pub fn new_internal(_peri: impl Peripheral<P = T> + 'd, dma: impl Peripheral<P = DMA> + 'd) -> Self {
|
||||
into_ref!(dma);
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
let mut dac = Self {
|
||||
phantom: PhantomData,
|
||||
dma,
|
||||
@ -356,7 +356,7 @@ impl_dma_methods!(2, DacDma2);
|
||||
|
||||
impl<'d, T: Instance, const N: u8, DMA> Drop for DacChannel<'d, T, N, DMA> {
|
||||
fn drop(&mut self) {
|
||||
T::disable();
|
||||
rcc::disable::<T>();
|
||||
}
|
||||
}
|
||||
|
||||
@ -400,8 +400,8 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
|
||||
pin_ch2.set_as_analog();
|
||||
|
||||
// Enable twice to increment the DAC refcount for each channel.
|
||||
T::enable_and_reset();
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
rcc::enable_and_reset::<T>();
|
||||
|
||||
let mut ch1 = DacCh1 {
|
||||
phantom: PhantomData,
|
||||
@ -444,8 +444,8 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
|
||||
) -> Self {
|
||||
into_ref!(dma_ch1, dma_ch2);
|
||||
// Enable twice to increment the DAC refcount for each channel.
|
||||
T::enable_and_reset();
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
rcc::enable_and_reset::<T>();
|
||||
|
||||
let mut ch1 = DacCh1 {
|
||||
phantom: PhantomData,
|
||||
@ -508,7 +508,7 @@ impl<'d, T: Instance, DMACh1, DMACh2> Dac<'d, T, DMACh1, DMACh2> {
|
||||
}
|
||||
|
||||
trait SealedInstance {
|
||||
fn regs() -> &'static crate::pac::dac::Dac;
|
||||
fn regs() -> crate::pac::dac::Dac;
|
||||
}
|
||||
|
||||
/// DAC instance.
|
||||
@ -523,8 +523,8 @@ pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
|
||||
foreach_peripheral!(
|
||||
(dac, $inst:ident) => {
|
||||
impl crate::dac::SealedInstance for peripherals::$inst {
|
||||
fn regs() -> &'static crate::pac::dac::Dac {
|
||||
&crate::pac::$inst
|
||||
fn regs() -> crate::pac::dac::Dac {
|
||||
crate::pac::$inst
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ use embassy_sync::waitqueue::AtomicWaker;
|
||||
use crate::dma::Transfer;
|
||||
use crate::gpio::{AFType, Speed};
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::{interrupt, Peripheral};
|
||||
use crate::{interrupt, rcc, Peripheral};
|
||||
|
||||
/// Interrupt handler.
|
||||
pub struct InterruptHandler<T: Instance> {
|
||||
@ -350,7 +350,7 @@ where
|
||||
use_embedded_synchronization: bool,
|
||||
edm: u8,
|
||||
) -> Self {
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
|
||||
peri.regs().cr().modify(|r| {
|
||||
r.set_cm(true); // disable continuous mode (snapshot mode)
|
||||
|
@ -48,6 +48,7 @@ impl<'d> ChannelAndRequest<'d> {
|
||||
Transfer::new_write_raw(&mut self.channel, self.request, buf, peri_addr, options)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub unsafe fn write_repeated<'a, W: Word>(
|
||||
&'a mut self,
|
||||
repeated: &'a W,
|
||||
|
@ -6,14 +6,14 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
|
||||
//use crate::gpio::{AnyPin, SealedPin};
|
||||
use crate::gpio::{AFType, AnyPin, Pull, Speed};
|
||||
use crate::rcc::RccPeripheral;
|
||||
use crate::rcc::{self, RccPeripheral};
|
||||
use crate::{peripherals, Peripheral};
|
||||
|
||||
/// Performs a busy-wait delay for a specified number of microseconds.
|
||||
pub fn blocking_delay_ms(ms: u32) {
|
||||
#[cfg(time)]
|
||||
embassy_time::block_for(embassy_time::Duration::from_millis(ms));
|
||||
#[cfg(not(time))]
|
||||
#[cfg(feature = "time")]
|
||||
embassy_time::block_for(embassy_time::Duration::from_millis(ms as u64));
|
||||
#[cfg(not(feature = "time"))]
|
||||
cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 1_000 * ms);
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@ impl<'d, T: Instance> DsiHost<'d, T> {
|
||||
pub fn new(_peri: impl Peripheral<P = T> + 'd, te: impl Peripheral<P = impl TePin<T>> + 'd) -> Self {
|
||||
into_ref!(te);
|
||||
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
|
||||
// Set Tearing Enable pin according to CubeMx example
|
||||
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> {
|
||||
}
|
||||
|
||||
trait SealedInstance: crate::rcc::SealedRccPeripheral {
|
||||
fn regs() -> &'static crate::pac::dsihost::Dsihost;
|
||||
fn regs() -> crate::pac::dsihost::Dsihost;
|
||||
}
|
||||
|
||||
/// DSI instance trait.
|
||||
@ -419,8 +419,8 @@ pin_trait!(TePin, Instance);
|
||||
foreach_peripheral!(
|
||||
(dsihost, $inst:ident) => {
|
||||
impl crate::dsihost::SealedInstance for peripherals::$inst {
|
||||
fn regs() -> &'static crate::pac::dsihost::Dsihost {
|
||||
&crate::pac::$inst
|
||||
fn regs() -> crate::pac::dsihost::Dsihost {
|
||||
crate::pac::$inst
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ pub enum FlashBank {
|
||||
#[cfg_attr(any(flash_f1, flash_f3), path = "f1f3.rs")]
|
||||
#[cfg_attr(flash_f4, path = "f4.rs")]
|
||||
#[cfg_attr(flash_f7, path = "f7.rs")]
|
||||
#[cfg_attr(any(flash_g0, flash_g4), path = "g.rs")]
|
||||
#[cfg_attr(any(flash_g0, flash_g4c2, flash_g4c3, flash_g4c4), path = "g.rs")]
|
||||
#[cfg_attr(flash_h7, path = "h7.rs")]
|
||||
#[cfg_attr(flash_h7ab, path = "h7.rs")]
|
||||
#[cfg_attr(flash_u5, path = "u5.rs")]
|
||||
@ -105,7 +105,7 @@ pub enum FlashBank {
|
||||
#[cfg_attr(
|
||||
not(any(
|
||||
flash_l0, flash_l1, flash_l4, flash_wl, flash_wb, flash_f0, flash_f1, flash_f3, flash_f4, flash_f7, flash_g0,
|
||||
flash_g4, flash_h7, flash_h7ab, flash_u5, flash_h50, flash_u0
|
||||
flash_g4c2, flash_g4c3, flash_g4c4, flash_h7, flash_h7ab, flash_u5, flash_h50, flash_u0
|
||||
)),
|
||||
path = "other.rs"
|
||||
)]
|
||||
|
@ -4,7 +4,7 @@ use core::marker::PhantomData;
|
||||
use embassy_hal_internal::into_ref;
|
||||
|
||||
use crate::gpio::{AFType, Pull, Speed};
|
||||
use crate::Peripheral;
|
||||
use crate::{rcc, Peripheral};
|
||||
|
||||
/// FMC driver
|
||||
pub struct Fmc<'d, T: Instance> {
|
||||
@ -27,7 +27,7 @@ where
|
||||
|
||||
/// Enable the FMC peripheral and reset it.
|
||||
pub fn enable(&mut self) {
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
}
|
||||
|
||||
/// Enable the memory controller on applicable chips.
|
||||
@ -35,7 +35,7 @@ where
|
||||
// fmc v1 and v2 does not have the fmcen bit
|
||||
// fsmc v1, v2 and v3 does not have the fmcen bit
|
||||
// This is a "not" because it is expected that all future versions have this bit
|
||||
#[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1, fmc_v4)))]
|
||||
#[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fmc_v4)))]
|
||||
T::REGS.bcr1().modify(|r| r.set_fmcen(true));
|
||||
#[cfg(any(fmc_v4))]
|
||||
T::REGS.nor_psram().bcr1().modify(|r| r.set_fmcen(true));
|
||||
@ -54,14 +54,14 @@ where
|
||||
const REGISTERS: *const () = T::REGS.as_ptr() as *const _;
|
||||
|
||||
fn enable(&mut self) {
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
}
|
||||
|
||||
fn memory_controller_enable(&mut self) {
|
||||
// fmc v1 and v2 does not have the fmcen bit
|
||||
// fsmc v1, v2 and v3 does not have the fmcen bit
|
||||
// This is a "not" because it is expected that all future versions have this bit
|
||||
#[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1, fmc_v4)))]
|
||||
#[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fmc_v4)))]
|
||||
T::REGS.bcr1().modify(|r| r.set_fmcen(true));
|
||||
#[cfg(any(fmc_v4))]
|
||||
T::REGS.nor_psram().bcr1().modify(|r| r.set_fmcen(true));
|
||||
@ -200,7 +200,7 @@ impl<'d, T: Instance> Fmc<'d, T> {
|
||||
));
|
||||
}
|
||||
|
||||
trait SealedInstance: crate::rcc::SealedRccPeripheral {
|
||||
trait SealedInstance: crate::rcc::RccPeripheral {
|
||||
const REGS: crate::pac::fmc::Fmc;
|
||||
}
|
||||
|
||||
|
@ -822,7 +822,7 @@ foreach_pin!(
|
||||
|
||||
pub(crate) unsafe fn init(_cs: CriticalSection) {
|
||||
#[cfg(afio)]
|
||||
<crate::peripherals::AFIO as crate::rcc::SealedRccPeripheral>::enable_and_reset_with_cs(_cs);
|
||||
crate::rcc::enable_and_reset_with_cs::<crate::peripherals::AFIO>(_cs);
|
||||
|
||||
crate::_generated::init_gpio();
|
||||
}
|
||||
|
@ -17,8 +17,7 @@ use crate::dma::NoDma;
|
||||
use crate::dma::Transfer;
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::peripherals::HASH;
|
||||
use crate::rcc::SealedRccPeripheral;
|
||||
use crate::{interrupt, pac, peripherals, Peripheral};
|
||||
use crate::{interrupt, pac, peripherals, rcc, Peripheral};
|
||||
|
||||
#[cfg(hash_v1)]
|
||||
const NUM_CONTEXT_REGS: usize = 51;
|
||||
@ -130,7 +129,7 @@ impl<'d, T: Instance, D> Hash<'d, T, D> {
|
||||
dma: impl Peripheral<P = D> + 'd,
|
||||
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
) -> Self {
|
||||
HASH::enable_and_reset();
|
||||
rcc::enable_and_reset::<HASH>();
|
||||
into_ref!(peripheral, dma);
|
||||
let instance = Self {
|
||||
_peripheral: peripheral,
|
||||
|
@ -9,7 +9,7 @@ pub use traits::Instance;
|
||||
|
||||
use crate::gpio::{AFType, AnyPin};
|
||||
use crate::time::Hertz;
|
||||
use crate::Peripheral;
|
||||
use crate::{rcc, Peripheral};
|
||||
|
||||
/// HRTIM burst controller instance.
|
||||
pub struct BurstController<T: Instance> {
|
||||
@ -172,7 +172,7 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> {
|
||||
fn new_inner(tim: impl Peripheral<P = T> + 'd) -> Self {
|
||||
into_ref!(tim);
|
||||
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
|
||||
#[cfg(stm32f334)]
|
||||
if crate::pac::RCC.cfgr3().read().hrtim1sw() == crate::pac::rcc::vals::Timsw::PLL1_P {
|
||||
|
@ -9,16 +9,16 @@ use core::future::Future;
|
||||
use core::iter;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use embassy_hal_internal::{into_ref, Peripheral};
|
||||
use embassy_hal_internal::{Peripheral, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
#[cfg(feature = "time")]
|
||||
use embassy_time::{Duration, Instant};
|
||||
|
||||
use crate::dma::ChannelAndRequest;
|
||||
use crate::gpio::{AFType, Pull};
|
||||
use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed};
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::mode::{Async, Blocking, Mode};
|
||||
use crate::rcc::{ClockEnableBit, SealedRccPeripheral};
|
||||
use crate::rcc::{RccInfo, SealedRccPeripheral};
|
||||
use crate::time::Hertz;
|
||||
use crate::{interrupt, peripherals};
|
||||
|
||||
@ -72,11 +72,29 @@ impl Default for Config {
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
fn scl_pull_mode(&self) -> Pull {
|
||||
match self.scl_pullup {
|
||||
true => Pull::Up,
|
||||
false => Pull::Down,
|
||||
}
|
||||
}
|
||||
|
||||
fn sda_pull_mode(&self) -> Pull {
|
||||
match self.sda_pullup {
|
||||
true => Pull::Up,
|
||||
false => Pull::Down,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// I2C driver.
|
||||
pub struct I2c<'d, M: Mode> {
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
kernel_clock: Hertz,
|
||||
scl: Option<PeripheralRef<'d, AnyPin>>,
|
||||
sda: Option<PeripheralRef<'d, AnyPin>>,
|
||||
tx_dma: Option<ChannelAndRequest<'d>>,
|
||||
rx_dma: Option<ChannelAndRequest<'d>>,
|
||||
#[cfg(feature = "time")]
|
||||
@ -98,7 +116,15 @@ impl<'d> I2c<'d, Async> {
|
||||
freq: Hertz,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
Self::new_inner(peri, scl, sda, new_dma!(tx_dma), new_dma!(rx_dma), freq, config)
|
||||
Self::new_inner(
|
||||
peri,
|
||||
new_pin!(scl, AFType::OutputOpenDrain, Speed::Medium, config.scl_pull_mode()),
|
||||
new_pin!(sda, AFType::OutputOpenDrain, Speed::Medium, config.sda_pull_mode()),
|
||||
new_dma!(tx_dma),
|
||||
new_dma!(rx_dma),
|
||||
freq,
|
||||
config,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,7 +137,15 @@ impl<'d> I2c<'d, Blocking> {
|
||||
freq: Hertz,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
Self::new_inner(peri, scl, sda, None, None, freq, config)
|
||||
Self::new_inner(
|
||||
peri,
|
||||
new_pin!(scl, AFType::OutputOpenDrain, Speed::Medium, config.scl_pull_mode()),
|
||||
new_pin!(sda, AFType::OutputOpenDrain, Speed::Medium, config.sda_pull_mode()),
|
||||
None,
|
||||
None,
|
||||
freq,
|
||||
config,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,34 +153,13 @@ impl<'d, M: Mode> I2c<'d, M> {
|
||||
/// Create a new I2C driver.
|
||||
fn new_inner<T: Instance>(
|
||||
_peri: impl Peripheral<P = T> + 'd,
|
||||
scl: impl Peripheral<P = impl SclPin<T>> + 'd,
|
||||
sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
|
||||
scl: Option<PeripheralRef<'d, AnyPin>>,
|
||||
sda: Option<PeripheralRef<'d, AnyPin>>,
|
||||
tx_dma: Option<ChannelAndRequest<'d>>,
|
||||
rx_dma: Option<ChannelAndRequest<'d>>,
|
||||
freq: Hertz,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(scl, sda);
|
||||
|
||||
T::enable_and_reset();
|
||||
|
||||
scl.set_as_af_pull(
|
||||
scl.af_num(),
|
||||
AFType::OutputOpenDrain,
|
||||
match config.scl_pullup {
|
||||
true => Pull::Up,
|
||||
false => Pull::None,
|
||||
},
|
||||
);
|
||||
sda.set_as_af_pull(
|
||||
sda.af_num(),
|
||||
AFType::OutputOpenDrain,
|
||||
match config.sda_pullup {
|
||||
true => Pull::Up,
|
||||
false => Pull::None,
|
||||
},
|
||||
);
|
||||
|
||||
unsafe { T::EventInterrupt::enable() };
|
||||
unsafe { T::ErrorInterrupt::enable() };
|
||||
|
||||
@ -154,18 +167,23 @@ impl<'d, M: Mode> I2c<'d, M> {
|
||||
info: T::info(),
|
||||
state: T::state(),
|
||||
kernel_clock: T::frequency(),
|
||||
scl,
|
||||
sda,
|
||||
tx_dma,
|
||||
rx_dma,
|
||||
#[cfg(feature = "time")]
|
||||
timeout: config.timeout,
|
||||
_phantom: PhantomData,
|
||||
};
|
||||
|
||||
this.init(freq, config);
|
||||
|
||||
this.enable_and_init(freq, config);
|
||||
this
|
||||
}
|
||||
|
||||
fn enable_and_init(&mut self, freq: Hertz, config: Config) {
|
||||
self.info.rcc.enable_and_reset();
|
||||
self.init(freq, config);
|
||||
}
|
||||
|
||||
fn timeout(&self) -> Timeout {
|
||||
Timeout {
|
||||
#[cfg(feature = "time")]
|
||||
@ -174,6 +192,15 @@ impl<'d, M: Mode> I2c<'d, M> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, M: Mode> Drop for I2c<'d, M> {
|
||||
fn drop(&mut self) {
|
||||
self.scl.as_ref().map(|x| x.set_as_disconnected());
|
||||
self.sda.as_ref().map(|x| x.set_as_disconnected());
|
||||
|
||||
self.info.rcc.disable()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Timeout {
|
||||
#[cfg(feature = "time")]
|
||||
@ -224,7 +251,7 @@ impl State {
|
||||
|
||||
struct Info {
|
||||
regs: crate::pac::i2c::I2c,
|
||||
pub(crate) enable_bit: ClockEnableBit,
|
||||
rcc: RccInfo,
|
||||
}
|
||||
|
||||
peri_trait!(
|
||||
@ -265,7 +292,7 @@ foreach_peripheral!(
|
||||
fn info() -> &'static Info {
|
||||
static INFO: Info = Info{
|
||||
regs: crate::pac::$inst,
|
||||
enable_bit: crate::peripherals::$inst::ENABLE_BIT,
|
||||
rcc: crate::peripherals::$inst::RCC_INFO,
|
||||
};
|
||||
&INFO
|
||||
}
|
||||
|
@ -700,12 +700,6 @@ impl<'d> I2c<'d, Async> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, M: PeriMode> Drop for I2c<'d, M> {
|
||||
fn drop(&mut self) {
|
||||
self.info.enable_bit.disable()
|
||||
}
|
||||
}
|
||||
|
||||
enum Mode {
|
||||
Fast,
|
||||
Standard,
|
||||
|
@ -671,12 +671,6 @@ impl<'d> I2c<'d, Async> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, M: Mode> Drop for I2c<'d, M> {
|
||||
fn drop(&mut self) {
|
||||
self.info.enable_bit.disable();
|
||||
}
|
||||
}
|
||||
|
||||
/// I2C Stop Configuration
|
||||
///
|
||||
/// Peripheral options for generating the STOP condition
|
||||
|
@ -1,7 +1,9 @@
|
||||
//! Inter-IC Sound (I2S)
|
||||
|
||||
use embassy_hal_internal::into_ref;
|
||||
|
||||
use crate::gpio::{AFType, AnyPin, SealedPin};
|
||||
use crate::dma::ChannelAndRequest;
|
||||
use crate::gpio::{AFType, AnyPin, SealedPin, Speed};
|
||||
use crate::mode::Async;
|
||||
use crate::pac::spi::vals;
|
||||
use crate::spi::{Config as SpiConfig, *};
|
||||
@ -17,15 +19,6 @@ pub enum Mode {
|
||||
Slave,
|
||||
}
|
||||
|
||||
/// I2S function
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Function {
|
||||
/// Transmit audio data
|
||||
Transmit,
|
||||
/// Receive audio data
|
||||
Receive,
|
||||
}
|
||||
|
||||
/// I2C standard
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum Standard {
|
||||
@ -42,7 +35,7 @@ pub enum Standard {
|
||||
}
|
||||
|
||||
impl Standard {
|
||||
#[cfg(any(spi_v1, spi_f1))]
|
||||
#[cfg(any(spi_v1, spi_v3, spi_f1))]
|
||||
const fn i2sstd(&self) -> vals::I2sstd {
|
||||
match self {
|
||||
Standard::Philips => vals::I2sstd::PHILIPS,
|
||||
@ -53,7 +46,7 @@ impl Standard {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(spi_v1, spi_f1))]
|
||||
#[cfg(any(spi_v1, spi_v3, spi_f1))]
|
||||
const fn pcmsync(&self) -> vals::Pcmsync {
|
||||
match self {
|
||||
Standard::PcmLongSync => vals::Pcmsync::LONG,
|
||||
@ -76,7 +69,7 @@ pub enum Format {
|
||||
}
|
||||
|
||||
impl Format {
|
||||
#[cfg(any(spi_v1, spi_f1))]
|
||||
#[cfg(any(spi_v1, spi_v3, spi_f1))]
|
||||
const fn datlen(&self) -> vals::Datlen {
|
||||
match self {
|
||||
Format::Data16Channel16 => vals::Datlen::BITS16,
|
||||
@ -86,7 +79,7 @@ impl Format {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(spi_v1, spi_f1))]
|
||||
#[cfg(any(spi_v1, spi_v3, spi_f1))]
|
||||
const fn chlen(&self) -> vals::Chlen {
|
||||
match self {
|
||||
Format::Data16Channel16 => vals::Chlen::BITS16,
|
||||
@ -107,7 +100,7 @@ pub enum ClockPolarity {
|
||||
}
|
||||
|
||||
impl ClockPolarity {
|
||||
#[cfg(any(spi_v1, spi_f1))]
|
||||
#[cfg(any(spi_v1, spi_v3, spi_f1))]
|
||||
const fn ckpol(&self) -> vals::Ckpol {
|
||||
match self {
|
||||
ClockPolarity::IdleHigh => vals::Ckpol::IDLEHIGH,
|
||||
@ -127,15 +120,13 @@ impl ClockPolarity {
|
||||
pub struct Config {
|
||||
/// Mode
|
||||
pub mode: Mode,
|
||||
/// Function (transmit, receive)
|
||||
pub function: Function,
|
||||
/// Which I2S standard to use.
|
||||
pub standard: Standard,
|
||||
/// Data format.
|
||||
pub format: Format,
|
||||
/// Clock polarity.
|
||||
pub clock_polarity: ClockPolarity,
|
||||
/// True to eanble master clock output from this instance.
|
||||
/// True to enable master clock output from this instance.
|
||||
pub master_clock: bool,
|
||||
}
|
||||
|
||||
@ -143,7 +134,6 @@ impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
mode: Mode::Master,
|
||||
function: Function::Transmit,
|
||||
standard: Standard::Philips,
|
||||
format: Format::Data16Channel16,
|
||||
clock_polarity: ClockPolarity::IdleLow,
|
||||
@ -155,43 +145,169 @@ impl Default for Config {
|
||||
/// I2S driver.
|
||||
pub struct I2S<'d> {
|
||||
_peri: Spi<'d, Async>,
|
||||
sd: Option<PeripheralRef<'d, AnyPin>>,
|
||||
txsd: Option<PeripheralRef<'d, AnyPin>>,
|
||||
rxsd: Option<PeripheralRef<'d, AnyPin>>,
|
||||
ws: Option<PeripheralRef<'d, AnyPin>>,
|
||||
ck: Option<PeripheralRef<'d, AnyPin>>,
|
||||
mck: Option<PeripheralRef<'d, AnyPin>>,
|
||||
}
|
||||
|
||||
/// I2S function
|
||||
#[derive(Copy, Clone)]
|
||||
#[allow(dead_code)]
|
||||
enum Function {
|
||||
/// Transmit audio data
|
||||
Transmit,
|
||||
/// Receive audio data
|
||||
Receive,
|
||||
#[cfg(spi_v3)]
|
||||
/// Transmit and Receive audio data
|
||||
FullDuplex,
|
||||
}
|
||||
|
||||
impl<'d> I2S<'d> {
|
||||
/// Note: Full-Duplex modes are not supported at this time
|
||||
pub fn new<T: Instance>(
|
||||
/// Create a transmitter driver
|
||||
pub fn new_txonly<T: Instance>(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
sd: impl Peripheral<P = impl MosiPin<T>> + 'd,
|
||||
ws: impl Peripheral<P = impl WsPin<T>> + 'd,
|
||||
ck: impl Peripheral<P = impl CkPin<T>> + 'd,
|
||||
mck: impl Peripheral<P = impl MckPin<T>> + 'd,
|
||||
txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
|
||||
freq: Hertz,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(sd);
|
||||
Self::new_inner(
|
||||
peri,
|
||||
new_pin!(sd, AFType::OutputPushPull, Speed::VeryHigh),
|
||||
None,
|
||||
ws,
|
||||
ck,
|
||||
mck,
|
||||
new_dma!(txdma),
|
||||
None,
|
||||
freq,
|
||||
config,
|
||||
Function::Transmit,
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a receiver driver
|
||||
pub fn new_rxonly<T: Instance>(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
sd: impl Peripheral<P = impl MisoPin<T>> + 'd,
|
||||
ws: impl Peripheral<P = impl WsPin<T>> + 'd,
|
||||
ck: impl Peripheral<P = impl CkPin<T>> + 'd,
|
||||
mck: impl Peripheral<P = impl MckPin<T>> + 'd,
|
||||
#[cfg(not(spi_v3))] txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
|
||||
rxdma: impl Peripheral<P = impl RxDma<T>> + 'd,
|
||||
freq: Hertz,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(sd);
|
||||
Self::new_inner(
|
||||
peri,
|
||||
None,
|
||||
new_pin!(sd, AFType::OutputPushPull, Speed::VeryHigh),
|
||||
ws,
|
||||
ck,
|
||||
mck,
|
||||
#[cfg(not(spi_v3))]
|
||||
new_dma!(txdma),
|
||||
#[cfg(spi_v3)]
|
||||
None,
|
||||
new_dma!(rxdma),
|
||||
freq,
|
||||
config,
|
||||
#[cfg(not(spi_v3))]
|
||||
Function::Transmit,
|
||||
#[cfg(spi_v3)]
|
||||
Function::Receive,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(spi_v3)]
|
||||
/// Create a full duplex transmitter driver
|
||||
pub fn new_full_duplex<T: Instance>(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
txsd: impl Peripheral<P = impl MosiPin<T>> + 'd,
|
||||
rxsd: impl Peripheral<P = impl MisoPin<T>> + 'd,
|
||||
ws: impl Peripheral<P = impl WsPin<T>> + 'd,
|
||||
ck: impl Peripheral<P = impl CkPin<T>> + 'd,
|
||||
mck: impl Peripheral<P = impl MckPin<T>> + 'd,
|
||||
txdma: impl Peripheral<P = impl TxDma<T>> + 'd,
|
||||
rxdma: impl Peripheral<P = impl RxDma<T>> + 'd,
|
||||
freq: Hertz,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
into_ref!(sd, ws, ck, mck);
|
||||
into_ref!(txsd, rxsd);
|
||||
Self::new_inner(
|
||||
peri,
|
||||
new_pin!(txsd, AFType::OutputPushPull, Speed::VeryHigh),
|
||||
new_pin!(rxsd, AFType::OutputPushPull, Speed::VeryHigh),
|
||||
ws,
|
||||
ck,
|
||||
mck,
|
||||
new_dma!(txdma),
|
||||
new_dma!(rxdma),
|
||||
freq,
|
||||
config,
|
||||
Function::FullDuplex,
|
||||
)
|
||||
}
|
||||
|
||||
sd.set_as_af(sd.af_num(), AFType::OutputPushPull);
|
||||
sd.set_speed(crate::gpio::Speed::VeryHigh);
|
||||
/// Write audio data.
|
||||
pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
|
||||
self._peri.read(data).await
|
||||
}
|
||||
|
||||
/// Write audio data.
|
||||
pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> {
|
||||
self._peri.write(data).await
|
||||
}
|
||||
|
||||
/// Transfer audio data.
|
||||
pub async fn transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
|
||||
self._peri.transfer(read, write).await
|
||||
}
|
||||
|
||||
/// Transfer audio data in place.
|
||||
pub async fn transfer_in_place<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
|
||||
self._peri.transfer_in_place(data).await
|
||||
}
|
||||
|
||||
fn new_inner<T: Instance>(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
txsd: Option<PeripheralRef<'d, AnyPin>>,
|
||||
rxsd: Option<PeripheralRef<'d, AnyPin>>,
|
||||
ws: impl Peripheral<P = impl WsPin<T>> + 'd,
|
||||
ck: impl Peripheral<P = impl CkPin<T>> + 'd,
|
||||
mck: impl Peripheral<P = impl MckPin<T>> + 'd,
|
||||
txdma: Option<ChannelAndRequest<'d>>,
|
||||
rxdma: Option<ChannelAndRequest<'d>>,
|
||||
freq: Hertz,
|
||||
config: Config,
|
||||
function: Function,
|
||||
) -> Self {
|
||||
into_ref!(ws, ck, mck);
|
||||
|
||||
ws.set_as_af(ws.af_num(), AFType::OutputPushPull);
|
||||
ws.set_speed(crate::gpio::Speed::VeryHigh);
|
||||
ws.set_speed(Speed::VeryHigh);
|
||||
|
||||
ck.set_as_af(ck.af_num(), AFType::OutputPushPull);
|
||||
ck.set_speed(crate::gpio::Speed::VeryHigh);
|
||||
ck.set_speed(Speed::VeryHigh);
|
||||
|
||||
mck.set_as_af(mck.af_num(), AFType::OutputPushPull);
|
||||
mck.set_speed(crate::gpio::Speed::VeryHigh);
|
||||
mck.set_speed(Speed::VeryHigh);
|
||||
|
||||
let mut spi_cfg = SpiConfig::default();
|
||||
spi_cfg.frequency = freq;
|
||||
|
||||
let spi = Spi::new_internal(peri, txdma, rxdma, spi_cfg);
|
||||
|
||||
let regs = T::info().regs;
|
||||
|
||||
// TODO move i2s to the new mux infra.
|
||||
//#[cfg(all(rcc_f4, not(stm32f410)))]
|
||||
//let pclk = unsafe { get_freqs() }.plli2s1_q.unwrap();
|
||||
@ -200,26 +316,23 @@ impl<'d> I2S<'d> {
|
||||
|
||||
let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format);
|
||||
|
||||
#[cfg(any(spi_v1, spi_f1))]
|
||||
#[cfg(any(spi_v1, spi_v3, spi_f1))]
|
||||
{
|
||||
#[cfg(spi_v3)]
|
||||
{
|
||||
regs.cr1().modify(|w| w.set_spe(false));
|
||||
|
||||
reset_incompatible_bitfields::<T>();
|
||||
}
|
||||
|
||||
use stm32_metapac::spi::vals::{I2scfg, Odd};
|
||||
|
||||
// 1. Select the I2SDIV[7:0] bits in the SPI_I2SPR register to define the serial clock baud
|
||||
// rate to reach the proper audio sample frequency. The ODD bit in the SPI_I2SPR
|
||||
// register also has to be defined.
|
||||
|
||||
spi.info.regs.i2spr().modify(|w| {
|
||||
w.set_i2sdiv(div);
|
||||
w.set_odd(match odd {
|
||||
true => Odd::ODD,
|
||||
false => Odd::EVEN,
|
||||
});
|
||||
|
||||
w.set_mckoe(config.master_clock);
|
||||
});
|
||||
// 1. Select the I2SDIV[7:0] bits in the SPI_I2SPR/SPI_I2SCFGR register to define the serial clock baud
|
||||
// rate to reach the proper audio sample frequency. The ODD bit in the
|
||||
// SPI_I2SPR/SPI_I2SCFGR register also has to be defined.
|
||||
|
||||
// 2. Select the CKPOL bit to define the steady level for the communication clock. Set the
|
||||
// MCKOE bit in the SPI_I2SPR register if the master clock MCK needs to be provided to
|
||||
// MCKOE bit in the SPI_I2SPR/SPI_I2SCFGR register if the master clock MCK needs to be provided to
|
||||
// the external DAC/ADC audio component (the I2SDIV and ODD values should be
|
||||
// computed depending on the state of the MCK output, for more details refer to
|
||||
// Section 28.4.4: Clock generator).
|
||||
@ -235,50 +348,72 @@ impl<'d> I2S<'d> {
|
||||
|
||||
// 5. The I2SE bit in SPI_I2SCFGR register must be set.
|
||||
|
||||
spi.info.regs.i2scfgr().modify(|w| {
|
||||
let clk_reg = {
|
||||
#[cfg(any(spi_v1, spi_f1))]
|
||||
{
|
||||
regs.i2spr()
|
||||
}
|
||||
#[cfg(spi_v3)]
|
||||
{
|
||||
regs.i2scfgr()
|
||||
}
|
||||
};
|
||||
|
||||
clk_reg.modify(|w| {
|
||||
w.set_i2sdiv(div);
|
||||
w.set_odd(match odd {
|
||||
true => Odd::ODD,
|
||||
false => Odd::EVEN,
|
||||
});
|
||||
|
||||
w.set_mckoe(config.master_clock);
|
||||
});
|
||||
|
||||
regs.i2scfgr().modify(|w| {
|
||||
w.set_ckpol(config.clock_polarity.ckpol());
|
||||
|
||||
w.set_i2smod(true);
|
||||
|
||||
w.set_i2sstd(config.standard.i2sstd());
|
||||
w.set_pcmsync(config.standard.pcmsync());
|
||||
|
||||
w.set_datlen(config.format.datlen());
|
||||
w.set_chlen(config.format.chlen());
|
||||
|
||||
w.set_i2scfg(match (config.mode, config.function) {
|
||||
w.set_i2scfg(match (config.mode, function) {
|
||||
(Mode::Master, Function::Transmit) => I2scfg::MASTERTX,
|
||||
(Mode::Master, Function::Receive) => I2scfg::MASTERRX,
|
||||
#[cfg(spi_v3)]
|
||||
(Mode::Master, Function::FullDuplex) => I2scfg::MASTERFULLDUPLEX,
|
||||
(Mode::Slave, Function::Transmit) => I2scfg::SLAVETX,
|
||||
(Mode::Slave, Function::Receive) => I2scfg::SLAVERX,
|
||||
#[cfg(spi_v3)]
|
||||
(Mode::Slave, Function::FullDuplex) => I2scfg::SLAVEFULLDUPLEX,
|
||||
});
|
||||
|
||||
w.set_i2se(true)
|
||||
#[cfg(any(spi_v1, spi_f1))]
|
||||
w.set_i2se(true);
|
||||
});
|
||||
|
||||
#[cfg(spi_v3)]
|
||||
regs.cr1().modify(|w| w.set_spe(true));
|
||||
}
|
||||
|
||||
Self {
|
||||
_peri: spi,
|
||||
sd: Some(sd.map_into()),
|
||||
txsd: txsd.map(|w| w.map_into()),
|
||||
rxsd: rxsd.map(|w| w.map_into()),
|
||||
ws: Some(ws.map_into()),
|
||||
ck: Some(ck.map_into()),
|
||||
mck: Some(mck.map_into()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Write audio data.
|
||||
pub async fn write<W: Word>(&mut self, data: &[W]) -> Result<(), Error> {
|
||||
self._peri.write(data).await
|
||||
}
|
||||
|
||||
/// Read audio data.
|
||||
pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
|
||||
self._peri.read(data).await
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> Drop for I2S<'d> {
|
||||
fn drop(&mut self) {
|
||||
self.sd.as_ref().map(|x| x.set_as_disconnected());
|
||||
self.txsd.as_ref().map(|x| x.set_as_disconnected());
|
||||
self.rxsd.as_ref().map(|x| x.set_as_disconnected());
|
||||
self.ws.as_ref().map(|x| x.set_as_disconnected());
|
||||
self.ck.as_ref().map(|x| x.set_as_disconnected());
|
||||
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
|
||||
((division & 1) == 1, (division >> 1) as u8)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(spi_v3)]
|
||||
// The STM32H7 reference manual specifies that any incompatible bitfields should be reset
|
||||
// to their reset values while operating in I2S mode.
|
||||
fn reset_incompatible_bitfields<T: Instance>() {
|
||||
let regs = T::info().regs;
|
||||
regs.cr1().modify(|w| {
|
||||
let iolock = w.iolock();
|
||||
let csusp = w.csusp();
|
||||
let spe = w.cstart();
|
||||
let cstart = w.cstart();
|
||||
w.0 = 0;
|
||||
w.set_iolock(iolock);
|
||||
w.set_csusp(csusp);
|
||||
w.set_spe(spe);
|
||||
w.set_cstart(cstart);
|
||||
});
|
||||
|
||||
regs.cr2().write(|w| w.0 = 0);
|
||||
|
||||
regs.cfg1().modify(|w| {
|
||||
let txdmaen = w.txdmaen();
|
||||
let rxdmaen = w.rxdmaen();
|
||||
let fthlv = w.fthlv();
|
||||
w.0 = 0;
|
||||
w.set_txdmaen(txdmaen);
|
||||
w.set_rxdmaen(rxdmaen);
|
||||
w.set_fthlv(fthlv);
|
||||
});
|
||||
|
||||
regs.cfg2().modify(|w| {
|
||||
let afcntr = w.afcntr();
|
||||
let lsbfirst = w.lsbfirst();
|
||||
let ioswp = w.ioswp();
|
||||
w.0 = 0;
|
||||
w.set_afcntr(afcntr);
|
||||
w.set_lsbfirst(lsbfirst);
|
||||
w.set_ioswp(ioswp);
|
||||
});
|
||||
|
||||
regs.ier().modify(|w| {
|
||||
let tifreie = w.tifreie();
|
||||
let ovrie = w.ovrie();
|
||||
let udrie = w.udrie();
|
||||
let txpie = w.txpie();
|
||||
let rxpie = w.rxpie();
|
||||
|
||||
w.0 = 0;
|
||||
|
||||
w.set_tifreie(tifreie);
|
||||
w.set_ovrie(ovrie);
|
||||
w.set_udrie(udrie);
|
||||
w.set_txpie(txpie);
|
||||
w.set_rxpie(rxpie);
|
||||
});
|
||||
|
||||
regs.ifcr().write(|w| {
|
||||
w.set_suspc(true);
|
||||
w.set_tifrec(true);
|
||||
w.set_ovrc(true);
|
||||
w.set_udrc(true);
|
||||
});
|
||||
|
||||
regs.crcpoly().write(|w| w.0 = 0x107);
|
||||
regs.txcrc().write(|w| w.0 = 0);
|
||||
regs.rxcrc().write(|w| w.0 = 0);
|
||||
regs.udrdr().write(|w| w.0 = 0);
|
||||
}
|
||||
|
@ -6,10 +6,9 @@ use core::task::Poll;
|
||||
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use crate::interrupt;
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::peripherals::IPCC;
|
||||
use crate::rcc::SealedRccPeripheral;
|
||||
use crate::{interrupt, rcc};
|
||||
|
||||
/// Interrupt handler.
|
||||
pub struct ReceiveInterruptHandler {}
|
||||
@ -102,7 +101,7 @@ pub struct Ipcc;
|
||||
impl Ipcc {
|
||||
/// Enable IPCC.
|
||||
pub fn enable(_config: Config) {
|
||||
IPCC::enable_and_reset();
|
||||
rcc::enable_and_reset::<IPCC>();
|
||||
IPCC::set_cpu2(true);
|
||||
|
||||
// set RF wake-up clock = LSE
|
||||
|
@ -83,7 +83,7 @@ pub mod hrtim;
|
||||
pub mod hsem;
|
||||
#[cfg(i2c)]
|
||||
pub mod i2c;
|
||||
#[cfg(all(spi_v1, rcc_f4))]
|
||||
#[cfg(any(all(spi_v1, rcc_f4), spi_v3))]
|
||||
pub mod i2s;
|
||||
#[cfg(stm32wb)]
|
||||
pub mod ipcc;
|
||||
@ -194,7 +194,6 @@ pub(crate) use stm32_metapac as pac;
|
||||
use crate::interrupt::Priority;
|
||||
#[cfg(feature = "rt")]
|
||||
pub use crate::pac::NVIC_PRIO_BITS;
|
||||
use crate::rcc::SealedRccPeripheral;
|
||||
|
||||
/// `embassy-stm32` global configuration.
|
||||
#[non_exhaustive]
|
||||
@ -310,11 +309,11 @@ pub fn init(config: Config) -> Peripherals {
|
||||
});
|
||||
|
||||
#[cfg(not(any(stm32f1, stm32wb, stm32wl)))]
|
||||
peripherals::SYSCFG::enable_and_reset_with_cs(cs);
|
||||
rcc::enable_and_reset_with_cs::<peripherals::SYSCFG>(cs);
|
||||
#[cfg(not(any(stm32h5, stm32h7, stm32h7rs, stm32wb, stm32wl)))]
|
||||
peripherals::PWR::enable_and_reset_with_cs(cs);
|
||||
rcc::enable_and_reset_with_cs::<peripherals::PWR>(cs);
|
||||
#[cfg(not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7, stm32h7rs)))]
|
||||
peripherals::FLASH::enable_and_reset_with_cs(cs);
|
||||
rcc::enable_and_reset_with_cs::<peripherals::FLASH>(cs);
|
||||
|
||||
// Enable the VDDIO2 power supply on chips that have it.
|
||||
// Note that this requires the PWR peripheral to be enabled first.
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! LTDC
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use crate::rcc::RccPeripheral;
|
||||
use crate::rcc::{self, RccPeripheral};
|
||||
use crate::{peripherals, Peripheral};
|
||||
|
||||
/// LTDC driver.
|
||||
@ -60,7 +60,7 @@ impl<'d, T: Instance> Ltdc<'d, T> {
|
||||
.modify(|w| w.set_pllsaidivr(stm32_metapac::rcc::vals::Pllsaidivr::DIV2));
|
||||
});
|
||||
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
|
||||
//new_pin!(clk, AFType::OutputPushPull, Speed::VeryHigh, Pull::None);
|
||||
|
||||
@ -93,7 +93,7 @@ impl<'d, T: Instance> Drop for Ltdc<'d, T> {
|
||||
}
|
||||
|
||||
trait SealedInstance: crate::rcc::SealedRccPeripheral {
|
||||
fn regs() -> &'static crate::pac::ltdc::Ltdc;
|
||||
fn regs() -> crate::pac::ltdc::Ltdc;
|
||||
}
|
||||
|
||||
/// DSI instance trait.
|
||||
@ -132,8 +132,8 @@ pin_trait!(B7Pin, Instance);
|
||||
foreach_peripheral!(
|
||||
(ltdc, $inst:ident) => {
|
||||
impl crate::ltdc::SealedInstance for peripherals::$inst {
|
||||
fn regs() -> &'static crate::pac::ltdc::Ltdc {
|
||||
&crate::pac::$inst
|
||||
fn regs() -> crate::pac::ltdc::Ltdc {
|
||||
crate::pac::$inst
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,6 +110,32 @@ impl<'d, T: Instance> OpAmp<'d, T> {
|
||||
|
||||
OpAmpOutput { _inner: self }
|
||||
}
|
||||
/// Configure the OpAmp as a buffer for the DAC it is connected to,
|
||||
/// outputting to the provided output pin, and enable the opamp.
|
||||
///
|
||||
/// The output pin is held within the returned [`OpAmpOutput`] struct,
|
||||
/// preventing it being used elsewhere. The `OpAmpOutput` can then be
|
||||
/// directly used as an ADC input. The opamp will be disabled when the
|
||||
/// [`OpAmpOutput`] is dropped.
|
||||
#[cfg(opamp_g4)]
|
||||
pub fn buffer_dac(
|
||||
&'d mut self,
|
||||
out_pin: impl Peripheral<P = impl OutputPin<T> + crate::gpio::Pin> + 'd,
|
||||
) -> OpAmpOutput<'d, T> {
|
||||
into_ref!(out_pin);
|
||||
out_pin.set_as_analog();
|
||||
|
||||
T::regs().csr().modify(|w| {
|
||||
use crate::pac::opamp::vals::*;
|
||||
|
||||
w.set_vm_sel(VmSel::OUTPUT);
|
||||
w.set_vp_sel(VpSel::DAC3_CH1);
|
||||
w.set_opaintoen(Opaintoen::OUTPUTPIN);
|
||||
w.set_opampen(true);
|
||||
});
|
||||
|
||||
OpAmpOutput { _inner: self }
|
||||
}
|
||||
|
||||
/// Configure the OpAmp as a buffer for the provided input pin,
|
||||
/// with the output only used internally, and enable the opamp.
|
||||
|
@ -16,7 +16,7 @@ use crate::dma::{word, ChannelAndRequest};
|
||||
use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed};
|
||||
use crate::mode::{Async, Blocking, Mode as PeriMode};
|
||||
use crate::pac::octospi::{vals, Octospi as Regs};
|
||||
use crate::rcc::RccPeripheral;
|
||||
use crate::rcc::{self, RccPeripheral};
|
||||
use crate::{peripherals, Peripheral};
|
||||
|
||||
/// OPSI driver config.
|
||||
@ -198,7 +198,7 @@ impl<'d, T: Instance, M: PeriMode> Ospi<'d, T, M> {
|
||||
into_ref!(peri);
|
||||
|
||||
// System configuration
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
while T::REGS.sr().read().busy() {}
|
||||
|
||||
// Device configuration
|
||||
@ -1013,7 +1013,7 @@ impl<'d, T: Instance, M: PeriMode> Drop for Ospi<'d, T, M> {
|
||||
self.nss.as_ref().map(|x| x.set_as_disconnected());
|
||||
self.dqs.as_ref().map(|x| x.set_as_disconnected());
|
||||
|
||||
T::disable();
|
||||
rcc::disable::<T>();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ use crate::dma::ChannelAndRequest;
|
||||
use crate::gpio::{AFType, AnyPin, Pull, Speed};
|
||||
use crate::mode::{Async, Blocking, Mode as PeriMode};
|
||||
use crate::pac::quadspi::Quadspi as Regs;
|
||||
use crate::rcc::RccPeripheral;
|
||||
use crate::rcc::{self, RccPeripheral};
|
||||
use crate::{peripherals, Peripheral};
|
||||
|
||||
/// QSPI transfer configuration.
|
||||
@ -102,7 +102,7 @@ impl<'d, T: Instance, M: PeriMode> Qspi<'d, T, M> {
|
||||
) -> Self {
|
||||
into_ref!(peri);
|
||||
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
|
||||
while T::REGS.sr().read().busy() {}
|
||||
|
||||
|
@ -33,7 +33,7 @@ pub enum LseDrive {
|
||||
}
|
||||
|
||||
// All families but these have the LSEDRV register
|
||||
#[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f400, rcc_f410, rcc_l1)))]
|
||||
#[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1)))]
|
||||
impl From<LseDrive> for crate::pac::rcc::vals::Lsedrv {
|
||||
fn from(value: LseDrive) -> Self {
|
||||
use crate::pac::rcc::vals::Lsedrv;
|
||||
@ -186,7 +186,7 @@ impl LsConfig {
|
||||
}
|
||||
ok &= reg.lseon() == lse_en;
|
||||
ok &= reg.lsebyp() == lse_byp;
|
||||
#[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f400, rcc_f410, rcc_l1)))]
|
||||
#[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1)))]
|
||||
if let Some(lse_drv) = lse_drv {
|
||||
ok &= reg.lsedrv() == lse_drv.into();
|
||||
}
|
||||
@ -224,7 +224,7 @@ impl LsConfig {
|
||||
|
||||
if lse_en {
|
||||
bdcr().modify(|w| {
|
||||
#[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f400, rcc_f410, rcc_l1)))]
|
||||
#[cfg(not(any(rcc_f1, rcc_f1cl, rcc_f100, rcc_f2, rcc_f4, rcc_f410, rcc_l1)))]
|
||||
if let Some(lse_drv) = lse_drv {
|
||||
w.set_lsedrv(lse_drv.into());
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ pub struct Config {
|
||||
|
||||
#[cfg(all(stm32f3, not(rcc_f37)))]
|
||||
pub adc: AdcClockSource,
|
||||
#[cfg(all(stm32f3, not(rcc_f37), adc3_common))]
|
||||
#[cfg(all(stm32f3, not(rcc_f37), any(peri_adc3_common, peri_adc34_common)))]
|
||||
pub adc34: AdcClockSource,
|
||||
|
||||
/// Per-peripheral kernel clock selection muxes
|
||||
@ -125,7 +125,7 @@ impl Default for Config {
|
||||
|
||||
#[cfg(all(stm32f3, not(rcc_f37)))]
|
||||
adc: AdcClockSource::Hclk(AdcHclkPrescaler::Div1),
|
||||
#[cfg(all(stm32f3, not(rcc_f37), adc3_common))]
|
||||
#[cfg(all(stm32f3, not(rcc_f37), any(peri_adc3_common, peri_adc34_common)))]
|
||||
adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1),
|
||||
|
||||
mux: Default::default(),
|
||||
@ -276,7 +276,7 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
// Set prescalers
|
||||
// CFGR has been written before (PLL, PLL48) don't overwrite these settings
|
||||
RCC.cfgr().modify(|w: &mut stm32_metapac::rcc::regs::Cfgr| {
|
||||
RCC.cfgr().modify(|w| {
|
||||
#[cfg(not(stm32f0))]
|
||||
{
|
||||
w.set_ppre1(config.apb1_pre);
|
||||
@ -339,7 +339,7 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(all(stm32f3, not(rcc_f37), adc3_common))]
|
||||
#[cfg(all(stm32f3, not(rcc_f37), any(peri_adc3_common, peri_adc34_common)))]
|
||||
let adc34 = {
|
||||
#[cfg(peri_adc3_common)]
|
||||
let common = crate::pac::ADC3_COMMON;
|
||||
@ -404,7 +404,7 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
hclk1: Some(hclk),
|
||||
#[cfg(all(stm32f3, not(rcc_f37)))]
|
||||
adc: Some(adc),
|
||||
#[cfg(all(stm32f3, not(rcc_f37), adc3_common))]
|
||||
#[cfg(all(stm32f3, not(rcc_f37), any(peri_adc3_common, peri_adc34_common)))]
|
||||
adc34: Some(adc34),
|
||||
rtc: rtc,
|
||||
hsi48: hsi48,
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use crate::pac::crs::vals::Syncsrc;
|
||||
use crate::pac::{CRS, RCC};
|
||||
use crate::rcc::SealedRccPeripheral;
|
||||
use crate::rcc::{self, SealedRccPeripheral};
|
||||
use crate::time::Hertz;
|
||||
|
||||
/// HSI48 speed
|
||||
@ -44,7 +44,7 @@ pub(crate) fn init_hsi48(config: Hsi48Config) -> Hertz {
|
||||
while r.read().hsi48rdy() == false {}
|
||||
|
||||
if config.sync_from_usb {
|
||||
crate::peripherals::CRS::enable_and_reset();
|
||||
rcc::enable_and_reset::<crate::peripherals::CRS>();
|
||||
|
||||
CRS.cfgr().modify(|w| {
|
||||
w.set_syncsrc(Syncsrc::USB);
|
||||
|
@ -67,23 +67,185 @@ pub(crate) unsafe fn get_freqs() -> &'static Clocks {
|
||||
}
|
||||
|
||||
pub(crate) trait SealedRccPeripheral {
|
||||
const ENABLE_BIT: ClockEnableBit;
|
||||
|
||||
fn frequency() -> Hertz;
|
||||
fn enable_and_reset_with_cs(cs: CriticalSection);
|
||||
fn disable_with_cs(cs: CriticalSection);
|
||||
|
||||
fn enable_and_reset() {
|
||||
critical_section::with(|cs| Self::enable_and_reset_with_cs(cs))
|
||||
}
|
||||
fn disable() {
|
||||
critical_section::with(|cs| Self::disable_with_cs(cs))
|
||||
}
|
||||
const RCC_INFO: RccInfo;
|
||||
}
|
||||
|
||||
#[allow(private_bounds)]
|
||||
pub trait RccPeripheral: SealedRccPeripheral + 'static {}
|
||||
|
||||
/// Runtime information necessary to reset, enable and disable a peripheral.
|
||||
pub(crate) struct RccInfo {
|
||||
/// Offset in 32-bit words of the xxxRSTR register into the RCC register block, or 0xff if the
|
||||
/// peripheral has no reset bit (we don't use an `Option` to save one byte of storage).
|
||||
reset_offset_or_0xff: u8,
|
||||
/// Position of the xxxRST bit within the xxxRSTR register (0..=31).
|
||||
reset_bit: u8,
|
||||
/// Offset in 32-bit words of the xxxENR register into the RCC register block.
|
||||
enable_offset: u8,
|
||||
/// Position of the xxxEN bit within the xxxENR register (0..=31).
|
||||
enable_bit: u8,
|
||||
/// If this peripheral shares the same xxxRSTR bit and xxxEN bit with other peripherals, we
|
||||
/// maintain a refcount in `crate::_generated::REFCOUNTS` at this index. If the bit is not
|
||||
/// shared, this is 0xff (we don't use an `Option` to save one byte of storage).
|
||||
refcount_idx_or_0xff: u8,
|
||||
/// Stop mode of the peripheral, used to maintain `REFCOUNT_STOP1` and `REFCOUNT_STOP2`.
|
||||
#[cfg(feature = "low-power")]
|
||||
stop_mode: StopMode,
|
||||
}
|
||||
|
||||
#[cfg(feature = "low-power")]
|
||||
#[allow(dead_code)]
|
||||
pub(crate) enum StopMode {
|
||||
Standby,
|
||||
Stop2,
|
||||
Stop1,
|
||||
}
|
||||
|
||||
impl RccInfo {
|
||||
/// Safety:
|
||||
/// - `reset_offset_and_bit`, if set, must correspond to valid xxxRST bit
|
||||
/// - `enable_offset_and_bit` must correspond to valid xxxEN bit
|
||||
/// - `refcount_idx`, if set, must correspond to valid refcount in `_generated::REFCOUNTS`
|
||||
/// - `stop_mode` must be valid
|
||||
pub(crate) const unsafe fn new(
|
||||
reset_offset_and_bit: Option<(u8, u8)>,
|
||||
enable_offset_and_bit: (u8, u8),
|
||||
refcount_idx: Option<u8>,
|
||||
#[cfg(feature = "low-power")] stop_mode: StopMode,
|
||||
) -> Self {
|
||||
let (reset_offset_or_0xff, reset_bit) = match reset_offset_and_bit {
|
||||
Some((offset, bit)) => (offset, bit),
|
||||
None => (0xff, 0xff),
|
||||
};
|
||||
let (enable_offset, enable_bit) = enable_offset_and_bit;
|
||||
let refcount_idx_or_0xff = match refcount_idx {
|
||||
Some(idx) => idx,
|
||||
None => 0xff,
|
||||
};
|
||||
Self {
|
||||
reset_offset_or_0xff,
|
||||
reset_bit,
|
||||
enable_offset,
|
||||
enable_bit,
|
||||
refcount_idx_or_0xff,
|
||||
#[cfg(feature = "low-power")]
|
||||
stop_mode,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: should this be `unsafe`?
|
||||
pub(crate) fn enable_and_reset_with_cs(&self, _cs: CriticalSection) {
|
||||
if self.refcount_idx_or_0xff != 0xff {
|
||||
let refcount_idx = self.refcount_idx_or_0xff as usize;
|
||||
unsafe {
|
||||
crate::_generated::REFCOUNTS[refcount_idx] += 1;
|
||||
}
|
||||
if unsafe { crate::_generated::REFCOUNTS[refcount_idx] } > 1 {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "low-power")]
|
||||
match self.stop_mode {
|
||||
StopMode::Standby => {}
|
||||
StopMode::Stop2 => unsafe {
|
||||
REFCOUNT_STOP2 += 1;
|
||||
},
|
||||
StopMode::Stop1 => unsafe {
|
||||
REFCOUNT_STOP1 += 1;
|
||||
},
|
||||
}
|
||||
|
||||
// set the xxxRST bit
|
||||
let reset_ptr = self.reset_ptr();
|
||||
if let Some(reset_ptr) = reset_ptr {
|
||||
unsafe {
|
||||
let val = reset_ptr.read_volatile();
|
||||
reset_ptr.write_volatile(val | 1u32 << self.reset_bit);
|
||||
}
|
||||
}
|
||||
|
||||
// set the xxxEN bit
|
||||
let enable_ptr = self.enable_ptr();
|
||||
unsafe {
|
||||
let val = enable_ptr.read_volatile();
|
||||
enable_ptr.write_volatile(val | 1u32 << self.enable_bit);
|
||||
}
|
||||
|
||||
// we must wait two peripheral clock cycles before the clock is active
|
||||
// this seems to work, but might be incorrect
|
||||
// see http://efton.sk/STM32/gotcha/g183.html
|
||||
|
||||
// dummy read (like in the ST HALs)
|
||||
let _ = unsafe { enable_ptr.read_volatile() };
|
||||
|
||||
// DSB for good measure
|
||||
cortex_m::asm::dsb();
|
||||
|
||||
// clear the xxxRST bit
|
||||
if let Some(reset_ptr) = reset_ptr {
|
||||
unsafe {
|
||||
let val = reset_ptr.read_volatile();
|
||||
reset_ptr.write_volatile(val & !(1u32 << self.reset_bit));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: should this be `unsafe`?
|
||||
pub(crate) fn disable_with_cs(&self, _cs: CriticalSection) {
|
||||
if self.refcount_idx_or_0xff != 0xff {
|
||||
let refcount_idx = self.refcount_idx_or_0xff as usize;
|
||||
unsafe {
|
||||
crate::_generated::REFCOUNTS[refcount_idx] -= 1;
|
||||
}
|
||||
if unsafe { crate::_generated::REFCOUNTS[refcount_idx] } > 0 {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "low-power")]
|
||||
match self.stop_mode {
|
||||
StopMode::Standby => {}
|
||||
StopMode::Stop2 => unsafe {
|
||||
REFCOUNT_STOP2 -= 1;
|
||||
},
|
||||
StopMode::Stop1 => unsafe {
|
||||
REFCOUNT_STOP1 -= 1;
|
||||
},
|
||||
}
|
||||
|
||||
// clear the xxxEN bit
|
||||
let enable_ptr = self.enable_ptr();
|
||||
unsafe {
|
||||
let val = enable_ptr.read_volatile();
|
||||
enable_ptr.write_volatile(val & !(1u32 << self.enable_bit));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: should this be `unsafe`?
|
||||
pub(crate) fn enable_and_reset(&self) {
|
||||
critical_section::with(|cs| self.enable_and_reset_with_cs(cs))
|
||||
}
|
||||
|
||||
// TODO: should this be `unsafe`?
|
||||
pub(crate) fn disable(&self) {
|
||||
critical_section::with(|cs| self.disable_with_cs(cs))
|
||||
}
|
||||
|
||||
fn reset_ptr(&self) -> Option<*mut u32> {
|
||||
if self.reset_offset_or_0xff != 0xff {
|
||||
Some(unsafe { (RCC.as_ptr() as *mut u32).add(self.reset_offset_or_0xff as _) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn enable_ptr(&self) -> *mut u32 {
|
||||
unsafe { (RCC.as_ptr() as *mut u32).add(self.enable_offset as _) }
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
mod util {
|
||||
use crate::time::Hertz;
|
||||
@ -128,8 +290,9 @@ pub fn frequency<T: RccPeripheral>() -> Hertz {
|
||||
/// # Safety
|
||||
///
|
||||
/// Peripheral must not be in use.
|
||||
pub unsafe fn enable_and_reset<T: RccPeripheral>() {
|
||||
T::enable_and_reset();
|
||||
// TODO: should this be `unsafe`?
|
||||
pub fn enable_and_reset_with_cs<T: RccPeripheral>(cs: CriticalSection) {
|
||||
T::RCC_INFO.enable_and_reset_with_cs(cs);
|
||||
}
|
||||
|
||||
/// Disables peripheral `T`.
|
||||
@ -137,52 +300,27 @@ pub unsafe fn enable_and_reset<T: RccPeripheral>() {
|
||||
/// # Safety
|
||||
///
|
||||
/// Peripheral must not be in use.
|
||||
pub unsafe fn disable<T: RccPeripheral>() {
|
||||
T::disable();
|
||||
// TODO: should this be `unsafe`?
|
||||
pub fn disable_with_cs<T: RccPeripheral>(cs: CriticalSection) {
|
||||
T::RCC_INFO.disable_with_cs(cs);
|
||||
}
|
||||
|
||||
/// Struct representing some clock enable bit (xxxENR.xxEN), only known at runtime.
|
||||
#[derive(Clone, Copy)]
|
||||
pub(crate) struct ClockEnableBit {
|
||||
/// offset in 32bit words of the xxxENR register into the RCC register block.
|
||||
offset: u8,
|
||||
/// bit within the register (0..=31)
|
||||
bit: u8,
|
||||
/// Enables and resets peripheral `T`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Peripheral must not be in use.
|
||||
// TODO: should this be `unsafe`?
|
||||
pub fn enable_and_reset<T: RccPeripheral>() {
|
||||
T::RCC_INFO.enable_and_reset();
|
||||
}
|
||||
|
||||
impl ClockEnableBit {
|
||||
/// Safety: offset+bit must correspond to a valid xxxEN bit.
|
||||
pub(crate) const unsafe fn new(offset: u8, bit: u8) -> Self {
|
||||
Self { offset, bit }
|
||||
}
|
||||
|
||||
fn ptr(self) -> *mut u32 {
|
||||
unsafe { (RCC.as_ptr() as *mut u32).add(self.offset as _) }
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub(crate) fn enable_with_cs(self, _cs: CriticalSection) {
|
||||
let p = self.ptr();
|
||||
unsafe {
|
||||
let val = p.read_volatile();
|
||||
p.write_volatile(val | 1u32 << self.bit);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn disable_with_cs(self, _cs: CriticalSection) {
|
||||
let p = self.ptr();
|
||||
unsafe {
|
||||
let val = p.read_volatile();
|
||||
p.write_volatile(val & !(1u32 << self.bit));
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub(crate) fn enable(self) {
|
||||
critical_section::with(|cs| self.enable_with_cs(cs))
|
||||
}
|
||||
|
||||
pub(crate) fn disable(self) {
|
||||
critical_section::with(|cs| self.disable_with_cs(cs))
|
||||
}
|
||||
/// Disables peripheral `T`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Peripheral must not be in use.
|
||||
// TODO: should this be `unsafe`?
|
||||
pub fn disable<T: RccPeripheral>() {
|
||||
T::RCC_INFO.disable();
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use embassy_sync::waitqueue::AtomicWaker;
|
||||
use rand_core::{CryptoRng, RngCore};
|
||||
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::{interrupt, pac, peripherals, Peripheral};
|
||||
use crate::{interrupt, pac, peripherals, rcc, Peripheral};
|
||||
|
||||
static RNG_WAKER: AtomicWaker = AtomicWaker::new();
|
||||
|
||||
@ -52,7 +52,7 @@ impl<'d, T: Instance> Rng<'d, T> {
|
||||
inner: impl Peripheral<P = T> + 'd,
|
||||
_irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
|
||||
) -> Self {
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
into_ref!(inner);
|
||||
let mut random = Self { _inner: inner };
|
||||
random.reset();
|
||||
|
@ -1,65 +1,6 @@
|
||||
#[cfg(feature = "chrono")]
|
||||
use chrono::{Datelike, NaiveDate, Timelike, Weekday};
|
||||
|
||||
#[cfg(any(feature = "defmt", feature = "time"))]
|
||||
use crate::peripherals::RTC;
|
||||
#[cfg(any(feature = "defmt", feature = "time"))]
|
||||
use crate::rtc::SealedInstance;
|
||||
|
||||
/// Represents an instant in time that can be substracted to compute a duration
|
||||
pub struct RtcInstant {
|
||||
/// 0..59
|
||||
pub second: u8,
|
||||
/// 0..256
|
||||
pub subsecond: u16,
|
||||
}
|
||||
|
||||
impl RtcInstant {
|
||||
#[cfg(not(rtc_v2f2))]
|
||||
pub(super) const fn from(second: u8, subsecond: u16) -> Result<Self, Error> {
|
||||
if second > 59 {
|
||||
Err(Error::InvalidSecond)
|
||||
} else {
|
||||
Ok(Self { second, subsecond })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
impl defmt::Format for RtcInstant {
|
||||
fn format(&self, fmt: defmt::Formatter) {
|
||||
defmt::write!(
|
||||
fmt,
|
||||
"{}:{}",
|
||||
self.second,
|
||||
RTC::regs().prer().read().prediv_s() - self.subsecond,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "time")]
|
||||
impl core::ops::Sub for RtcInstant {
|
||||
type Output = embassy_time::Duration;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
use embassy_time::{Duration, TICK_HZ};
|
||||
|
||||
let second = if self.second < rhs.second {
|
||||
self.second + 60
|
||||
} else {
|
||||
self.second
|
||||
};
|
||||
|
||||
let psc = RTC::regs().prer().read().prediv_s() as u32;
|
||||
|
||||
let self_ticks = second as u32 * (psc + 1) + (psc - self.subsecond as u32);
|
||||
let other_ticks = rhs.second as u32 * (psc + 1) + (psc - rhs.subsecond as u32);
|
||||
let rtc_ticks = self_ticks - other_ticks;
|
||||
|
||||
Duration::from_ticks(((rtc_ticks * TICK_HZ as u32) / (psc + 1)) as u64)
|
||||
}
|
||||
}
|
||||
|
||||
/// Errors regarding the [`DateTime`] struct.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Error {
|
||||
|
230
embassy-stm32/src/rtc/low_power.rs
Normal file
230
embassy-stm32/src/rtc/low_power.rs
Normal file
@ -0,0 +1,230 @@
|
||||
use super::{bcd2_to_byte, DateTimeError, Rtc, RtcError};
|
||||
use crate::peripherals::RTC;
|
||||
use crate::rtc::SealedInstance;
|
||||
|
||||
/// Represents an instant in time that can be substracted to compute a duration
|
||||
pub(super) struct RtcInstant {
|
||||
/// 0..59
|
||||
second: u8,
|
||||
/// 0..256
|
||||
subsecond: u16,
|
||||
}
|
||||
|
||||
impl RtcInstant {
|
||||
#[cfg(not(rtc_v2f2))]
|
||||
const fn from(second: u8, subsecond: u16) -> Result<Self, DateTimeError> {
|
||||
if second > 59 {
|
||||
Err(DateTimeError::InvalidSecond)
|
||||
} else {
|
||||
Ok(Self { second, subsecond })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
impl defmt::Format for RtcInstant {
|
||||
fn format(&self, fmt: defmt::Formatter) {
|
||||
defmt::write!(
|
||||
fmt,
|
||||
"{}:{}",
|
||||
self.second,
|
||||
RTC::regs().prer().read().prediv_s() - self.subsecond,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "time")]
|
||||
impl core::ops::Sub for RtcInstant {
|
||||
type Output = embassy_time::Duration;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
use embassy_time::{Duration, TICK_HZ};
|
||||
|
||||
let second = if self.second < rhs.second {
|
||||
self.second + 60
|
||||
} else {
|
||||
self.second
|
||||
};
|
||||
|
||||
let psc = RTC::regs().prer().read().prediv_s() as u32;
|
||||
|
||||
let self_ticks = second as u32 * (psc + 1) + (psc - self.subsecond as u32);
|
||||
let other_ticks = rhs.second as u32 * (psc + 1) + (psc - rhs.subsecond as u32);
|
||||
let rtc_ticks = self_ticks - other_ticks;
|
||||
|
||||
Duration::from_ticks(((rtc_ticks * TICK_HZ as u32) / (psc + 1)) as u64)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub(crate) enum WakeupPrescaler {
|
||||
Div2 = 2,
|
||||
Div4 = 4,
|
||||
Div8 = 8,
|
||||
Div16 = 16,
|
||||
}
|
||||
|
||||
#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l5, stm32wb, stm32h5, stm32g0))]
|
||||
impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
|
||||
fn from(val: WakeupPrescaler) -> Self {
|
||||
use crate::pac::rtc::vals::Wucksel;
|
||||
|
||||
match val {
|
||||
WakeupPrescaler::Div2 => Wucksel::DIV2,
|
||||
WakeupPrescaler::Div4 => Wucksel::DIV4,
|
||||
WakeupPrescaler::Div8 => Wucksel::DIV8,
|
||||
WakeupPrescaler::Div16 => Wucksel::DIV16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l5, stm32wb, stm32h5, stm32g0))]
|
||||
impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler {
|
||||
fn from(val: crate::pac::rtc::vals::Wucksel) -> Self {
|
||||
use crate::pac::rtc::vals::Wucksel;
|
||||
|
||||
match val {
|
||||
Wucksel::DIV2 => WakeupPrescaler::Div2,
|
||||
Wucksel::DIV4 => WakeupPrescaler::Div4,
|
||||
Wucksel::DIV8 => WakeupPrescaler::Div8,
|
||||
Wucksel::DIV16 => WakeupPrescaler::Div16,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WakeupPrescaler {
|
||||
pub fn compute_min(val: u32) -> Self {
|
||||
*[
|
||||
WakeupPrescaler::Div2,
|
||||
WakeupPrescaler::Div4,
|
||||
WakeupPrescaler::Div8,
|
||||
WakeupPrescaler::Div16,
|
||||
]
|
||||
.iter()
|
||||
.find(|psc| **psc as u32 > val)
|
||||
.unwrap_or(&WakeupPrescaler::Div16)
|
||||
}
|
||||
}
|
||||
|
||||
impl Rtc {
|
||||
/// Return the current instant.
|
||||
fn instant(&self) -> Result<RtcInstant, RtcError> {
|
||||
self.time_provider().read(|_, tr, ss| {
|
||||
let second = bcd2_to_byte((tr.st(), tr.su()));
|
||||
|
||||
RtcInstant::from(second, ss).map_err(RtcError::InvalidDateTime)
|
||||
})
|
||||
}
|
||||
|
||||
/// start the wakeup alarm and with a duration that is as close to but less than
|
||||
/// the requested duration, and record the instant the wakeup alarm was started
|
||||
pub(crate) fn start_wakeup_alarm(
|
||||
&self,
|
||||
requested_duration: embassy_time::Duration,
|
||||
cs: critical_section::CriticalSection,
|
||||
) {
|
||||
use embassy_time::{Duration, TICK_HZ};
|
||||
|
||||
#[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
|
||||
use crate::pac::rtc::vals::Calrf;
|
||||
|
||||
// Panic if the rcc mod knows we're not using low-power rtc
|
||||
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
|
||||
unsafe { crate::rcc::get_freqs() }.rtc.unwrap();
|
||||
|
||||
let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64);
|
||||
let rtc_hz = Self::frequency().0 as u64;
|
||||
let rtc_ticks = requested_duration * rtc_hz / TICK_HZ;
|
||||
let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32);
|
||||
|
||||
// adjust the rtc ticks to the prescaler and subtract one rtc tick
|
||||
let rtc_ticks = rtc_ticks / prescaler as u64;
|
||||
let rtc_ticks = rtc_ticks.clamp(0, (u16::MAX - 1) as u64).saturating_sub(1) as u16;
|
||||
|
||||
self.write(false, |regs| {
|
||||
regs.cr().modify(|w| w.set_wute(false));
|
||||
|
||||
#[cfg(any(
|
||||
rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb
|
||||
))]
|
||||
{
|
||||
regs.isr().modify(|w| w.set_wutf(false));
|
||||
while !regs.isr().read().wutwf() {}
|
||||
}
|
||||
|
||||
#[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
|
||||
{
|
||||
regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR));
|
||||
while !regs.icsr().read().wutwf() {}
|
||||
}
|
||||
|
||||
regs.cr().modify(|w| w.set_wucksel(prescaler.into()));
|
||||
regs.wutr().write(|w| w.set_wut(rtc_ticks));
|
||||
regs.cr().modify(|w| w.set_wute(true));
|
||||
regs.cr().modify(|w| w.set_wutie(true));
|
||||
});
|
||||
|
||||
let instant = self.instant().unwrap();
|
||||
trace!(
|
||||
"rtc: start wakeup alarm for {} ms (psc: {}, ticks: {}) at {}",
|
||||
Duration::from_ticks(rtc_ticks as u64 * TICK_HZ * prescaler as u64 / rtc_hz).as_millis(),
|
||||
prescaler as u32,
|
||||
rtc_ticks,
|
||||
instant,
|
||||
);
|
||||
|
||||
assert!(self.stop_time.borrow(cs).replace(Some(instant)).is_none())
|
||||
}
|
||||
|
||||
/// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm`
|
||||
/// was called, otherwise none
|
||||
pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> {
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
#[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
|
||||
use crate::pac::rtc::vals::Calrf;
|
||||
|
||||
let instant = self.instant().unwrap();
|
||||
if RTC::regs().cr().read().wute() {
|
||||
trace!("rtc: stop wakeup alarm at {}", instant);
|
||||
|
||||
self.write(false, |regs| {
|
||||
regs.cr().modify(|w| w.set_wutie(false));
|
||||
regs.cr().modify(|w| w.set_wute(false));
|
||||
|
||||
#[cfg(any(
|
||||
rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb
|
||||
))]
|
||||
regs.isr().modify(|w| w.set_wutf(false));
|
||||
|
||||
#[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
|
||||
regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR));
|
||||
|
||||
// Check RM for EXTI and/or NVIC section, "Event event input mapping" or "EXTI interrupt/event mapping" or something similar,
|
||||
// there is a table for every "Event input" / "EXTI Line".
|
||||
// If you find the EXTI line related to "RTC wakeup" marks as "Configurable" (not "Direct"),
|
||||
// then write 1 to related field of Pending Register, to clean it's pending state.
|
||||
#[cfg(any(exti_v1, stm32h7, stm32wb))]
|
||||
crate::pac::EXTI
|
||||
.pr(0)
|
||||
.modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
|
||||
|
||||
<RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend();
|
||||
});
|
||||
}
|
||||
|
||||
self.stop_time.borrow(cs).take().map(|stop_time| instant - stop_time)
|
||||
}
|
||||
|
||||
pub(crate) fn enable_wakeup_line(&self) {
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::pac::EXTI;
|
||||
|
||||
<RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend();
|
||||
unsafe { <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::enable() };
|
||||
|
||||
EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
|
||||
EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
|
||||
}
|
||||
}
|
@ -1,6 +1,9 @@
|
||||
//! Real Time Clock (RTC)
|
||||
mod datetime;
|
||||
|
||||
#[cfg(feature = "low-power")]
|
||||
mod low_power;
|
||||
|
||||
#[cfg(feature = "low-power")]
|
||||
use core::cell::Cell;
|
||||
|
||||
@ -9,8 +12,6 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
#[cfg(feature = "low-power")]
|
||||
use embassy_sync::blocking_mutex::Mutex;
|
||||
|
||||
#[cfg(not(rtc_v2f2))]
|
||||
use self::datetime::RtcInstant;
|
||||
use self::datetime::{day_of_week_from_u8, day_of_week_to_u8};
|
||||
pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError};
|
||||
use crate::pac::rtc::regs::{Dr, Tr};
|
||||
@ -32,60 +33,6 @@ use embassy_hal_internal::Peripheral;
|
||||
|
||||
use crate::peripherals::RTC;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub(crate) enum WakeupPrescaler {
|
||||
Div2 = 2,
|
||||
Div4 = 4,
|
||||
Div8 = 8,
|
||||
Div16 = 16,
|
||||
}
|
||||
|
||||
#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l5, stm32wb, stm32h5, stm32g0))]
|
||||
impl From<WakeupPrescaler> for crate::pac::rtc::vals::Wucksel {
|
||||
fn from(val: WakeupPrescaler) -> Self {
|
||||
use crate::pac::rtc::vals::Wucksel;
|
||||
|
||||
match val {
|
||||
WakeupPrescaler::Div2 => Wucksel::DIV2,
|
||||
WakeupPrescaler::Div4 => Wucksel::DIV4,
|
||||
WakeupPrescaler::Div8 => Wucksel::DIV8,
|
||||
WakeupPrescaler::Div16 => Wucksel::DIV16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(stm32f4, stm32l0, stm32g4, stm32l5, stm32wb, stm32h5, stm32g0))]
|
||||
impl From<crate::pac::rtc::vals::Wucksel> for WakeupPrescaler {
|
||||
fn from(val: crate::pac::rtc::vals::Wucksel) -> Self {
|
||||
use crate::pac::rtc::vals::Wucksel;
|
||||
|
||||
match val {
|
||||
Wucksel::DIV2 => WakeupPrescaler::Div2,
|
||||
Wucksel::DIV4 => WakeupPrescaler::Div4,
|
||||
Wucksel::DIV8 => WakeupPrescaler::Div8,
|
||||
Wucksel::DIV16 => WakeupPrescaler::Div16,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "low-power")]
|
||||
impl WakeupPrescaler {
|
||||
pub fn compute_min(val: u32) -> Self {
|
||||
*[
|
||||
WakeupPrescaler::Div2,
|
||||
WakeupPrescaler::Div4,
|
||||
WakeupPrescaler::Div8,
|
||||
WakeupPrescaler::Div16,
|
||||
]
|
||||
.iter()
|
||||
.find(|psc| **psc as u32 > val)
|
||||
.unwrap_or(&WakeupPrescaler::Div16)
|
||||
}
|
||||
}
|
||||
|
||||
/// Errors that can occur on methods on [RtcClock]
|
||||
#[non_exhaustive]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
@ -106,15 +53,6 @@ pub struct RtcTimeProvider {
|
||||
}
|
||||
|
||||
impl RtcTimeProvider {
|
||||
#[cfg(not(rtc_v2f2))]
|
||||
pub(crate) fn instant(&self) -> Result<RtcInstant, RtcError> {
|
||||
self.read(|_, tr, ss| {
|
||||
let second = bcd2_to_byte((tr.st(), tr.su()));
|
||||
|
||||
RtcInstant::from(second, ss).map_err(RtcError::InvalidDateTime)
|
||||
})
|
||||
}
|
||||
|
||||
/// Return the current datetime.
|
||||
///
|
||||
/// # Errors
|
||||
@ -165,8 +103,7 @@ impl RtcTimeProvider {
|
||||
/// RTC driver.
|
||||
pub struct Rtc {
|
||||
#[cfg(feature = "low-power")]
|
||||
stop_time: Mutex<CriticalSectionRawMutex, Cell<Option<RtcInstant>>>,
|
||||
#[cfg(not(feature = "low-power"))]
|
||||
stop_time: Mutex<CriticalSectionRawMutex, Cell<Option<low_power::RtcInstant>>>,
|
||||
_private: (),
|
||||
}
|
||||
|
||||
@ -205,12 +142,11 @@ impl Rtc {
|
||||
/// Create a new RTC instance.
|
||||
pub fn new(_rtc: impl Peripheral<P = RTC>, rtc_config: RtcConfig) -> Self {
|
||||
#[cfg(not(any(stm32l0, stm32f3, stm32l1, stm32f0, stm32f2)))]
|
||||
<RTC as crate::rcc::SealedRccPeripheral>::enable_and_reset();
|
||||
crate::rcc::enable_and_reset::<RTC>();
|
||||
|
||||
let mut this = Self {
|
||||
#[cfg(feature = "low-power")]
|
||||
stop_time: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)),
|
||||
#[cfg(not(feature = "low-power"))]
|
||||
_private: (),
|
||||
};
|
||||
|
||||
@ -223,9 +159,8 @@ impl Rtc {
|
||||
// Wait for the clock to update after initialization
|
||||
#[cfg(not(rtc_v2f2))]
|
||||
{
|
||||
let now = this.instant().unwrap();
|
||||
|
||||
while this.instant().unwrap().subsecond == now.subsecond {}
|
||||
let now = this.time_provider().read(|_, _, ss| Ok(ss)).unwrap();
|
||||
while now == this.time_provider().read(|_, _, ss| Ok(ss)).unwrap() {}
|
||||
}
|
||||
|
||||
this
|
||||
@ -284,12 +219,6 @@ impl Rtc {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(rtc_v2f2))]
|
||||
/// Return the current instant.
|
||||
fn instant(&self) -> Result<RtcInstant, RtcError> {
|
||||
self.time_provider().instant()
|
||||
}
|
||||
|
||||
/// Return the current datetime.
|
||||
///
|
||||
/// # Errors
|
||||
@ -320,7 +249,7 @@ impl Rtc {
|
||||
/// The registers retain their values during wakes from standby mode or system resets. They also
|
||||
/// retain their value when Vdd is switched off as long as V_BAT is powered.
|
||||
pub fn read_backup_register(&self, register: usize) -> Option<u32> {
|
||||
RTC::read_backup_register(&RTC::regs(), register)
|
||||
RTC::read_backup_register(RTC::regs(), register)
|
||||
}
|
||||
|
||||
/// Set content of the backup register.
|
||||
@ -328,120 +257,7 @@ impl Rtc {
|
||||
/// The registers retain their values during wakes from standby mode or system resets. They also
|
||||
/// retain their value when Vdd is switched off as long as V_BAT is powered.
|
||||
pub fn write_backup_register(&self, register: usize, value: u32) {
|
||||
RTC::write_backup_register(&RTC::regs(), register, value)
|
||||
}
|
||||
|
||||
#[cfg(feature = "low-power")]
|
||||
/// start the wakeup alarm and with a duration that is as close to but less than
|
||||
/// the requested duration, and record the instant the wakeup alarm was started
|
||||
pub(crate) fn start_wakeup_alarm(
|
||||
&self,
|
||||
requested_duration: embassy_time::Duration,
|
||||
cs: critical_section::CriticalSection,
|
||||
) {
|
||||
use embassy_time::{Duration, TICK_HZ};
|
||||
|
||||
#[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
|
||||
use crate::pac::rtc::vals::Calrf;
|
||||
|
||||
// Panic if the rcc mod knows we're not using low-power rtc
|
||||
#[cfg(any(rcc_wb, rcc_f4, rcc_f410))]
|
||||
unsafe { crate::rcc::get_freqs() }.rtc.unwrap();
|
||||
|
||||
let requested_duration = requested_duration.as_ticks().clamp(0, u32::MAX as u64);
|
||||
let rtc_hz = Self::frequency().0 as u64;
|
||||
let rtc_ticks = requested_duration * rtc_hz / TICK_HZ;
|
||||
let prescaler = WakeupPrescaler::compute_min((rtc_ticks / u16::MAX as u64) as u32);
|
||||
|
||||
// adjust the rtc ticks to the prescaler and subtract one rtc tick
|
||||
let rtc_ticks = rtc_ticks / prescaler as u64;
|
||||
let rtc_ticks = rtc_ticks.clamp(0, (u16::MAX - 1) as u64).saturating_sub(1) as u16;
|
||||
|
||||
self.write(false, |regs| {
|
||||
regs.cr().modify(|w| w.set_wute(false));
|
||||
|
||||
#[cfg(any(
|
||||
rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb
|
||||
))]
|
||||
{
|
||||
regs.isr().modify(|w| w.set_wutf(false));
|
||||
while !regs.isr().read().wutwf() {}
|
||||
}
|
||||
|
||||
#[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
|
||||
{
|
||||
regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR));
|
||||
while !regs.icsr().read().wutwf() {}
|
||||
}
|
||||
|
||||
regs.cr().modify(|w| w.set_wucksel(prescaler.into()));
|
||||
regs.wutr().write(|w| w.set_wut(rtc_ticks));
|
||||
regs.cr().modify(|w| w.set_wute(true));
|
||||
regs.cr().modify(|w| w.set_wutie(true));
|
||||
});
|
||||
|
||||
let instant = self.instant().unwrap();
|
||||
trace!(
|
||||
"rtc: start wakeup alarm for {} ms (psc: {}, ticks: {}) at {}",
|
||||
Duration::from_ticks(rtc_ticks as u64 * TICK_HZ * prescaler as u64 / rtc_hz).as_millis(),
|
||||
prescaler as u32,
|
||||
rtc_ticks,
|
||||
instant,
|
||||
);
|
||||
|
||||
assert!(self.stop_time.borrow(cs).replace(Some(instant)).is_none())
|
||||
}
|
||||
|
||||
#[cfg(feature = "low-power")]
|
||||
/// stop the wakeup alarm and return the time elapsed since `start_wakeup_alarm`
|
||||
/// was called, otherwise none
|
||||
pub(crate) fn stop_wakeup_alarm(&self, cs: critical_section::CriticalSection) -> Option<embassy_time::Duration> {
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
#[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
|
||||
use crate::pac::rtc::vals::Calrf;
|
||||
|
||||
let instant = self.instant().unwrap();
|
||||
if RTC::regs().cr().read().wute() {
|
||||
trace!("rtc: stop wakeup alarm at {}", instant);
|
||||
|
||||
self.write(false, |regs| {
|
||||
regs.cr().modify(|w| w.set_wutie(false));
|
||||
regs.cr().modify(|w| w.set_wute(false));
|
||||
|
||||
#[cfg(any(
|
||||
rtc_v2f0, rtc_v2f2, rtc_v2f3, rtc_v2f4, rtc_v2f7, rtc_v2h7, rtc_v2l0, rtc_v2l1, rtc_v2l4, rtc_v2wb
|
||||
))]
|
||||
regs.isr().modify(|w| w.set_wutf(false));
|
||||
|
||||
#[cfg(any(rtc_v3, rtc_v3u5, rtc_v3l5))]
|
||||
regs.scr().write(|w| w.set_cwutf(Calrf::CLEAR));
|
||||
|
||||
// Check RM for EXTI and/or NVIC section, "Event event input mapping" or "EXTI interrupt/event mapping" or something similar,
|
||||
// there is a table for every "Event input" / "EXTI Line".
|
||||
// If you find the EXTI line related to "RTC wakeup" marks as "Configurable" (not "Direct"),
|
||||
// then write 1 to related field of Pending Register, to clean it's pending state.
|
||||
#[cfg(any(exti_v1, stm32h7, stm32wb))]
|
||||
crate::pac::EXTI
|
||||
.pr(0)
|
||||
.modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
|
||||
|
||||
<RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend();
|
||||
});
|
||||
}
|
||||
|
||||
self.stop_time.borrow(cs).take().map(|stop_time| instant - stop_time)
|
||||
}
|
||||
|
||||
#[cfg(feature = "low-power")]
|
||||
pub(crate) fn enable_wakeup_line(&self) {
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::pac::EXTI;
|
||||
|
||||
<RTC as crate::rtc::SealedInstance>::WakeupInterrupt::unpend();
|
||||
unsafe { <RTC as crate::rtc::SealedInstance>::WakeupInterrupt::enable() };
|
||||
|
||||
EXTI.rtsr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
|
||||
EXTI.imr(0).modify(|w| w.set_line(RTC::EXTI_WAKEUP_LINE, true));
|
||||
RTC::write_backup_register(RTC::regs(), register, value)
|
||||
}
|
||||
}
|
||||
|
||||
@ -482,13 +298,13 @@ trait SealedInstance {
|
||||
///
|
||||
/// The registers retain their values during wakes from standby mode or system resets. They also
|
||||
/// retain their value when Vdd is switched off as long as V_BAT is powered.
|
||||
fn read_backup_register(rtc: &crate::pac::rtc::Rtc, register: usize) -> Option<u32>;
|
||||
fn read_backup_register(rtc: crate::pac::rtc::Rtc, register: usize) -> Option<u32>;
|
||||
|
||||
/// Set content of the backup register.
|
||||
///
|
||||
/// The registers retain their values during wakes from standby mode or system resets. They also
|
||||
/// retain their value when Vdd is switched off as long as V_BAT is powered.
|
||||
fn write_backup_register(rtc: &crate::pac::rtc::Rtc, register: usize, value: u32);
|
||||
fn write_backup_register(rtc: crate::pac::rtc::Rtc, register: usize, value: u32);
|
||||
|
||||
// fn apply_config(&mut self, rtc_config: RtcConfig);
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ impl super::Rtc {
|
||||
|
||||
pub(super) fn write<F, R>(&self, init_mode: bool, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&crate::pac::rtc::Rtc) -> R,
|
||||
F: FnOnce(crate::pac::rtc::Rtc) -> R,
|
||||
{
|
||||
let r = RTC::regs();
|
||||
// Disable write protection.
|
||||
@ -112,7 +112,7 @@ impl super::Rtc {
|
||||
while !r.isr().read().initf() {}
|
||||
}
|
||||
|
||||
let result = f(&r);
|
||||
let result = f(r);
|
||||
|
||||
if init_mode {
|
||||
r.isr().modify(|w| w.set_init(false)); // Exits init mode
|
||||
@ -140,7 +140,7 @@ impl SealedInstance for crate::peripherals::RTC {
|
||||
#[cfg(all(feature = "low-power", stm32l0))]
|
||||
type WakeupInterrupt = crate::interrupt::typelevel::RTC;
|
||||
|
||||
fn read_backup_register(rtc: &Rtc, register: usize) -> Option<u32> {
|
||||
fn read_backup_register(rtc: Rtc, register: usize) -> Option<u32> {
|
||||
if register < Self::BACKUP_REGISTER_COUNT {
|
||||
Some(rtc.bkpr(register).read().bkp())
|
||||
} else {
|
||||
@ -148,7 +148,7 @@ impl SealedInstance for crate::peripherals::RTC {
|
||||
}
|
||||
}
|
||||
|
||||
fn write_backup_register(rtc: &Rtc, register: usize, value: u32) {
|
||||
fn write_backup_register(rtc: Rtc, register: usize, value: u32) {
|
||||
if register < Self::BACKUP_REGISTER_COUNT {
|
||||
rtc.bkpr(register).write(|w| w.set_bkp(value));
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ impl super::Rtc {
|
||||
|
||||
pub(super) fn write<F, R>(&self, init_mode: bool, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&crate::pac::rtc::Rtc) -> R,
|
||||
F: FnOnce(crate::pac::rtc::Rtc) -> R,
|
||||
{
|
||||
let r = RTC::regs();
|
||||
// Disable write protection.
|
||||
@ -112,7 +112,7 @@ impl super::Rtc {
|
||||
while !r.icsr().read().initf() {}
|
||||
}
|
||||
|
||||
let result = f(&r);
|
||||
let result = f(r);
|
||||
|
||||
if init_mode {
|
||||
r.icsr().modify(|w| w.set_init(false)); // Exits init mode
|
||||
@ -143,7 +143,7 @@ impl SealedInstance for crate::peripherals::RTC {
|
||||
}
|
||||
);
|
||||
|
||||
fn read_backup_register(_rtc: &Rtc, register: usize) -> Option<u32> {
|
||||
fn read_backup_register(_rtc: Rtc, register: usize) -> Option<u32> {
|
||||
#[allow(clippy::if_same_then_else)]
|
||||
if register < Self::BACKUP_REGISTER_COUNT {
|
||||
//Some(rtc.bkpr()[register].read().bits())
|
||||
@ -153,7 +153,7 @@ impl SealedInstance for crate::peripherals::RTC {
|
||||
}
|
||||
}
|
||||
|
||||
fn write_backup_register(_rtc: &Rtc, register: usize, _value: u32) {
|
||||
fn write_backup_register(_rtc: Rtc, register: usize, _value: u32) {
|
||||
if register < Self::BACKUP_REGISTER_COUNT {
|
||||
// RTC3 backup registers come from the TAMP peripheral, not RTC. Not() even in the L412 PAC
|
||||
//self.rtc.bkpr()[register].write(|w| w.bits(value))
|
||||
|
@ -11,7 +11,7 @@ pub use crate::dma::word;
|
||||
use crate::dma::{ringbuffer, Channel, ReadableRingBuffer, Request, TransferOptions, WritableRingBuffer};
|
||||
use crate::gpio::{AFType, AnyPin, SealedPin as _};
|
||||
use crate::pac::sai::{vals, Sai as Regs};
|
||||
use crate::rcc::RccPeripheral;
|
||||
use crate::rcc::{self, RccPeripheral};
|
||||
use crate::{peripherals, Peripheral};
|
||||
|
||||
/// SAI error
|
||||
@ -722,7 +722,7 @@ pub struct SubBlock<'d, T, S: SubBlockInstance> {
|
||||
/// You can then create a [`Sai`] driver for each each half.
|
||||
pub fn split_subblocks<'d, T: Instance>(peri: impl Peripheral<P = T> + 'd) -> (SubBlock<'d, T, A>, SubBlock<'d, T, B>) {
|
||||
into_ref!(peri);
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
|
||||
(
|
||||
SubBlock {
|
||||
@ -978,7 +978,7 @@ impl<'d, T: Instance, W: word::Word> Sai<'d, T, W> {
|
||||
|
||||
/// Reset SAI operation.
|
||||
pub fn reset() {
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
}
|
||||
|
||||
/// Flush.
|
||||
|
@ -16,7 +16,7 @@ use crate::dma::NoDma;
|
||||
use crate::gpio::{AFType, AnyPin, Pull, SealedPin, Speed};
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::pac::sdmmc::Sdmmc as RegBlock;
|
||||
use crate::rcc::RccPeripheral;
|
||||
use crate::rcc::{self, RccPeripheral};
|
||||
use crate::time::Hertz;
|
||||
use crate::{interrupt, peripherals, Peripheral};
|
||||
|
||||
@ -468,7 +468,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
) -> Self {
|
||||
into_ref!(sdmmc, dma);
|
||||
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
|
||||
T::Interrupt::unpend();
|
||||
unsafe { T::Interrupt::enable() };
|
||||
|
@ -13,7 +13,7 @@ use crate::dma::{slice_ptr_parts, word, ChannelAndRequest};
|
||||
use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed};
|
||||
use crate::mode::{Async, Blocking, Mode as PeriMode};
|
||||
use crate::pac::spi::{regs, vals, Spi as Regs};
|
||||
use crate::rcc::{ClockEnableBit, SealedRccPeripheral};
|
||||
use crate::rcc::{RccInfo, SealedRccPeripheral};
|
||||
use crate::time::Hertz;
|
||||
use crate::Peripheral;
|
||||
|
||||
@ -120,17 +120,30 @@ impl<'d, M: PeriMode> Spi<'d, M> {
|
||||
rx_dma: Option<ChannelAndRequest<'d>>,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
let regs = T::info().regs;
|
||||
let kernel_clock = T::frequency();
|
||||
let br = compute_baud_rate(kernel_clock, config.frequency);
|
||||
let mut this = Self {
|
||||
info: T::info(),
|
||||
kernel_clock: T::frequency(),
|
||||
sck,
|
||||
mosi,
|
||||
miso,
|
||||
tx_dma,
|
||||
rx_dma,
|
||||
current_word_size: <u8 as SealedWord>::CONFIG,
|
||||
_phantom: PhantomData,
|
||||
};
|
||||
this.enable_and_init(config);
|
||||
this
|
||||
}
|
||||
|
||||
fn enable_and_init(&mut self, config: Config) {
|
||||
let br = compute_baud_rate(self.kernel_clock, config.frequency);
|
||||
let cpha = config.raw_phase();
|
||||
let cpol = config.raw_polarity();
|
||||
|
||||
let lsbfirst = config.raw_byte_order();
|
||||
|
||||
T::enable_and_reset();
|
||||
self.info.rcc.enable_and_reset();
|
||||
|
||||
let regs = self.info.regs;
|
||||
#[cfg(any(spi_v1, spi_f1))]
|
||||
{
|
||||
regs.cr2().modify(|w| {
|
||||
@ -148,9 +161,10 @@ impl<'d, M: PeriMode> Spi<'d, M> {
|
||||
w.set_ssm(true);
|
||||
w.set_crcen(false);
|
||||
w.set_bidimode(vals::Bidimode::UNIDIRECTIONAL);
|
||||
if mosi.is_none() {
|
||||
w.set_rxonly(vals::Rxonly::OUTPUTDISABLED);
|
||||
}
|
||||
// we're doing "fake rxonly", by actually writing one
|
||||
// byte to TXDR for each byte we want to receive. if we
|
||||
// set OUTPUTDISABLED here, this hangs.
|
||||
w.set_rxonly(vals::Rxonly::FULLDUPLEX);
|
||||
w.set_dff(<u8 as SealedWord>::CONFIG)
|
||||
});
|
||||
}
|
||||
@ -208,18 +222,6 @@ impl<'d, M: PeriMode> Spi<'d, M> {
|
||||
w.set_spe(true);
|
||||
});
|
||||
}
|
||||
|
||||
Self {
|
||||
info: T::info(),
|
||||
kernel_clock,
|
||||
sck,
|
||||
mosi,
|
||||
miso,
|
||||
tx_dma,
|
||||
rx_dma,
|
||||
current_word_size: <u8 as SealedWord>::CONFIG,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Reconfigures it with the supplied config.
|
||||
@ -350,17 +352,46 @@ impl<'d, M: PeriMode> Spi<'d, M> {
|
||||
|
||||
/// Blocking write.
|
||||
pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
|
||||
// needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...?
|
||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||
self.info.regs.cr1().modify(|w| w.set_spe(false));
|
||||
self.info.regs.cr1().modify(|w| w.set_spe(true));
|
||||
flush_rx_fifo(self.info.regs);
|
||||
self.set_word_size(W::CONFIG);
|
||||
for word in words.iter() {
|
||||
let _ = transfer_word(self.info.regs, *word)?;
|
||||
// this cannot use `transfer_word` because on SPIv2 and higher,
|
||||
// the SPI RX state machine hangs if no physical pin is connected to the SCK AF.
|
||||
// This is the case when the SPI has been created with `new_(blocking_?)txonly_nosck`.
|
||||
// See https://github.com/embassy-rs/embassy/issues/2902
|
||||
// This is not documented as an errata by ST, and I've been unable to find anything online...
|
||||
#[cfg(not(any(spi_v1, spi_f1)))]
|
||||
write_word(self.info.regs, *word)?;
|
||||
|
||||
// if we're doing tx only, after writing the last byte to FIFO we have to wait
|
||||
// until it's actually sent. On SPIv1 you're supposed to use the BSY flag for this
|
||||
// but apparently it's broken, it clears too soon. Workaround is to wait for RXNE:
|
||||
// when it gets set you know the transfer is done, even if you don't care about rx.
|
||||
// Luckily this doesn't affect SPIv2+.
|
||||
// See http://efton.sk/STM32/gotcha/g68.html
|
||||
// ST doesn't seem to document this in errata sheets (?)
|
||||
#[cfg(any(spi_v1, spi_f1))]
|
||||
transfer_word(self.info.regs, *word)?;
|
||||
}
|
||||
|
||||
// wait until last word is transmitted. (except on v1, see above)
|
||||
#[cfg(not(any(spi_v1, spi_f1, spi_v2)))]
|
||||
while !self.info.regs.sr().read().txc() {}
|
||||
#[cfg(spi_v2)]
|
||||
while self.info.regs.sr().read().bsy() {}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Blocking read.
|
||||
pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
|
||||
// needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...?
|
||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||
self.info.regs.cr1().modify(|w| w.set_spe(false));
|
||||
self.info.regs.cr1().modify(|w| w.set_spe(true));
|
||||
flush_rx_fifo(self.info.regs);
|
||||
self.set_word_size(W::CONFIG);
|
||||
@ -374,6 +405,9 @@ impl<'d, M: PeriMode> Spi<'d, M> {
|
||||
///
|
||||
/// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time.
|
||||
pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
|
||||
// needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...?
|
||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||
self.info.regs.cr1().modify(|w| w.set_spe(false));
|
||||
self.info.regs.cr1().modify(|w| w.set_spe(true));
|
||||
flush_rx_fifo(self.info.regs);
|
||||
self.set_word_size(W::CONFIG);
|
||||
@ -390,6 +424,9 @@ impl<'d, M: PeriMode> Spi<'d, M> {
|
||||
/// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
|
||||
/// If `write` is shorter it is padded with zero bytes.
|
||||
pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
|
||||
// needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...?
|
||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||
self.info.regs.cr1().modify(|w| w.set_spe(false));
|
||||
self.info.regs.cr1().modify(|w| w.set_spe(true));
|
||||
flush_rx_fifo(self.info.regs);
|
||||
self.set_word_size(W::CONFIG);
|
||||
@ -508,6 +545,7 @@ impl<'d> Spi<'d, Async> {
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
sck: impl Peripheral<P = impl SckPin<T>> + 'd,
|
||||
miso: impl Peripheral<P = impl MisoPin<T>> + 'd,
|
||||
#[cfg(any(spi_v1, spi_f1, spi_v2))] tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
|
||||
rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
@ -516,6 +554,9 @@ impl<'d> Spi<'d, Async> {
|
||||
new_pin!(sck, AFType::OutputPushPull, Speed::VeryHigh, config.sck_pull_mode()),
|
||||
None,
|
||||
new_pin!(miso, AFType::Input, Speed::VeryHigh),
|
||||
#[cfg(any(spi_v1, spi_f1, spi_v2))]
|
||||
new_dma!(tx_dma),
|
||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||
None,
|
||||
new_dma!(rx_dma),
|
||||
config,
|
||||
@ -571,7 +612,7 @@ impl<'d> Spi<'d, Async> {
|
||||
// see RM0453 rev 1 section 7.2.13 page 291
|
||||
// The SUBGHZSPI_SCK frequency is obtained by PCLK3 divided by two.
|
||||
// The SUBGHZSPI_SCK clock maximum speed must not exceed 16 MHz.
|
||||
let pclk3_freq = <crate::peripherals::SUBGHZSPI as crate::rcc::SealedRccPeripheral>::frequency().0;
|
||||
let pclk3_freq = <crate::peripherals::SUBGHZSPI as SealedRccPeripheral>::frequency().0;
|
||||
let freq = Hertz(core::cmp::min(pclk3_freq / 2, 16_000_000));
|
||||
let mut config = Config::default();
|
||||
config.mode = MODE_0;
|
||||
@ -584,11 +625,11 @@ impl<'d> Spi<'d, Async> {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn new_internal<T: Instance>(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
tx_dma: impl Peripheral<P = impl TxDma<T>> + 'd,
|
||||
rx_dma: impl Peripheral<P = impl RxDma<T>> + 'd,
|
||||
tx_dma: Option<ChannelAndRequest<'d>>,
|
||||
rx_dma: Option<ChannelAndRequest<'d>>,
|
||||
config: Config,
|
||||
) -> Self {
|
||||
Self::new_inner(peri, None, None, None, new_dma!(tx_dma), new_dma!(rx_dma), config)
|
||||
Self::new_inner(peri, None, None, None, tx_dma, rx_dma, config)
|
||||
}
|
||||
|
||||
/// SPI write, using DMA.
|
||||
@ -622,12 +663,100 @@ impl<'d> Spi<'d, Async> {
|
||||
}
|
||||
|
||||
/// SPI read, using DMA.
|
||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||
pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
|
||||
if data.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let regs = self.info.regs;
|
||||
|
||||
regs.cr1().modify(|w| {
|
||||
w.set_spe(false);
|
||||
});
|
||||
|
||||
let comm = regs.cfg2().modify(|w| {
|
||||
let prev = w.comm();
|
||||
w.set_comm(vals::Comm::RECEIVER);
|
||||
prev
|
||||
});
|
||||
|
||||
#[cfg(spi_v3)]
|
||||
let i2scfg = regs.i2scfgr().modify(|w| {
|
||||
w.i2smod().then(|| {
|
||||
let prev = w.i2scfg();
|
||||
w.set_i2scfg(match prev {
|
||||
vals::I2scfg::SLAVERX | vals::I2scfg::SLAVEFULLDUPLEX => vals::I2scfg::SLAVERX,
|
||||
vals::I2scfg::MASTERRX | vals::I2scfg::MASTERFULLDUPLEX => vals::I2scfg::MASTERRX,
|
||||
_ => panic!("unsupported configuration"),
|
||||
});
|
||||
prev
|
||||
})
|
||||
});
|
||||
|
||||
let rx_src = regs.rx_ptr();
|
||||
|
||||
for mut chunk in data.chunks_mut(u16::max_value().into()) {
|
||||
self.set_word_size(W::CONFIG);
|
||||
set_rxdmaen(regs, true);
|
||||
|
||||
let tsize = chunk.len();
|
||||
|
||||
let transfer = unsafe {
|
||||
self.rx_dma
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.read(rx_src, &mut chunk, Default::default())
|
||||
};
|
||||
|
||||
regs.cr2().modify(|w| {
|
||||
w.set_tsize(tsize as u16);
|
||||
});
|
||||
|
||||
regs.cr1().modify(|w| {
|
||||
w.set_spe(true);
|
||||
});
|
||||
|
||||
regs.cr1().modify(|w| {
|
||||
w.set_cstart(true);
|
||||
});
|
||||
|
||||
transfer.await;
|
||||
|
||||
finish_dma(regs);
|
||||
}
|
||||
|
||||
regs.cr1().modify(|w| {
|
||||
w.set_spe(false);
|
||||
});
|
||||
|
||||
regs.cfg2().modify(|w| {
|
||||
w.set_comm(comm);
|
||||
});
|
||||
|
||||
regs.cr2().modify(|w| {
|
||||
w.set_tsize(0);
|
||||
});
|
||||
|
||||
#[cfg(spi_v3)]
|
||||
if let Some(i2scfg) = i2scfg {
|
||||
regs.i2scfgr().modify(|w| {
|
||||
w.set_i2scfg(i2scfg);
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// SPI read, using DMA.
|
||||
#[cfg(any(spi_v1, spi_f1, spi_v2))]
|
||||
pub async fn read<W: Word>(&mut self, data: &mut [W]) -> Result<(), Error> {
|
||||
if data.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.set_word_size(W::CONFIG);
|
||||
|
||||
self.info.regs.cr1().modify(|w| {
|
||||
w.set_spe(false);
|
||||
});
|
||||
@ -738,7 +867,7 @@ impl<'d, M: PeriMode> Drop for Spi<'d, M> {
|
||||
self.mosi.as_ref().map(|x| x.set_as_disconnected());
|
||||
self.miso.as_ref().map(|x| x.set_as_disconnected());
|
||||
|
||||
self.info.enable_bit.disable();
|
||||
self.info.rcc.disable();
|
||||
}
|
||||
}
|
||||
|
||||
@ -805,8 +934,8 @@ impl RegsExt for Regs {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_error_flags(sr: regs::Sr) -> Result<(), Error> {
|
||||
if sr.ovr() {
|
||||
fn check_error_flags(sr: regs::Sr, ovr: bool) -> Result<(), Error> {
|
||||
if sr.ovr() && ovr {
|
||||
return Err(Error::Overrun);
|
||||
}
|
||||
#[cfg(not(any(spi_f1, spi_v3, spi_v4, spi_v5)))]
|
||||
@ -832,11 +961,11 @@ fn check_error_flags(sr: regs::Sr) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn spin_until_tx_ready(regs: Regs) -> Result<(), Error> {
|
||||
fn spin_until_tx_ready(regs: Regs, ovr: bool) -> Result<(), Error> {
|
||||
loop {
|
||||
let sr = regs.sr().read();
|
||||
|
||||
check_error_flags(sr)?;
|
||||
check_error_flags(sr, ovr)?;
|
||||
|
||||
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
|
||||
if sr.txe() {
|
||||
@ -853,7 +982,7 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> {
|
||||
loop {
|
||||
let sr = regs.sr().read();
|
||||
|
||||
check_error_flags(sr)?;
|
||||
check_error_flags(sr, true)?;
|
||||
|
||||
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
|
||||
if sr.rxne() {
|
||||
@ -907,7 +1036,13 @@ fn finish_dma(regs: Regs) {
|
||||
while regs.sr().read().ftlvl().to_bits() > 0 {}
|
||||
|
||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||
while !regs.sr().read().txc() {}
|
||||
{
|
||||
if regs.cr2().read().tsize() == 0 {
|
||||
while !regs.sr().read().txc() {}
|
||||
} else {
|
||||
while !regs.sr().read().eot() {}
|
||||
}
|
||||
}
|
||||
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
|
||||
while regs.sr().read().bsy() {}
|
||||
|
||||
@ -931,7 +1066,7 @@ fn finish_dma(regs: Regs) {
|
||||
}
|
||||
|
||||
fn transfer_word<W: Word>(regs: Regs, tx_word: W) -> Result<W, Error> {
|
||||
spin_until_tx_ready(regs)?;
|
||||
spin_until_tx_ready(regs, true)?;
|
||||
|
||||
unsafe {
|
||||
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> {
|
||||
Ok(rx_word)
|
||||
}
|
||||
|
||||
#[allow(unused)] // unused in SPIv1
|
||||
fn write_word<W: Word>(regs: Regs, tx_word: W) -> Result<(), Error> {
|
||||
// for write, we intentionally ignore the rx fifo, which will cause
|
||||
// overrun errors that we have to ignore.
|
||||
spin_until_tx_ready(regs, false)?;
|
||||
|
||||
unsafe {
|
||||
ptr::write_volatile(regs.tx_ptr(), tx_word);
|
||||
|
||||
#[cfg(any(spi_v3, spi_v4, spi_v5))]
|
||||
regs.cr1().modify(|reg| reg.set_cstart(true));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Note: It is not possible to impl these traits generically in embedded-hal 0.2 due to a conflict with
|
||||
// some marker traits. For details, see https://github.com/rust-embedded/embedded-hal/pull/289
|
||||
macro_rules! impl_blocking {
|
||||
@ -1118,7 +1268,7 @@ mod word_impl {
|
||||
|
||||
pub(crate) struct Info {
|
||||
pub(crate) regs: Regs,
|
||||
pub(crate) enable_bit: ClockEnableBit,
|
||||
pub(crate) rcc: RccInfo,
|
||||
}
|
||||
|
||||
struct State {}
|
||||
@ -1145,7 +1295,7 @@ foreach_peripheral!(
|
||||
(spi, $inst:ident) => {
|
||||
peri_trait_impl!($inst, Info {
|
||||
regs: crate::pac::$inst,
|
||||
enable_bit: crate::peripherals::$inst::ENABLE_BIT,
|
||||
rcc: crate::peripherals::$inst::RCC_INFO,
|
||||
});
|
||||
};
|
||||
);
|
||||
|
@ -12,7 +12,7 @@ use stm32_metapac::timer::{regs, TimGp16};
|
||||
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::pac::timer::vals;
|
||||
use crate::rcc::SealedRccPeripheral;
|
||||
use crate::rcc::{self, SealedRccPeripheral};
|
||||
#[cfg(feature = "low-power")]
|
||||
use crate::rtc::Rtc;
|
||||
use crate::timer::{CoreInstance, GeneralInstance1Channel};
|
||||
@ -276,7 +276,7 @@ impl RtcDriver {
|
||||
fn init(&'static self, cs: critical_section::CriticalSection) {
|
||||
let r = regs_gp16();
|
||||
|
||||
<T as SealedRccPeripheral>::enable_and_reset_with_cs(cs);
|
||||
rcc::enable_and_reset_with_cs::<T>(cs);
|
||||
|
||||
let timer_freq = T::frequency();
|
||||
|
||||
|
@ -7,7 +7,7 @@ use core::task::{Context, Poll};
|
||||
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
|
||||
use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, Timer};
|
||||
use super::low_level::{CountingMode, FilterValue, InputCaptureMode, InputTISelection, Timer};
|
||||
use super::{
|
||||
CaptureCompareInterruptHandler, Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin,
|
||||
GeneralInstance4Channel,
|
||||
@ -40,11 +40,9 @@ macro_rules! channel_impl {
|
||||
#[doc = concat!("Create a new ", stringify!($channel), " capture pin instance.")]
|
||||
pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, pull_type: Pull) -> Self {
|
||||
into_ref!(pin);
|
||||
critical_section::with(|_| {
|
||||
pin.set_as_af_pull(pin.af_num(), AFType::Input, pull_type);
|
||||
#[cfg(gpio_v2)]
|
||||
pin.set_speed(crate::gpio::Speed::VeryHigh);
|
||||
});
|
||||
|
||||
pin.set_as_af_pull(pin.af_num(), AFType::Input, pull_type);
|
||||
|
||||
CapturePin {
|
||||
_pin: pin.map_into(),
|
||||
phantom: PhantomData,
|
||||
@ -83,7 +81,7 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
|
||||
let mut this = Self { inner: Timer::new(tim) };
|
||||
|
||||
this.inner.set_counting_mode(counting_mode);
|
||||
this.set_tick_freq(freq);
|
||||
this.inner.set_tick_freq(freq);
|
||||
this.inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details
|
||||
this.inner.start();
|
||||
|
||||
@ -109,24 +107,6 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
|
||||
self.inner.get_channel_enable_state(channel)
|
||||
}
|
||||
|
||||
/// Set tick frequency.
|
||||
///
|
||||
/// Note: when you call this, the max period value changes
|
||||
pub fn set_tick_freq(&mut self, freq: Hertz) {
|
||||
let f = freq;
|
||||
assert!(f.0 > 0);
|
||||
let timer_f = self.inner.get_clock_frequency();
|
||||
|
||||
let pclk_ticks_per_timer_period = timer_f / f;
|
||||
let psc: u16 = unwrap!((pclk_ticks_per_timer_period - 1).try_into());
|
||||
|
||||
let regs = self.inner.regs_core();
|
||||
regs.psc().write_value(psc);
|
||||
|
||||
// Generate an Update Request
|
||||
regs.egr().write(|r| r.set_ug(true));
|
||||
}
|
||||
|
||||
/// Set the input capture mode for a given channel.
|
||||
pub fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) {
|
||||
self.inner.set_input_capture_mode(channel, mode);
|
||||
@ -148,10 +128,13 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
|
||||
}
|
||||
|
||||
fn new_future(&self, channel: Channel, mode: InputCaptureMode, tisel: InputTISelection) -> InputCaptureFuture<T> {
|
||||
self.inner.enable_channel(channel, true);
|
||||
self.inner.set_input_capture_mode(channel, mode);
|
||||
// Configuration steps from ST RM0390 (STM32F446) chapter 17.3.5
|
||||
// or ST RM0008 (STM32F103) chapter 15.3.5 Input capture mode
|
||||
self.inner.set_input_ti_selection(channel, tisel);
|
||||
self.inner.clear_input_interrupt(channel);
|
||||
self.inner.set_input_capture_filter(channel, FilterValue::NOFILTER);
|
||||
self.inner.set_input_capture_mode(channel, mode);
|
||||
self.inner.set_input_capture_prescaler(channel, 0);
|
||||
self.inner.enable_channel(channel, true);
|
||||
self.inner.enable_input_interrupt(channel, true);
|
||||
|
||||
InputCaptureFuture {
|
||||
|
@ -7,9 +7,12 @@
|
||||
//! The available functionality depends on the timer type.
|
||||
|
||||
use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
|
||||
// Re-export useful enums
|
||||
pub use stm32_metapac::timer::vals::{FilterValue, Sms as SlaveMode, Ts as TriggerSource};
|
||||
|
||||
use super::*;
|
||||
use crate::pac::timer::vals;
|
||||
use crate::rcc;
|
||||
use crate::time::Hertz;
|
||||
|
||||
/// Input capture mode.
|
||||
@ -181,7 +184,7 @@ pub struct Timer<'d, T: CoreInstance> {
|
||||
|
||||
impl<'d, T: CoreInstance> Drop for Timer<'d, T> {
|
||||
fn drop(&mut self) {
|
||||
T::disable()
|
||||
rcc::disable::<T>();
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,7 +193,7 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
|
||||
pub fn new(tim: impl Peripheral<P = T> + 'd) -> Self {
|
||||
into_ref!(tim);
|
||||
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
|
||||
Self { tim }
|
||||
}
|
||||
@ -273,6 +276,22 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Set tick frequency.
|
||||
pub fn set_tick_freq(&mut self, freq: Hertz) {
|
||||
let f = freq;
|
||||
assert!(f.0 > 0);
|
||||
let timer_f = self.get_clock_frequency();
|
||||
|
||||
let pclk_ticks_per_timer_period = timer_f / f;
|
||||
let psc: u16 = unwrap!((pclk_ticks_per_timer_period - 1).try_into());
|
||||
|
||||
let regs = self.regs_core();
|
||||
regs.psc().write_value(psc);
|
||||
|
||||
// Generate an Update Request
|
||||
regs.egr().write(|r| r.set_ug(true));
|
||||
}
|
||||
|
||||
/// Clear update interrupt.
|
||||
///
|
||||
/// Returns whether the update interrupt flag was set.
|
||||
@ -572,6 +591,16 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
|
||||
pub fn set_cc_dma_enable_state(&self, channel: Channel, ccde: bool) {
|
||||
self.regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde))
|
||||
}
|
||||
|
||||
/// Set Timer Slave Mode
|
||||
pub fn set_slave_mode(&self, sms: SlaveMode) {
|
||||
self.regs_gp16().smcr().modify(|r| r.set_sms(sms));
|
||||
}
|
||||
|
||||
/// Set Timer Trigger Source
|
||||
pub fn set_trigger_source(&self, ts: TriggerSource) {
|
||||
self.regs_gp16().smcr().modify(|r| r.set_ts(ts));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stm32l0))]
|
||||
|
@ -8,6 +8,7 @@ use embassy_sync::waitqueue::AtomicWaker;
|
||||
pub mod complementary_pwm;
|
||||
pub mod input_capture;
|
||||
pub mod low_level;
|
||||
pub mod pwm_input;
|
||||
pub mod qei;
|
||||
pub mod simple_pwm;
|
||||
|
||||
|
114
embassy-stm32/src/timer/pwm_input.rs
Normal file
114
embassy-stm32/src/timer/pwm_input.rs
Normal file
@ -0,0 +1,114 @@
|
||||
//! PWM Input driver.
|
||||
|
||||
use embassy_hal_internal::into_ref;
|
||||
|
||||
use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource};
|
||||
use super::{Channel, Channel1Pin, Channel2Pin, GeneralInstance4Channel};
|
||||
use crate::gpio::{AFType, Pull};
|
||||
use crate::time::Hertz;
|
||||
use crate::Peripheral;
|
||||
|
||||
/// PWM Input driver.
|
||||
pub struct PwmInput<'d, T: GeneralInstance4Channel> {
|
||||
channel: Channel,
|
||||
inner: Timer<'d, T>,
|
||||
}
|
||||
|
||||
impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> {
|
||||
/// Create a new PWM input driver.
|
||||
pub fn new(
|
||||
tim: impl Peripheral<P = T> + 'd,
|
||||
pin: impl Peripheral<P = impl Channel1Pin<T>> + 'd,
|
||||
pull_type: Pull,
|
||||
freq: Hertz,
|
||||
) -> Self {
|
||||
into_ref!(pin);
|
||||
|
||||
pin.set_as_af_pull(pin.af_num(), AFType::Input, pull_type);
|
||||
|
||||
Self::new_inner(tim, freq, Channel::Ch1, Channel::Ch2)
|
||||
}
|
||||
|
||||
/// Create a new PWM input driver.
|
||||
pub fn new_alt(
|
||||
tim: impl Peripheral<P = T> + 'd,
|
||||
pin: impl Peripheral<P = impl Channel2Pin<T>> + 'd,
|
||||
pull_type: Pull,
|
||||
freq: Hertz,
|
||||
) -> Self {
|
||||
into_ref!(pin);
|
||||
|
||||
pin.set_as_af_pull(pin.af_num(), AFType::Input, pull_type);
|
||||
|
||||
Self::new_inner(tim, freq, Channel::Ch2, Channel::Ch1)
|
||||
}
|
||||
|
||||
fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz, ch1: Channel, ch2: Channel) -> Self {
|
||||
let mut inner = Timer::new(tim);
|
||||
|
||||
inner.set_counting_mode(CountingMode::EdgeAlignedUp);
|
||||
inner.set_tick_freq(freq);
|
||||
inner.enable_outputs(); // Required for advanced timers, see GeneralInstance4Channel for details
|
||||
inner.start();
|
||||
|
||||
// Configuration steps from ST RM0390 (STM32F446) chapter 17.3.6
|
||||
// or ST RM0008 (STM32F103) chapter 15.3.6 Input capture mode
|
||||
inner.set_input_ti_selection(ch1, InputTISelection::Normal);
|
||||
inner.set_input_capture_mode(ch1, InputCaptureMode::Rising);
|
||||
|
||||
inner.set_input_ti_selection(ch2, InputTISelection::Alternate);
|
||||
inner.set_input_capture_mode(ch2, InputCaptureMode::Falling);
|
||||
|
||||
inner.set_trigger_source(match ch1 {
|
||||
Channel::Ch1 => TriggerSource::TI1FP1,
|
||||
Channel::Ch2 => TriggerSource::TI2FP2,
|
||||
_ => panic!("Invalid channel for PWM input"),
|
||||
});
|
||||
|
||||
inner.set_slave_mode(SlaveMode::RESET_MODE);
|
||||
|
||||
// Must call the `enable` function after
|
||||
|
||||
Self { channel: ch1, inner }
|
||||
}
|
||||
|
||||
/// Enable the given channel.
|
||||
pub fn enable(&mut self) {
|
||||
self.inner.enable_channel(Channel::Ch1, true);
|
||||
self.inner.enable_channel(Channel::Ch2, true);
|
||||
}
|
||||
|
||||
/// Disable the given channel.
|
||||
pub fn disable(&mut self) {
|
||||
self.inner.enable_channel(Channel::Ch1, false);
|
||||
self.inner.enable_channel(Channel::Ch2, false);
|
||||
}
|
||||
|
||||
/// Check whether given channel is enabled
|
||||
pub fn is_enabled(&self) -> bool {
|
||||
self.inner.get_channel_enable_state(Channel::Ch1)
|
||||
}
|
||||
|
||||
/// Get the period tick count
|
||||
pub fn get_period_ticks(&self) -> u32 {
|
||||
self.inner.get_capture_value(self.channel)
|
||||
}
|
||||
|
||||
/// Get the pulse width tick count
|
||||
pub fn get_width_ticks(&self) -> u32 {
|
||||
self.inner.get_capture_value(match self.channel {
|
||||
Channel::Ch1 => Channel::Ch2,
|
||||
Channel::Ch2 => Channel::Ch1,
|
||||
_ => panic!("Invalid channel for PWM input"),
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the duty cycle in 100%
|
||||
pub fn get_duty_cycle(&self) -> f32 {
|
||||
let period = self.get_period_ticks();
|
||||
if period == 0 {
|
||||
return 0.;
|
||||
}
|
||||
100. * (self.get_width_ticks() as f32) / (period as f32)
|
||||
}
|
||||
}
|
@ -72,7 +72,7 @@ pub use enums::*;
|
||||
|
||||
use crate::gpio::{AFType, AnyPin};
|
||||
use crate::pac::tsc::Tsc as Regs;
|
||||
use crate::rcc::RccPeripheral;
|
||||
use crate::rcc::{self, RccPeripheral};
|
||||
use crate::{peripherals, Peripheral};
|
||||
|
||||
#[cfg(tsc_v1)]
|
||||
@ -649,7 +649,7 @@ impl<'d, T: Instance> Tsc<'d, T> {
|
||||
) -> Self {
|
||||
into_ref!(peri);
|
||||
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
|
||||
T::REGS.cr().modify(|w| {
|
||||
w.set_tsce(true);
|
||||
@ -880,7 +880,7 @@ impl<'d, T: Instance> Tsc<'d, T> {
|
||||
|
||||
impl<'d, T: Instance> Drop for Tsc<'d, T> {
|
||||
fn drop(&mut self) {
|
||||
T::disable();
|
||||
rcc::disable::<T>();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ use crate::interrupt;
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::pac::ucpd::vals::{Anamode, Ccenable, PscUsbpdclk, Txmode};
|
||||
pub use crate::pac::ucpd::vals::{Phyccsel as CcSel, TypecVstateCc as CcVState};
|
||||
use crate::rcc::RccPeripheral;
|
||||
use crate::rcc::{self, RccPeripheral};
|
||||
|
||||
pub(crate) fn init(
|
||||
_cs: critical_section::CriticalSection,
|
||||
@ -103,7 +103,7 @@ impl<'d, T: Instance> Ucpd<'d, T> {
|
||||
cc1.set_as_analog();
|
||||
cc2.set_as_analog();
|
||||
|
||||
T::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
T::Interrupt::unpend();
|
||||
unsafe { T::Interrupt::enable() };
|
||||
|
||||
@ -212,7 +212,7 @@ impl<'d, T: Instance> Drop for CcPhy<'d, T> {
|
||||
drop_not_ready.store(true, Ordering::Relaxed);
|
||||
} else {
|
||||
r.cfgr1().write(|w| w.set_ucpden(false));
|
||||
T::disable();
|
||||
rcc::disable::<T>();
|
||||
T::Interrupt::disable();
|
||||
}
|
||||
}
|
||||
@ -325,7 +325,7 @@ impl<'d, T: Instance> Drop for PdPhy<'d, T> {
|
||||
drop_not_ready.store(true, Ordering::Relaxed);
|
||||
} else {
|
||||
T::REGS.cfgr1().write(|w| w.set_ucpden(false));
|
||||
T::disable();
|
||||
rcc::disable::<T>();
|
||||
T::Interrupt::disable();
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use core::task::Poll;
|
||||
|
||||
use embassy_embedded_hal::SetConfig;
|
||||
use embassy_hal_internal::atomic_ring_buffer::RingBuffer;
|
||||
use embassy_hal_internal::{into_ref, Peripheral};
|
||||
use embassy_hal_internal::{Peripheral, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
#[cfg(not(any(usart_v1, usart_v2)))]
|
||||
@ -15,8 +15,7 @@ use super::{
|
||||
clear_interrupt_flags, configure, rdr, reconfigure, sr, tdr, Config, ConfigError, CtsPin, Error, Info, Instance,
|
||||
Regs, RtsPin, RxPin, TxPin,
|
||||
};
|
||||
use crate::gpio::AFType;
|
||||
use crate::interrupt::typelevel::Interrupt as _;
|
||||
use crate::gpio::{AFType, AnyPin, SealedPin as _};
|
||||
use crate::interrupt::{self, InterruptExt};
|
||||
use crate::time::Hertz;
|
||||
|
||||
@ -155,7 +154,9 @@ pub struct BufferedUartTx<'d> {
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
kernel_clock: Hertz,
|
||||
_phantom: PhantomData<&'d mut ()>,
|
||||
tx: Option<PeripheralRef<'d, AnyPin>>,
|
||||
cts: Option<PeripheralRef<'d, AnyPin>>,
|
||||
de: Option<PeripheralRef<'d, AnyPin>>,
|
||||
}
|
||||
|
||||
/// Rx-only buffered UART
|
||||
@ -165,7 +166,8 @@ pub struct BufferedUartRx<'d> {
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
kernel_clock: Hertz,
|
||||
_phantom: PhantomData<&'d mut ()>,
|
||||
rx: Option<PeripheralRef<'d, AnyPin>>,
|
||||
rts: Option<PeripheralRef<'d, AnyPin>>,
|
||||
}
|
||||
|
||||
impl<'d> SetConfig for BufferedUart<'d> {
|
||||
@ -206,9 +208,17 @@ impl<'d> BufferedUart<'d> {
|
||||
rx_buffer: &'d mut [u8],
|
||||
config: Config,
|
||||
) -> Result<Self, ConfigError> {
|
||||
T::enable_and_reset();
|
||||
|
||||
Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
|
||||
Self::new_inner(
|
||||
peri,
|
||||
new_pin!(rx, AFType::Input),
|
||||
new_pin!(tx, AFType::OutputPushPull),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
tx_buffer,
|
||||
rx_buffer,
|
||||
config,
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a new bidirectional buffered UART driver with request-to-send and clear-to-send pins
|
||||
@ -223,18 +233,17 @@ impl<'d> BufferedUart<'d> {
|
||||
rx_buffer: &'d mut [u8],
|
||||
config: Config,
|
||||
) -> Result<Self, ConfigError> {
|
||||
into_ref!(cts, rts);
|
||||
|
||||
T::enable_and_reset();
|
||||
|
||||
rts.set_as_af(rts.af_num(), AFType::OutputPushPull);
|
||||
cts.set_as_af(cts.af_num(), AFType::Input);
|
||||
T::info().regs.cr3().write(|w| {
|
||||
w.set_rtse(true);
|
||||
w.set_ctse(true);
|
||||
});
|
||||
|
||||
Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
|
||||
Self::new_inner(
|
||||
peri,
|
||||
new_pin!(rx, AFType::Input),
|
||||
new_pin!(tx, AFType::OutputPushPull),
|
||||
new_pin!(rts, AFType::OutputPushPull),
|
||||
new_pin!(cts, AFType::Input),
|
||||
None,
|
||||
tx_buffer,
|
||||
rx_buffer,
|
||||
config,
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a new bidirectional buffered UART driver with a driver-enable pin
|
||||
@ -249,66 +258,89 @@ impl<'d> BufferedUart<'d> {
|
||||
rx_buffer: &'d mut [u8],
|
||||
config: Config,
|
||||
) -> Result<Self, ConfigError> {
|
||||
into_ref!(de);
|
||||
|
||||
T::enable_and_reset();
|
||||
|
||||
de.set_as_af(de.af_num(), AFType::OutputPushPull);
|
||||
T::info().regs.cr3().write(|w| {
|
||||
w.set_dem(true);
|
||||
});
|
||||
|
||||
Self::new_inner(peri, rx, tx, tx_buffer, rx_buffer, config)
|
||||
Self::new_inner(
|
||||
peri,
|
||||
new_pin!(rx, AFType::Input),
|
||||
new_pin!(tx, AFType::OutputPushPull),
|
||||
None,
|
||||
None,
|
||||
new_pin!(de, AFType::OutputPushPull),
|
||||
tx_buffer,
|
||||
rx_buffer,
|
||||
config,
|
||||
)
|
||||
}
|
||||
|
||||
fn new_inner<T: Instance>(
|
||||
_peri: impl Peripheral<P = T> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
rx: Option<PeripheralRef<'d, AnyPin>>,
|
||||
tx: Option<PeripheralRef<'d, AnyPin>>,
|
||||
rts: Option<PeripheralRef<'d, AnyPin>>,
|
||||
cts: Option<PeripheralRef<'d, AnyPin>>,
|
||||
de: Option<PeripheralRef<'d, AnyPin>>,
|
||||
tx_buffer: &'d mut [u8],
|
||||
rx_buffer: &'d mut [u8],
|
||||
config: Config,
|
||||
) -> Result<Self, ConfigError> {
|
||||
into_ref!(_peri, rx, tx);
|
||||
|
||||
let info = T::info();
|
||||
let state = T::buffered_state();
|
||||
let kernel_clock = T::frequency();
|
||||
let len = tx_buffer.len();
|
||||
unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
|
||||
let len = rx_buffer.len();
|
||||
unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
|
||||
|
||||
let r = info.regs;
|
||||
rx.set_as_af(rx.af_num(), AFType::Input);
|
||||
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
||||
|
||||
configure(info, kernel_clock, &config, true, true)?;
|
||||
|
||||
r.cr1().modify(|w| {
|
||||
w.set_rxneie(true);
|
||||
w.set_idleie(true);
|
||||
});
|
||||
|
||||
T::Interrupt::unpend();
|
||||
unsafe { T::Interrupt::enable() };
|
||||
|
||||
state.tx_rx_refcount.store(2, Ordering::Relaxed);
|
||||
|
||||
Ok(Self {
|
||||
let mut this = Self {
|
||||
rx: BufferedUartRx {
|
||||
info,
|
||||
state,
|
||||
kernel_clock,
|
||||
_phantom: PhantomData,
|
||||
rx,
|
||||
rts,
|
||||
},
|
||||
tx: BufferedUartTx {
|
||||
info,
|
||||
state,
|
||||
kernel_clock,
|
||||
_phantom: PhantomData,
|
||||
tx,
|
||||
cts,
|
||||
de,
|
||||
},
|
||||
})
|
||||
};
|
||||
this.enable_and_configure(tx_buffer, rx_buffer, &config)?;
|
||||
Ok(this)
|
||||
}
|
||||
|
||||
fn enable_and_configure(
|
||||
&mut self,
|
||||
tx_buffer: &'d mut [u8],
|
||||
rx_buffer: &'d mut [u8],
|
||||
config: &Config,
|
||||
) -> Result<(), ConfigError> {
|
||||
let info = self.rx.info;
|
||||
let state = self.rx.state;
|
||||
state.tx_rx_refcount.store(2, Ordering::Relaxed);
|
||||
|
||||
info.rcc.enable_and_reset();
|
||||
|
||||
let len = tx_buffer.len();
|
||||
unsafe { state.tx_buf.init(tx_buffer.as_mut_ptr(), len) };
|
||||
let len = rx_buffer.len();
|
||||
unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
|
||||
|
||||
info.regs.cr3().write(|w| {
|
||||
w.set_rtse(self.rx.rts.is_some());
|
||||
w.set_ctse(self.tx.cts.is_some());
|
||||
#[cfg(not(any(usart_v1, usart_v2)))]
|
||||
w.set_dem(self.tx.de.is_some());
|
||||
});
|
||||
configure(info, self.rx.kernel_clock, &config, true, true)?;
|
||||
|
||||
info.regs.cr1().modify(|w| {
|
||||
w.set_rxneie(true);
|
||||
w.set_idleie(true);
|
||||
});
|
||||
|
||||
info.interrupt.unpend();
|
||||
unsafe { info.interrupt.enable() };
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
}
|
||||
}
|
||||
|
||||
self.rx.as_ref().map(|x| x.set_as_disconnected());
|
||||
self.rts.as_ref().map(|x| x.set_as_disconnected());
|
||||
drop_tx_rx(self.info, state);
|
||||
}
|
||||
}
|
||||
@ -532,6 +566,9 @@ impl<'d> Drop for BufferedUartTx<'d> {
|
||||
}
|
||||
}
|
||||
|
||||
self.tx.as_ref().map(|x| x.set_as_disconnected());
|
||||
self.cts.as_ref().map(|x| x.set_as_disconnected());
|
||||
self.de.as_ref().map(|x| x.set_as_disconnected());
|
||||
drop_tx_rx(self.info, state);
|
||||
}
|
||||
}
|
||||
@ -545,7 +582,7 @@ fn drop_tx_rx(info: &Info, state: &State) {
|
||||
refcount == 1
|
||||
});
|
||||
if is_last_drop {
|
||||
info.enable_bit.disable();
|
||||
info.rcc.disable();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ use embassy_sync::waitqueue::AtomicWaker;
|
||||
use futures_util::future::{select, Either};
|
||||
|
||||
use crate::dma::ChannelAndRequest;
|
||||
use crate::gpio::{AFType, AnyPin, SealedPin};
|
||||
use crate::gpio::{AFType, AnyPin, SealedPin as _};
|
||||
use crate::interrupt::typelevel::Interrupt as _;
|
||||
use crate::interrupt::{self, Interrupt, InterruptExt};
|
||||
use crate::mode::{Async, Blocking, Mode};
|
||||
@ -28,7 +28,7 @@ use crate::pac::usart::Lpuart as Regs;
|
||||
#[cfg(any(usart_v1, usart_v2))]
|
||||
use crate::pac::usart::Usart as Regs;
|
||||
use crate::pac::usart::{regs, vals};
|
||||
use crate::rcc::{ClockEnableBit, SealedRccPeripheral};
|
||||
use crate::rcc::{RccInfo, SealedRccPeripheral};
|
||||
use crate::time::Hertz;
|
||||
use crate::Peripheral;
|
||||
|
||||
@ -429,29 +429,33 @@ impl<'d, M: Mode> UartTx<'d, M> {
|
||||
tx_dma: Option<ChannelAndRequest<'d>>,
|
||||
config: Config,
|
||||
) -> Result<Self, ConfigError> {
|
||||
T::enable_and_reset();
|
||||
|
||||
let info = T::info();
|
||||
let state = T::state();
|
||||
let kernel_clock = T::frequency();
|
||||
let r = info.regs;
|
||||
r.cr3().modify(|w| {
|
||||
w.set_ctse(cts.is_some());
|
||||
});
|
||||
configure(info, kernel_clock, &config, false, true)?;
|
||||
|
||||
state.tx_rx_refcount.store(1, Ordering::Relaxed);
|
||||
|
||||
Ok(Self {
|
||||
info,
|
||||
state,
|
||||
kernel_clock,
|
||||
let mut this = Self {
|
||||
info: T::info(),
|
||||
state: T::state(),
|
||||
kernel_clock: T::frequency(),
|
||||
tx,
|
||||
cts,
|
||||
de: None,
|
||||
tx_dma,
|
||||
_phantom: PhantomData,
|
||||
})
|
||||
};
|
||||
this.enable_and_configure(&config)?;
|
||||
Ok(this)
|
||||
}
|
||||
|
||||
fn enable_and_configure(&mut self, config: &Config) -> Result<(), ConfigError> {
|
||||
let info = self.info;
|
||||
let state = self.state;
|
||||
state.tx_rx_refcount.store(1, Ordering::Relaxed);
|
||||
|
||||
info.rcc.enable_and_reset();
|
||||
|
||||
info.regs.cr3().modify(|w| {
|
||||
w.set_ctse(self.cts.is_some());
|
||||
});
|
||||
configure(info, self.kernel_clock, config, false, true)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Reconfigure the driver
|
||||
@ -775,34 +779,38 @@ impl<'d, M: Mode> UartRx<'d, M> {
|
||||
rx_dma: Option<ChannelAndRequest<'d>>,
|
||||
config: Config,
|
||||
) -> Result<Self, ConfigError> {
|
||||
T::enable_and_reset();
|
||||
|
||||
let info = T::info();
|
||||
let state = T::state();
|
||||
let kernel_clock = T::frequency();
|
||||
let r = info.regs;
|
||||
r.cr3().write(|w| {
|
||||
w.set_rtse(rts.is_some());
|
||||
});
|
||||
configure(info, kernel_clock, &config, true, false)?;
|
||||
|
||||
T::Interrupt::unpend();
|
||||
unsafe { T::Interrupt::enable() };
|
||||
|
||||
state.tx_rx_refcount.store(1, Ordering::Relaxed);
|
||||
|
||||
Ok(Self {
|
||||
let mut this = Self {
|
||||
_phantom: PhantomData,
|
||||
info,
|
||||
state,
|
||||
kernel_clock,
|
||||
info: T::info(),
|
||||
state: T::state(),
|
||||
kernel_clock: T::frequency(),
|
||||
rx,
|
||||
rts,
|
||||
rx_dma,
|
||||
detect_previous_overrun: config.detect_previous_overrun,
|
||||
#[cfg(any(usart_v1, usart_v2))]
|
||||
buffered_sr: stm32_metapac::usart::regs::Sr(0),
|
||||
})
|
||||
};
|
||||
this.enable_and_configure(&config)?;
|
||||
Ok(this)
|
||||
}
|
||||
|
||||
fn enable_and_configure(&mut self, config: &Config) -> Result<(), ConfigError> {
|
||||
let info = self.info;
|
||||
let state = self.state;
|
||||
state.tx_rx_refcount.store(1, Ordering::Relaxed);
|
||||
|
||||
info.rcc.enable_and_reset();
|
||||
|
||||
info.regs.cr3().write(|w| {
|
||||
w.set_rtse(self.rts.is_some());
|
||||
});
|
||||
configure(info, self.kernel_clock, &config, true, false)?;
|
||||
|
||||
info.interrupt.unpend();
|
||||
unsafe { info.interrupt.enable() };
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Reconfigure the driver
|
||||
@ -916,7 +924,7 @@ fn drop_tx_rx(info: &Info, state: &State) {
|
||||
refcount == 1
|
||||
});
|
||||
if is_last_drop {
|
||||
info.enable_bit.disable();
|
||||
info.rcc.disable();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1228,27 +1236,11 @@ impl<'d, M: Mode> Uart<'d, M> {
|
||||
rx_dma: Option<ChannelAndRequest<'d>>,
|
||||
config: Config,
|
||||
) -> Result<Self, ConfigError> {
|
||||
T::enable_and_reset();
|
||||
|
||||
let info = T::info();
|
||||
let state = T::state();
|
||||
let kernel_clock = T::frequency();
|
||||
let r = info.regs;
|
||||
|
||||
r.cr3().write(|w| {
|
||||
w.set_rtse(rts.is_some());
|
||||
w.set_ctse(cts.is_some());
|
||||
#[cfg(not(any(usart_v1, usart_v2)))]
|
||||
w.set_dem(de.is_some());
|
||||
});
|
||||
configure(info, kernel_clock, &config, true, true)?;
|
||||
|
||||
T::Interrupt::unpend();
|
||||
unsafe { T::Interrupt::enable() };
|
||||
|
||||
state.tx_rx_refcount.store(2, Ordering::Relaxed);
|
||||
|
||||
Ok(Self {
|
||||
let mut this = Self {
|
||||
tx: UartTx {
|
||||
_phantom: PhantomData,
|
||||
info,
|
||||
@ -1271,7 +1263,30 @@ impl<'d, M: Mode> Uart<'d, M> {
|
||||
#[cfg(any(usart_v1, usart_v2))]
|
||||
buffered_sr: stm32_metapac::usart::regs::Sr(0),
|
||||
},
|
||||
})
|
||||
};
|
||||
this.enable_and_configure(&config)?;
|
||||
Ok(this)
|
||||
}
|
||||
|
||||
fn enable_and_configure(&mut self, config: &Config) -> Result<(), ConfigError> {
|
||||
let info = self.rx.info;
|
||||
let state = self.rx.state;
|
||||
state.tx_rx_refcount.store(2, Ordering::Relaxed);
|
||||
|
||||
info.rcc.enable_and_reset();
|
||||
|
||||
info.regs.cr3().write(|w| {
|
||||
w.set_rtse(self.rx.rts.is_some());
|
||||
w.set_ctse(self.tx.cts.is_some());
|
||||
#[cfg(not(any(usart_v1, usart_v2)))]
|
||||
w.set_dem(self.tx.de.is_some());
|
||||
});
|
||||
configure(info, self.rx.kernel_clock, config, true, true)?;
|
||||
|
||||
info.interrupt.unpend();
|
||||
unsafe { info.interrupt.enable() };
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Perform a blocking write
|
||||
@ -1718,7 +1733,7 @@ impl State {
|
||||
|
||||
struct Info {
|
||||
regs: Regs,
|
||||
enable_bit: ClockEnableBit,
|
||||
rcc: RccInfo,
|
||||
interrupt: Interrupt,
|
||||
kind: Kind,
|
||||
}
|
||||
@ -1754,7 +1769,7 @@ macro_rules! impl_usart {
|
||||
fn info() -> &'static Info {
|
||||
static INFO: Info = Info {
|
||||
regs: unsafe { Regs::from_ptr(crate::pac::$inst.as_ptr()) },
|
||||
enable_bit: crate::peripherals::$inst::ENABLE_BIT,
|
||||
rcc: crate::peripherals::$inst::RCC_INFO,
|
||||
interrupt: crate::interrupt::typelevel::$irq::IRQ,
|
||||
kind: $kind,
|
||||
};
|
||||
|
@ -4,10 +4,12 @@ use core::sync::atomic::{compiler_fence, Ordering};
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_embedded_hal::SetConfig;
|
||||
use embassy_hal_internal::PeripheralRef;
|
||||
use futures_util::future::{select, Either};
|
||||
|
||||
use super::{clear_interrupt_flags, rdr, reconfigure, sr, Config, ConfigError, Error, Info, State, UartRx};
|
||||
use crate::dma::ReadableRingBuffer;
|
||||
use crate::gpio::{AnyPin, SealedPin as _};
|
||||
use crate::mode::Async;
|
||||
use crate::time::Hertz;
|
||||
use crate::usart::{Regs, Sr};
|
||||
@ -19,6 +21,8 @@ pub struct RingBufferedUartRx<'d> {
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
kernel_clock: Hertz,
|
||||
rx: Option<PeripheralRef<'d, AnyPin>>,
|
||||
rts: Option<PeripheralRef<'d, AnyPin>>,
|
||||
ring_buf: ReadableRingBuffer<'d, u8>,
|
||||
}
|
||||
|
||||
@ -49,6 +53,8 @@ impl<'d> UartRx<'d, Async> {
|
||||
let state = self.state;
|
||||
let kernel_clock = self.kernel_clock;
|
||||
let ring_buf = unsafe { ReadableRingBuffer::new(rx_dma, request, rdr(info.regs), dma_buf, opts) };
|
||||
let rx = unsafe { self.rx.as_ref().map(|x| x.clone_unchecked()) };
|
||||
let rts = unsafe { self.rts.as_ref().map(|x| x.clone_unchecked()) };
|
||||
|
||||
// Don't disable the clock
|
||||
mem::forget(self);
|
||||
@ -57,6 +63,8 @@ impl<'d> UartRx<'d, Async> {
|
||||
info,
|
||||
state,
|
||||
kernel_clock,
|
||||
rx,
|
||||
rts,
|
||||
ring_buf,
|
||||
}
|
||||
}
|
||||
@ -221,6 +229,8 @@ impl<'d> RingBufferedUartRx<'d> {
|
||||
impl Drop for RingBufferedUartRx<'_> {
|
||||
fn drop(&mut self) {
|
||||
self.teardown_uart();
|
||||
self.rx.as_ref().map(|x| x.set_as_disconnected());
|
||||
self.rts.as_ref().map(|x| x.set_as_disconnected());
|
||||
super::drop_tx_rx(self.info, self.state);
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ mod _version;
|
||||
pub use _version::*;
|
||||
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::rcc::SealedRccPeripheral;
|
||||
use crate::rcc;
|
||||
|
||||
/// clock, power initialization stuff that's common for USB and OTG.
|
||||
fn common_init<T: Instance>() {
|
||||
@ -65,5 +65,5 @@ fn common_init<T: Instance>() {
|
||||
T::Interrupt::unpend();
|
||||
unsafe { T::Interrupt::enable() };
|
||||
|
||||
<T as SealedRccPeripheral>::enable_and_reset();
|
||||
rcc::enable_and_reset::<T>();
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ use embassy_usb_synopsys_otg::{
|
||||
use crate::gpio::AFType;
|
||||
use crate::interrupt;
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::rcc::{RccPeripheral, SealedRccPeripheral};
|
||||
use crate::rcc::{self, RccPeripheral};
|
||||
|
||||
const MAX_EP_COUNT: usize = 9;
|
||||
|
||||
@ -246,7 +246,7 @@ impl<'d, T: Instance> Bus<'d, T> {
|
||||
fn disable(&mut self) {
|
||||
T::Interrupt::disable();
|
||||
|
||||
<T as SealedRccPeripheral>::disable();
|
||||
rcc::disable::<T>();
|
||||
self.inited = false;
|
||||
|
||||
#[cfg(stm32l4)]
|
||||
|
@ -267,9 +267,9 @@ impl<'d, T: Instance> Driver<'d, T> {
|
||||
w.set_fres(true);
|
||||
});
|
||||
|
||||
#[cfg(time)]
|
||||
#[cfg(feature = "time")]
|
||||
embassy_time::block_for(embassy_time::Duration::from_millis(100));
|
||||
#[cfg(not(time))]
|
||||
#[cfg(not(feature = "time"))]
|
||||
cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 10);
|
||||
|
||||
#[cfg(not(usb_v4))]
|
||||
|
@ -1,31 +1,7 @@
|
||||
use std::env;
|
||||
#[path = "./build_common.rs"]
|
||||
mod common;
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
|
||||
let target = env::var("TARGET").unwrap();
|
||||
|
||||
if target.starts_with("thumbv6m-") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv6m");
|
||||
} else if target.starts_with("thumbv7m-") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv7m");
|
||||
} else if target.starts_with("thumbv7em-") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv7m");
|
||||
println!("cargo:rustc-cfg=armv7em"); // (not currently used)
|
||||
} else if target.starts_with("thumbv8m.base") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv8m");
|
||||
println!("cargo:rustc-cfg=armv8m_base");
|
||||
} else if target.starts_with("thumbv8m.main") {
|
||||
println!("cargo:rustc-cfg=cortex_m");
|
||||
println!("cargo:rustc-cfg=armv8m");
|
||||
println!("cargo:rustc-cfg=armv8m_main");
|
||||
}
|
||||
|
||||
if target.ends_with("-eabihf") {
|
||||
println!("cargo:rustc-cfg=has_fpu");
|
||||
}
|
||||
let mut cfgs = common::CfgSet::new();
|
||||
common::set_target_cfgs(&mut cfgs);
|
||||
}
|
||||
|
109
embassy-sync/build_common.rs
Normal file
109
embassy-sync/build_common.rs
Normal file
@ -0,0 +1,109 @@
|
||||
// NOTE: this file is copy-pasted between several Embassy crates, because there is no
|
||||
// straightforward way to share this code:
|
||||
// - it cannot be placed into the root of the repo and linked from each build.rs using `#[path =
|
||||
// "../build_common.rs"]`, because `cargo publish` requires that all files published with a crate
|
||||
// reside in the crate's directory,
|
||||
// - it cannot be symlinked from `embassy-xxx/build_common.rs` to `../build_common.rs`, because
|
||||
// symlinks don't work on Windows.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::process::Command;
|
||||
|
||||
/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring
|
||||
/// them (`cargo:rust-check-cfg=cfg(X)`).
|
||||
#[derive(Debug)]
|
||||
pub struct CfgSet {
|
||||
enabled: HashSet<String>,
|
||||
declared: HashSet<String>,
|
||||
emit_declared: bool,
|
||||
}
|
||||
|
||||
impl CfgSet {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
enabled: HashSet::new(),
|
||||
declared: HashSet::new(),
|
||||
emit_declared: is_rustc_nightly(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable a config, which can then be used in `#[cfg(...)]` for conditional compilation.
|
||||
///
|
||||
/// All configs that can potentially be enabled should be unconditionally declared using
|
||||
/// [`Self::declare()`].
|
||||
pub fn enable(&mut self, cfg: impl AsRef<str>) {
|
||||
if self.enabled.insert(cfg.as_ref().to_owned()) {
|
||||
println!("cargo:rustc-cfg={}", cfg.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enable_all(&mut self, cfgs: &[impl AsRef<str>]) {
|
||||
for cfg in cfgs.iter() {
|
||||
self.enable(cfg.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
/// Declare a valid config for conditional compilation, without enabling it.
|
||||
///
|
||||
/// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid.
|
||||
pub fn declare(&mut self, cfg: impl AsRef<str>) {
|
||||
if self.declared.insert(cfg.as_ref().to_owned()) && self.emit_declared {
|
||||
println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn declare_all(&mut self, cfgs: &[impl AsRef<str>]) {
|
||||
for cfg in cfgs.iter() {
|
||||
self.declare(cfg.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set(&mut self, cfg: impl Into<String>, enable: bool) {
|
||||
let cfg = cfg.into();
|
||||
if enable {
|
||||
self.enable(cfg.clone());
|
||||
}
|
||||
self.declare(cfg);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_rustc_nightly() -> bool {
|
||||
let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
|
||||
|
||||
let output = Command::new(rustc)
|
||||
.arg("--version")
|
||||
.output()
|
||||
.expect("failed to run `rustc --version`");
|
||||
|
||||
String::from_utf8_lossy(&output.stdout).contains("nightly")
|
||||
}
|
||||
|
||||
/// Sets configs that describe the target platform.
|
||||
pub fn set_target_cfgs(cfgs: &mut CfgSet) {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
|
||||
if target.starts_with("thumbv6m-") {
|
||||
cfgs.enable_all(&["cortex_m", "armv6m"]);
|
||||
} else if target.starts_with("thumbv7m-") {
|
||||
cfgs.enable_all(&["cortex_m", "armv7m"]);
|
||||
} else if target.starts_with("thumbv7em-") {
|
||||
cfgs.enable_all(&["cortex_m", "armv7m", "armv7em"]);
|
||||
} else if target.starts_with("thumbv8m.base") {
|
||||
cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_base"]);
|
||||
} else if target.starts_with("thumbv8m.main") {
|
||||
cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_main"]);
|
||||
}
|
||||
cfgs.declare_all(&[
|
||||
"cortex_m",
|
||||
"armv6m",
|
||||
"armv7m",
|
||||
"armv7em",
|
||||
"armv8m",
|
||||
"armv8m_base",
|
||||
"armv8m_main",
|
||||
]);
|
||||
|
||||
cfgs.set("has_fpu", target.ends_with("-eabihf"));
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
#![cfg_attr(not(any(feature = "std", feature = "wasm")), no_std)]
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
#![allow(async_fn_in_trait)]
|
||||
#![allow(clippy::new_without_default)]
|
||||
#![doc = include_str!("../README.md")]
|
||||
|
@ -27,9 +27,17 @@ features = ["defmt", "std"]
|
||||
std = ["tick-hz-1_000_000", "critical-section/std"]
|
||||
wasm = ["dep:wasm-bindgen", "dep:js-sys", "dep:wasm-timer", "tick-hz-1_000_000"]
|
||||
|
||||
## Display a timestamp of the number of seconds since startup next to defmt log messages
|
||||
## Display the time since startup next to defmt log messages.
|
||||
## At most 1 `defmt-timestamp-uptime-*` feature can be used.
|
||||
## `defmt-timestamp-uptime` is provided for backwards compatibility (provides the same format as `uptime-us`).
|
||||
## To use this you must have a time driver provided.
|
||||
defmt-timestamp-uptime = ["defmt"]
|
||||
defmt-timestamp-uptime-s = ["defmt"]
|
||||
defmt-timestamp-uptime-ms = ["defmt"]
|
||||
defmt-timestamp-uptime-us = ["defmt"]
|
||||
defmt-timestamp-uptime-ts = ["defmt"]
|
||||
defmt-timestamp-uptime-tms = ["defmt"]
|
||||
defmt-timestamp-uptime-tus = ["defmt"]
|
||||
|
||||
## Create a `MockDriver` that can be manually advanced for testing purposes.
|
||||
mock-driver = ["tick-hz-1_000_000"]
|
||||
|
@ -46,5 +46,20 @@ pub(crate) const GCD_1K: u64 = gcd(TICK_HZ, 1_000);
|
||||
pub(crate) const GCD_1M: u64 = gcd(TICK_HZ, 1_000_000);
|
||||
pub(crate) const GCD_1G: u64 = gcd(TICK_HZ, 1_000_000_000);
|
||||
|
||||
#[cfg(feature = "defmt-timestamp-uptime")]
|
||||
#[cfg(feature = "defmt-timestamp-uptime-s")]
|
||||
defmt::timestamp! {"{=u64}", Instant::now().as_secs() }
|
||||
|
||||
#[cfg(feature = "defmt-timestamp-uptime-ms")]
|
||||
defmt::timestamp! {"{=u64:ms}", Instant::now().as_millis() }
|
||||
|
||||
#[cfg(any(feature = "defmt-timestamp-uptime", feature = "defmt-timestamp-uptime-us"))]
|
||||
defmt::timestamp! {"{=u64:us}", Instant::now().as_micros() }
|
||||
|
||||
#[cfg(feature = "defmt-timestamp-uptime-ts")]
|
||||
defmt::timestamp! {"{=u64:ts}", Instant::now().as_secs() }
|
||||
|
||||
#[cfg(feature = "defmt-timestamp-uptime-tms")]
|
||||
defmt::timestamp! {"{=u64:tms}", Instant::now().as_millis() }
|
||||
|
||||
#[cfg(feature = "defmt-timestamp-uptime-tus")]
|
||||
defmt::timestamp! {"{=u64:tus}", Instant::now().as_micros() }
|
||||
|
@ -26,9 +26,11 @@ flavors = [
|
||||
features = ["defmt", "cortex-m", "dfu"]
|
||||
|
||||
[dependencies]
|
||||
defmt = { version = "0.3.5", optional = true }
|
||||
log = { version = "0.4.17", optional = true }
|
||||
|
||||
bitflags = "2.4.1"
|
||||
cortex-m = { version = "0.7.7", features = ["inline-asm"], optional = true }
|
||||
defmt = { version = "0.3.5", optional = true }
|
||||
embassy-boot = { version = "0.2.0", path = "../embassy-boot" }
|
||||
embassy-futures = { version = "0.1.1", path = "../embassy-futures" }
|
||||
embassy-sync = { version = "0.6.0", path = "../embassy-sync" }
|
||||
|
@ -25,3 +25,10 @@ cortex-m-rt = "0.7.0"
|
||||
ed25519-dalek = ["embassy-boot/ed25519-dalek"]
|
||||
ed25519-salty = ["embassy-boot/ed25519-salty"]
|
||||
skip-include = []
|
||||
defmt = [
|
||||
"dep:defmt",
|
||||
"dep:defmt-rtt",
|
||||
"embassy-nrf/defmt",
|
||||
"embassy-boot-nrf/defmt",
|
||||
"embassy-sync/defmt",
|
||||
]
|
||||
|
@ -23,6 +23,7 @@ cortex-m-rt = "0.7.0"
|
||||
[features]
|
||||
defmt = [
|
||||
"dep:defmt",
|
||||
"dep:defmt-rtt",
|
||||
"embassy-stm32/defmt",
|
||||
"embassy-boot-stm32/defmt",
|
||||
"embassy-sync/defmt",
|
||||
|
@ -1,7 +1,7 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[cfg(feature = "defmt-rtt")]
|
||||
#[cfg(feature = "defmt")]
|
||||
use defmt_rtt::*;
|
||||
use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
|
||||
use embassy_embedded_hal::adapter::BlockingAsync;
|
||||
|
@ -1,7 +1,7 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[cfg(feature = "defmt-rtt")]
|
||||
#[cfg(feature = "defmt")]
|
||||
use defmt_rtt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::gpio::{Level, Output, Speed};
|
||||
|
@ -24,6 +24,7 @@ cortex-m-rt = "0.7.0"
|
||||
[features]
|
||||
defmt = [
|
||||
"dep:defmt",
|
||||
"dep:defmt-rtt",
|
||||
"embassy-stm32/defmt",
|
||||
"embassy-boot-stm32/defmt",
|
||||
"embassy-sync/defmt",
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
use core::cell::RefCell;
|
||||
|
||||
#[cfg(feature = "defmt-rtt")]
|
||||
#[cfg(feature = "defmt")]
|
||||
use defmt_rtt::*;
|
||||
use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig};
|
||||
use embassy_executor::Spawner;
|
||||
|
@ -1,7 +1,7 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[cfg(feature = "defmt-rtt")]
|
||||
#[cfg(feature = "defmt")]
|
||||
use defmt_rtt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::gpio::{Level, Output, Speed};
|
||||
|
@ -24,6 +24,7 @@ cortex-m-rt = "0.7.0"
|
||||
[features]
|
||||
defmt = [
|
||||
"dep:defmt",
|
||||
"dep:defmt-rtt",
|
||||
"embassy-stm32/defmt",
|
||||
"embassy-boot-stm32/defmt",
|
||||
"embassy-sync/defmt",
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
use core::cell::RefCell;
|
||||
|
||||
#[cfg(feature = "defmt-rtt")]
|
||||
#[cfg(feature = "defmt")]
|
||||
use defmt_rtt::*;
|
||||
use embassy_boot_stm32::{AlignedBuffer, BlockingFirmwareUpdater, FirmwareUpdaterConfig};
|
||||
use embassy_executor::Spawner;
|
||||
|
@ -1,7 +1,7 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[cfg(feature = "defmt-rtt")]
|
||||
#[cfg(feature = "defmt")]
|
||||
use defmt_rtt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::gpio::{Level, Output, Speed};
|
||||
|
@ -23,6 +23,7 @@ cortex-m-rt = "0.7.0"
|
||||
[features]
|
||||
defmt = [
|
||||
"dep:defmt",
|
||||
"dep:defmt-rtt",
|
||||
"embassy-stm32/defmt",
|
||||
"embassy-boot-stm32/defmt",
|
||||
"embassy-sync/defmt",
|
||||
|
@ -1,7 +1,7 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[cfg(feature = "defmt-rtt")]
|
||||
#[cfg(feature = "defmt")]
|
||||
use defmt_rtt::*;
|
||||
use embassy_boot_stm32::{AlignedBuffer, FirmwareUpdater, FirmwareUpdaterConfig};
|
||||
use embassy_embedded_hal::adapter::BlockingAsync;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user