Merge branch 'main' of https://github.com/embassy-rs/embassy into fix_main

This commit is contained in:
Gustav Toft 2024-06-05 08:11:50 +02:00
commit 319e18b399
139 changed files with 3171 additions and 1562 deletions

View File

@ -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]
----

View File

@ -131,7 +131,7 @@ If youre using a raspberry pi pico-w, make sure youre running `+cargo run
If youre 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 youre 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 youre 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?

View File

@ -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 }

View File

@ -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

View File

@ -5,4 +5,5 @@ fn main() {
if target.starts_with("thumbv6m-") {
println!("cargo:rustc-cfg=armv6m");
}
println!("cargo:rustc-check-cfg=cfg(armv6m)");
}

View File

@ -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

View File

@ -5,4 +5,5 @@ fn main() {
if target.starts_with("thumbv6m-") {
println!("cargo:rustc-cfg=armv6m");
}
println!("cargo:rustc-check-cfg=cfg(armv6m)");
}

View File

@ -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

View File

@ -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);
}

View 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"));
}

View File

@ -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);
}

View 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"));
}

View File

@ -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"]

View File

@ -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)]

View File

@ -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
});

View File

@ -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"

View File

@ -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"]

View File

@ -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");

View 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"));
}

View File

@ -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>();
}
}

View File

@ -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>();
}
}

View File

@ -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>();
}
}

View File

@ -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());

View File

@ -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;

View File

@ -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>();
}
}

View File

@ -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>();
}
}

View File

@ -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);

View File

@ -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());

View File

@ -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))
}
}

View File

@ -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;

View File

@ -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();

View File

@ -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::*;

View File

@ -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)

View File

@ -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>();
}
}

View File

@ -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();

View File

@ -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,

View File

@ -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.

View File

@ -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
}
}

View File

@ -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)

View File

@ -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,

View File

@ -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
}
}

View File

@ -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"
)]

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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,

View File

@ -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 {

View File

@ -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
}

View File

@ -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,

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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.

View File

@ -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
}
}

View File

@ -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.

View File

@ -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>();
}
}

View File

@ -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() {}

View File

@ -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());
}

View File

@ -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,

View File

@ -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);

View File

@ -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();
}

View File

@ -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();

View File

@ -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 {

View 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));
}
}

View File

@ -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);
}

View File

@ -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));
}

View File

@ -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))

View File

@ -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.

View File

@ -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() };

View File

@ -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,
});
};
);

View File

@ -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();

View File

@ -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 {

View File

@ -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))]

View File

@ -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;

View 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)
}
}

View File

@ -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>();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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,
};

View File

@ -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);
}
}

View File

@ -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>();
}

View File

@ -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)]

View File

@ -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))]

View File

@ -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);
}

View 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"));
}

View File

@ -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")]

View File

@ -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"]

View File

@ -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() }

View File

@ -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" }

View File

@ -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",
]

View File

@ -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",

View File

@ -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;

View File

@ -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};

View File

@ -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",

View File

@ -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;

View File

@ -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};

View File

@ -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",

View File

@ -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;

View File

@ -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};

View File

@ -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",

View File

@ -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