Initial commit which enables STM32U3

This commit is contained in:
graynode 2025-12-19 11:32:25 -05:00
parent 905bdfa766
commit 93b355f89b
15 changed files with 899 additions and 139 deletions

View File

@ -97,6 +97,7 @@ build = [
{target = "thumbv8m.main-none-eabihf", features = ["defmt", "exti", "stm32wba55ug", "time", "time-driver-any"]},
{target = "thumbv8m.main-none-eabihf", features = ["defmt", "exti", "stm32wba62cg", "time", "time-driver-any"]},
{target = "thumbv8m.main-none-eabihf", features = ["defmt", "exti", "low-power", "stm32wba65ri", "time", "time-driver-any"]},
{target = "thumbv8m.main-none-eabihf", features = ["defmt", "exti", "stm32u385rg", "time", "time-driver-any"]},
{target = "thumbv8m.main-none-eabihf", features = ["defmt", "exti", "stm32u5f9zj", "time", "time-driver-any"]},
{target = "thumbv8m.main-none-eabihf", features = ["defmt", "exti", "stm32u5g9nj", "time", "time-driver-any"]},
{target = "thumbv8m.main-none-eabihf", features = ["defmt", "exti", "stm32n657x0", "time", "time-driver-any"]},
@ -135,6 +136,7 @@ flavors = [
{ regex_feature = "stm32l5...e", target = "thumbv8m.main-none-eabihf", features = ["low-power", "dual-bank"] },
{ regex_feature = "stm32l5.*", target = "thumbv8m.main-none-eabihf", features = ["low-power"] },
{ regex_feature = "stm32u0.*", target = "thumbv6m-none-eabi" },
{ regex_feature = "stm32u3.*", target = "thumbv8m.main-none-eabihf"},
{ regex_feature = "stm32u5.*", target = "thumbv8m.main-none-eabihf" },
{ regex_feature = "stm32wb.*", target = "thumbv7em-none-eabi" },
{ regex_feature = "stm32wba.*", target = "thumbv8m.main-none-eabihf" },
@ -200,11 +202,13 @@ aligned = "0.4.1"
heapless = "0.9.1"
#stm32-metapac = { version = "18" }
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-658588478e426d68090a59ff8385bce5b407c2bc" }
stm32-metapac = { path = "../../stm32-data/build/stm32-metapac" }
# stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-b77c8d968f53b18d6bdcd052e354b5070ec2bbc2" }
[build-dependencies]
#stm32-metapac = { version = "18", default-features = false, features = ["metadata"]}
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-658588478e426d68090a59ff8385bce5b407c2bc", default-features = false, features = ["metadata"] }
# stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-b77c8d968f53b18d6bdcd052e354b5070ec2bbc2", default-features = false, features = ["metadata"] }
stm32-metapac = { path = "../../stm32-data/build/stm32-metapac" , default-features = false, features = ["metadata"] }
proc-macro2 = "1.0.36"
quote = "1.0.15"
@ -1701,6 +1705,18 @@ stm32u083hc = [ "stm32-metapac/stm32u083hc" ]
stm32u083kc = [ "stm32-metapac/stm32u083kc" ]
stm32u083mc = [ "stm32-metapac/stm32u083mc" ]
stm32u083rc = [ "stm32-metapac/stm32u083rc" ]
stm32u375ce = [ "stm32-metapac/stm32u375ce" ]
stm32u375cg = [ "stm32-metapac/stm32u375cg" ]
stm32u375ke = [ "stm32-metapac/stm32u375ke" ]
stm32u375kg = [ "stm32-metapac/stm32u375kg" ]
stm32u375re = [ "stm32-metapac/stm32u375re" ]
stm32u375rg = [ "stm32-metapac/stm32u375rg" ]
stm32u375ve = [ "stm32-metapac/stm32u375ve" ]
stm32u375vg = [ "stm32-metapac/stm32u375vg" ]
stm32u385cg = [ "stm32-metapac/stm32u385cg" ]
stm32u385kg = [ "stm32-metapac/stm32u385kg" ]
stm32u385rg = [ "stm32-metapac/stm32u385rg" ]
stm32u385vg = [ "stm32-metapac/stm32u385vg" ]
stm32u535cb = [ "stm32-metapac/stm32u535cb" ]
stm32u535cc = [ "stm32-metapac/stm32u535cc" ]
stm32u535ce = [ "stm32-metapac/stm32u535ce" ]

View File

@ -97,12 +97,10 @@ fn main() {
match (single_bank_selected, dual_bank_selected) {
(true, true) => panic!("Both 'single-bank' and 'dual-bank' features enabled"),
(true, false) => {
single_bank_memory.expect("The 'single-bank' feature is not supported on this dual bank chip")
}
(false, true) => {
dual_bank_memory.expect("The 'dual-bank' feature is not supported on this single bank chip")
}
(true, false) => single_bank_memory
.expect("The 'single-bank' feature is not supported on this dual bank chip"),
(false, true) => dual_bank_memory
.expect("The 'dual-bank' feature is not supported on this single bank chip"),
(false, false) => {
if METADATA.memory.len() != 1 {
panic!(
@ -350,8 +348,8 @@ fn main() {
};
for tim in [
"tim1", "tim2", "tim3", "tim4", "tim5", "tim8", "tim9", "tim12", "tim15", "tim20", "tim21", "tim22", "tim23",
"tim24",
"tim1", "tim2", "tim3", "tim4", "tim5", "tim8", "tim9", "tim12", "tim15", "tim20", "tim21",
"tim22", "tim23", "tim24",
] {
cfgs.declare(format!("time_driver_{}", tim));
}
@ -514,7 +512,12 @@ fn main() {
.filter_map(|p| p.registers.as_ref())
.find(|r| r.kind == "rcc")
.unwrap();
let rcc_block = rcc_registers.ir.blocks.iter().find(|b| b.name == "Rcc").unwrap();
let rcc_block = rcc_registers
.ir
.blocks
.iter()
.find(|b| b.name == "Rcc")
.unwrap();
// ========
// Generate RccPeripheral impls
@ -570,7 +573,7 @@ fn main() {
},
);
}
if chip_name.starts_with("stm32u5") {
if chip_name.starts_with("stm32u5") || chip_name.starts_with("stm32U3") {
clock_gen.chained_muxes.insert(
"ICLK",
&PeripheralRccRegister {
@ -669,7 +672,11 @@ fn main() {
.find(|i| i.name.eq_ignore_ascii_case(&fieldset_name))
.unwrap();
let field_name = mux.field.to_ascii_lowercase();
let field = fieldset.fields.iter().find(|i| i.name == field_name).unwrap();
let field = fieldset
.fields
.iter()
.find(|i| i.name == field_name)
.unwrap();
let enum_name = field.enumm.unwrap();
let enumm = ir.enums.iter().find(|i| i.name == enum_name).unwrap();
@ -757,7 +764,10 @@ fn main() {
};
let enable_offset_and_bit = get_offset_and_bit(en_reg);
let needs_refcount = *rcc_field_count.get(&(en_reg.register, en_reg.field)).unwrap() > 1;
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
@ -853,7 +863,11 @@ fn main() {
})
}
let enum_names: BTreeSet<_> = clock_gen.muxes.iter().map(|(_, _, enum_name)| enum_name).collect();
let enum_names: BTreeSet<_> = clock_gen
.muxes
.iter()
.map(|(_, _, enum_name)| enum_name)
.collect();
g.extend(quote! {
pub mod mux {
@ -899,7 +913,11 @@ fn main() {
clock_gen.clock_names.insert("plli2s1_r".to_string());
}
let clock_idents: Vec<_> = clock_gen.clock_names.iter().map(|n| format_ident!("{}", n)).collect();
let clock_idents: Vec<_> = clock_gen
.clock_names
.iter()
.map(|n| format_ident!("{}", n))
.collect();
g.extend(quote! {
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@ -1471,7 +1489,9 @@ fn main() {
let pin_name = {
// If we encounter a _C pin but the split_feature for this pin is not enabled, skip it
if pin.pin.ends_with("_C") && !split_features.iter().any(|x| x.pin_name_with_c == pin.pin) {
if pin.pin.ends_with("_C")
&& !split_features.iter().any(|x| x.pin_name_with_c == pin.pin)
{
continue;
}
@ -1538,12 +1558,13 @@ fn main() {
} else {
let reg = format_ident!("{}", afio.register.to_lowercase());
let setter = format_ident!("set_{}", afio.field.to_lowercase());
let type_and_values = if is_bool_field("AFIO", afio.register, afio.field) {
let values = values.iter().map(|&v| v > 0);
quote!(AfioRemapBool, [#(#values),*])
} else {
quote!(AfioRemap, [#(#values),*])
};
let type_and_values =
if is_bool_field("AFIO", afio.register, afio.field) {
let values = values.iter().map(|&v| v > 0);
quote!(AfioRemapBool, [#(#values),*])
} else {
quote!(AfioRemap, [#(#values),*])
};
Some(quote! {
pin_trait_afio_impl!(#tr, #peri, #pin_name, {#reg, #setter, #type_and_values});
@ -1562,11 +1583,12 @@ fn main() {
"LPUART",
"TIM",
];
let not_applicable = if peripherals_with_afio.iter().any(|&x| p.name.starts_with(x)) {
quote!(, crate::gpio::AfioRemapNotApplicable)
} else {
quote!()
};
let not_applicable =
if peripherals_with_afio.iter().any(|&x| p.name.starts_with(x)) {
quote!(, crate::gpio::AfioRemapNotApplicable)
} else {
quote!()
};
Some(quote!(pin_trait_impl!(#tr, #peri, #pin_name, #af #not_applicable);))
};
@ -1583,7 +1605,9 @@ fn main() {
let peri = format_ident!("{}", p.name);
let pin_name = {
// If we encounter a _C pin but the split_feature for this pin is not enabled, skip it
if pin.pin.ends_with("_C") && !split_features.iter().any(|x| x.pin_name_with_c == pin.pin) {
if pin.pin.ends_with("_C")
&& !split_features.iter().any(|x| x.pin_name_with_c == pin.pin)
{
continue;
}
format_ident!("{}", pin.pin)
@ -1591,27 +1615,49 @@ fn main() {
// H7 has differential voltage measurements
let ch: Option<(u8, bool)> = if pin.signal.starts_with("INP") {
Some((pin.signal.strip_prefix("INP").unwrap().parse().unwrap(), false))
Some((
pin.signal.strip_prefix("INP").unwrap().parse().unwrap(),
false,
))
} else if pin.signal.starts_with("INN") {
Some((pin.signal.strip_prefix("INN").unwrap().parse().unwrap(), true))
Some((
pin.signal.strip_prefix("INN").unwrap().parse().unwrap(),
true,
))
} else if pin.signal.starts_with("IN") && pin.signal.ends_with('b') {
// we number STM32L1 ADC bank 1 as 0..=31, bank 2 as 32..=63
let signal = pin.signal.strip_prefix("IN").unwrap().strip_suffix('b').unwrap();
let signal = pin
.signal
.strip_prefix("IN")
.unwrap()
.strip_suffix('b')
.unwrap();
Some((32u8 + signal.parse::<u8>().unwrap(), false))
} else if pin.signal.starts_with("IN") {
Some((pin.signal.strip_prefix("IN").unwrap().parse().unwrap(), false))
Some((
pin.signal.strip_prefix("IN").unwrap().parse().unwrap(),
false,
))
} else {
None
};
if let Some((ch, false)) = ch {
adc_pairs.entry(ch).or_insert((None, None)).0.replace(pin_name.clone());
adc_pairs
.entry(ch)
.or_insert((None, None))
.0
.replace(pin_name.clone());
g.extend(quote! {
impl_adc_pin!( #peri, #pin_name, #ch);
})
}
if let Some((ch, true)) = ch {
adc_pairs.entry(ch).or_insert((None, None)).1.replace(pin_name.clone());
adc_pairs
.entry(ch)
.or_insert((None, None))
.1
.replace(pin_name.clone());
}
}
@ -1711,7 +1757,7 @@ fn main() {
(("timer", "CH3"), quote!(crate::timer::Dma<Ch3>)),
(("timer", "CH4"), quote!(crate::timer::Dma<Ch4>)),
(("cordic", "WRITE"), quote!(crate::cordic::WriteDma)), // FIXME: stm32u5a crash on Cordic driver
(("cordic", "READ"), quote!(crate::cordic::ReadDma)), // FIXME: stm32u5a crash on Cordic driver
(("cordic", "READ"), quote!(crate::cordic::ReadDma)), // FIXME: stm32u5a crash on Cordic driver
]
.into();
@ -1787,13 +1833,15 @@ fn main() {
let register = format_ident!("{}", remap_info.register.to_lowercase());
let setter = format_ident!("set_{}", remap_info.field.to_lowercase());
let value = if is_bool_field("SYSCFG", &remap_info.register, &remap_info.field) {
let bool_value = format_ident!("{}", remap_info.value > 0);
quote!(#bool_value)
} else {
let value = remap_info.value;
quote!(#value.into())
};
let value =
if is_bool_field("SYSCFG", &remap_info.register, &remap_info.field)
{
let bool_value = format_ident!("{}", remap_info.value > 0);
quote!(#bool_value)
} else {
let value = remap_info.value;
quote!(#value.into())
};
remap.extend(quote!(crate::pac::SYSCFG.#register().modify(|w| w.#setter(#value));));
}
@ -1828,9 +1876,16 @@ fn main() {
fn is_rcc_name(e: &str) -> bool {
match e {
"Pllp" | "Pllq" | "Pllr" | "Plldivst" | "Pllm" | "Plln" | "Prediv1" | "Prediv2" | "Hpre5" => true,
"Pllp" | "Pllq" | "Pllr" | "Plldivst" | "Pllm" | "Plln" | "Prediv1"
| "Prediv2" | "Hpre5" => true,
"Timpre" | "Pllrclkpre" => false,
e if e.ends_with("pre") || e.ends_with("pres") || e.ends_with("div") || e.ends_with("mul") => true,
e if e.ends_with("pre")
|| e.ends_with("pres")
|| e.ends_with("div")
|| e.ends_with("mul") =>
{
true
}
_ => false,
}
}
@ -1850,7 +1905,8 @@ fn main() {
Err(())
}
if (kind == "rcc" && is_rcc_name(e.name)) || ((kind == "adccommon" || kind == "adc") && is_adc_name(e.name))
if (kind == "rcc" && is_rcc_name(e.name))
|| ((kind == "adccommon" || kind == "adc") && is_adc_name(e.name))
{
let kind = format_ident!("{}", kind);
let enum_name = format_ident!("{}", e.name);
@ -1858,7 +1914,10 @@ fn main() {
let mut divs = Vec::new();
for v in e.variants {
let Ok(val) = parse_num(v.name) else {
panic!("could not parse mul/div. enum={} variant={}", e.name, v.name)
panic!(
"could not parse mul/div. enum={} variant={}",
e.name, v.name
)
};
let variant_name = format_ident!("{}", v.name);
let variant = quote!(crate::pac::#kind::vals::#enum_name::#variant_name);
@ -1951,7 +2010,11 @@ fn main() {
for pin in METADATA.pins {
let port_letter = pin.name.chars().nth(1).unwrap();
let pname = format!("GPIO{}", port_letter);
let p = METADATA.peripherals.iter().find(|p| p.name == pname).unwrap();
let p = METADATA
.peripherals
.iter()
.find(|p| p.name == pname)
.unwrap();
assert_eq!(0, (p.address as u32 - gpio_base) % gpio_stride);
let port_num = (p.address as u32 - gpio_base) / gpio_stride;
let pin_num: u32 = pin.name[2..].parse().unwrap();
@ -1988,14 +2051,22 @@ fn main() {
let adc_num = p.name.strip_prefix("ADC").unwrap();
let mut adc_common = None;
for p2 in METADATA.peripherals {
if let Some(common_nums) = p2.name.strip_prefix("ADC").and_then(|s| s.strip_suffix("_COMMON")) {
if let Some(common_nums) = p2
.name
.strip_prefix("ADC")
.and_then(|s| s.strip_suffix("_COMMON"))
{
if common_nums.contains(adc_num) {
adc_common = Some(p2);
}
}
}
let adc_common = adc_common.map(|p| p.name).unwrap_or("none");
let row = vec![p.name.to_string(), adc_common.to_string(), "adc".to_string()];
let row = vec![
p.name.to_string(),
adc_common.to_string(),
"adc".to_string(),
];
adc_table.push(row);
}
@ -2053,7 +2124,10 @@ fn main() {
#[cfg(feature = "_dual-core")]
for (irq, channels) in &dma_irqs {
for channel in channels {
dma_ch_to_irq.entry(channel).or_default().push(irq.to_string());
dma_ch_to_irq
.entry(channel)
.or_default()
.push(irq.to_string());
}
}
@ -2098,7 +2172,9 @@ fn main() {
"dma" => quote!(crate::dma::DmaInfo::Dma(crate::pac::#dma)),
"bdma" => quote!(crate::dma::DmaInfo::Bdma(crate::pac::#dma)),
"gpdma" => quote!(crate::pac::#dma),
"lpdma" => quote!(unsafe { crate::pac::gpdma::Gpdma::from_ptr(crate::pac::#dma.as_ptr())}),
"lpdma" => {
quote!(unsafe { crate::pac::gpdma::Gpdma::from_ptr(crate::pac::#dma.as_ptr())})
}
_ => panic!("bad dma channel kind {}", bi.kind),
};
@ -2166,7 +2242,12 @@ fn main() {
// ========
// Generate gpio_block() function
let gpio_base = METADATA.peripherals.iter().find(|p| p.name == "GPIOA").unwrap().address as usize;
let gpio_base = METADATA
.peripherals
.iter()
.find(|p| p.name == "GPIOA")
.unwrap()
.address as usize;
let gpio_stride = 0x400 as usize;
for p in METADATA.peripherals {
@ -2231,8 +2312,10 @@ fn main() {
cfgs.declare("eeprom");
let eeprom_memory_regions: Vec<&MemoryRegion> =
memory.iter().filter(|x| x.kind == MemoryRegionKind::Eeprom).collect();
let eeprom_memory_regions: Vec<&MemoryRegion> = memory
.iter()
.filter(|x| x.kind == MemoryRegionKind::Eeprom)
.collect();
if !eeprom_memory_regions.is_empty() {
cfgs.enable("eeprom");
@ -2252,7 +2335,11 @@ fn main() {
"EEPROM regions for chip {} are not contiguous, which is unexpected for L0/L1 series. \
First region: '{}' at {:#X}. Found next non-contiguous region: '{}' at {:#X}. \
Please verify chip metadata. Embassy currently assumes contiguous EEPROM for these series.",
chip_name, sorted_eeprom_regions[0].name, first_eeprom_address, region.name, region.address
chip_name,
sorted_eeprom_regions[0].name,
first_eeprom_address,
region.name,
region.address
);
}
total_eeprom_size += region.size;
@ -2485,7 +2572,10 @@ fn gen_memory_x(memory: &[MemoryRegion], out_dir: &Path) {
}
fn get_memory_range(memory: &[MemoryRegion], kind: MemoryRegionKind) -> (u32, u32, String) {
let mut mems: Vec<_> = memory.iter().filter(|m| m.kind == kind && m.size != 0).collect();
let mut mems: Vec<_> = memory
.iter()
.filter(|m| m.kind == kind && m.size != 0)
.collect();
mems.sort_by_key(|m| m.address);
let mut start = u32::MAX;
@ -2524,7 +2614,8 @@ fn mem_filter(chip: &str, region: &str) -> bool {
return false;
}
if region.starts_with("SDRAM_") || region.starts_with("FMC_") || region.starts_with("OCTOSPI_") {
if region.starts_with("SDRAM_") || region.starts_with("FMC_") || region.starts_with("OCTOSPI_")
{
return false;
}

View File

@ -12,7 +12,7 @@
#[cfg_attr(adc_l0, path = "v1.rs")]
#[cfg_attr(adc_v2, path = "v2.rs")]
#[cfg_attr(any(adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0), path = "v3.rs")]
#[cfg_attr(any(adc_v4, adc_u5), path = "v4.rs")]
#[cfg_attr(any(adc_v4, adc_u5, adc_u3), path = "v4.rs")]
#[cfg_attr(adc_g4, path = "g4.rs")]
#[cfg_attr(adc_c0, path = "c0.rs")]
mod _version;
@ -126,7 +126,7 @@ trait SealedInstance: BasicInstance {
}
pub(crate) trait SealedAdcChannel<T> {
#[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))]
#[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_u3, adc_wba))]
fn setup(&mut self) {}
#[allow(unused)]
@ -138,7 +138,7 @@ pub(crate) trait SealedAdcChannel<T> {
}
}
#[cfg(any(adc_c0, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))]
#[cfg(any(adc_c0, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_u3))]
/// Number of samples used for averaging.
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@ -152,18 +152,20 @@ pub enum Averaging {
Samples64,
Samples128,
Samples256,
#[cfg(any(adc_c0, adc_v4, adc_u5))]
#[cfg(any(adc_c0, adc_v4, adc_u5, adc_u3))]
Samples512,
#[cfg(any(adc_c0, adc_v4, adc_u5))]
#[cfg(any(adc_c0, adc_v4, adc_u5, adc_u3))]
Samples1024,
}
#[cfg(any(
adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0
adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_u3, adc_wba, adc_c0
))]
pub(crate) enum ConversionMode {
// Should match the cfg on "read" below
#[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))]
#[cfg(any(
adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_u3, adc_wba, adc_c0
))]
Singular,
// Should match the cfg on "into_ring_buffered" below
#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
@ -184,7 +186,7 @@ pub enum RegularConversionMode {
impl<'d, T: Instance> Adc<'d, T> {
#[cfg(any(
adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v3, adc_v4, adc_wba, adc_c0
adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u3, adc_u5, adc_v3, adc_v4, adc_wba, adc_c0
))]
/// Read an ADC pin.
pub fn blocking_read(
@ -192,12 +194,12 @@ impl<'d, T: Instance> Adc<'d, T> {
channel: &mut impl AdcChannel<T>,
sample_time: <T::Regs as BasicAdcRegs>::SampleTime,
) -> u16 {
#[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))]
#[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u3, adc_u5, adc_wba))]
channel.setup();
// Ensure no conversions are ongoing
T::regs().stop();
#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h7rs, adc_u0, adc_u5, adc_wba, adc_c0))]
#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h7rs, adc_u0, adc_u3, adc_u5, adc_wba, adc_c0))]
T::regs().enable();
T::regs().configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter());
@ -211,7 +213,9 @@ impl<'d, T: Instance> Adc<'d, T> {
unsafe { core::ptr::read_volatile(T::regs().data()) }
}
#[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))]
#[cfg(any(
adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_u3, adc_wba, adc_c0
))]
/// Read one or multiple ADC regular channels using DMA.
///
/// `readings` must have a length that is a multiple of the length of the `sequence` iterator.
@ -263,7 +267,7 @@ impl<'d, T: Instance> Adc<'d, T> {
// Ensure no conversions are ongoing
T::regs().stop();
#[cfg(any(adc_g0, adc_v3, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))]
#[cfg(any(adc_g0, adc_v3, adc_h7rs, adc_u0, adc_v4, adc_u3, adc_u5, adc_wba, adc_c0))]
T::regs().enable();
T::regs().configure_sequence(
@ -401,7 +405,7 @@ impl SpecialChannel for Dac {}
/// ADC instance.
#[cfg(not(any(
adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_g4, adc_f3v1, adc_f3v2, adc_g0, adc_u0, adc_h5, adc_h7rs,
adc_u5, adc_c0, adc_wba,
adc_u5, adc_u3, adc_c0, adc_wba,
)))]
#[allow(private_bounds)]
pub trait Instance: SealedInstance + crate::PeripheralType {
@ -410,7 +414,7 @@ pub trait Instance: SealedInstance + crate::PeripheralType {
/// ADC instance.
#[cfg(any(
adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_g4, adc_f3v1, adc_f3v2, adc_g0, adc_u0, adc_h5, adc_h7rs,
adc_u5, adc_c0, adc_wba,
adc_u5, adc_u3, adc_c0, adc_wba,
))]
#[allow(private_bounds)]
pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeripheral {
@ -425,7 +429,7 @@ pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized {
where
Self: 'a,
{
#[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))]
#[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u3, adc_u5, adc_wba))]
self.setup();
AnyAdcChannel {
@ -600,7 +604,9 @@ macro_rules! impl_adc_pin {
($inst:ident, $pin:ident, $ch:expr) => {
impl crate::adc::AdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> {}
impl crate::adc::SealedAdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> {
#[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))]
#[cfg(any(
adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u3, adc_u5, adc_wba
))]
fn setup(&mut self) {
<crate::peripherals::$pin as crate::gpio::SealedPin>::set_as_analog(self);
}
@ -628,7 +634,7 @@ macro_rules! impl_adc_pair {
crate::Peri<'_, crate::peripherals::$npin>,
)
{
#[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))]
#[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u3, adc_u5, adc_wba))]
fn setup(&mut self) {
<crate::peripherals::$pin as crate::gpio::SealedPin>::set_as_analog(&mut self.0);
<crate::peripherals::$npin as crate::gpio::SealedPin>::set_as_analog(&mut self.1);

View File

@ -1,7 +1,10 @@
#[cfg(not(stm32u5))]
#[cfg(not(stm32u3))]
use pac::adc::vals::Difsel;
#[cfg(not(any(stm32u5, stm32u3)))]
use pac::adc::vals::{Adcaldif, Boost};
#[allow(unused)]
use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel};
use pac::adc::vals::{Adstp, Dmngt, Exten, Pcsel};
#[cfg(not(stm32u3))]
use pac::adccommon::vals::Presc;
use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us};
@ -23,6 +26,8 @@ const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60);
const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50);
#[cfg(stm32u5)]
const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(55);
#[cfg(stm32u3)]
const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(48);
#[cfg(stm32g4)]
impl<T: Instance> super::SealedSpecialConverter<super::VrefInt> for T {
@ -43,12 +48,12 @@ impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
}
// TODO this should be 14 for H7a/b/35
#[cfg(not(stm32u5))]
#[cfg(not(any(stm32u5, stm32u3)))]
impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
const CHANNEL: u8 = 17;
}
#[cfg(stm32u5)]
#[cfg(any(stm32u5, stm32u3))]
impl<T: DefaultInstance> super::SealedSpecialConverter<super::VrefInt> for T {
const CHANNEL: u8 = 0;
}
@ -61,6 +66,17 @@ impl<T: DefaultInstance> super::SealedSpecialConverter<super::Vbat> for T {
const CHANNEL: u8 = 18;
}
#[cfg(stm32u3)]
impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T {
const CHANNEL: u8 = 16;
}
#[cfg(stm32u3)]
impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T {
const CHANNEL: u8 = 17;
}
#[cfg(not(stm32u3))]
fn from_ker_ck(frequency: Hertz) -> Presc {
let raw_prescaler = rcc::raw_prescaler(frequency.0, MAX_ADC_CLK_FREQ.0);
match raw_prescaler {
@ -163,7 +179,7 @@ impl AdcRegs for crate::pac::adc::Adc {
self.smpr(1).modify(|reg| reg.set_smp((channel - 10) as _, sample_time));
}
#[cfg(any(stm32h7, stm32u5))]
#[cfg(any(stm32h7, stm32u5, stm32u3))]
{
self.cfgr2().modify(|w| w.set_lshift(0));
self.pcsel().modify(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED));
@ -202,7 +218,9 @@ impl<'d, T: Instance<Regs = crate::pac::adc::Adc>> Adc<'d, T> {
// Set the ADC resolution.
if let Some(resolution) = config.resolution {
T::regs().cfgr().modify(|reg| reg.set_res(resolution.into()));
T::regs()
.cfgr()
.modify(|reg| reg.set_res(resolution.into()));
}
// Set hardware averaging.
@ -235,11 +253,16 @@ impl<'d, T: Instance<Regs = crate::pac::adc::Adc>> Adc<'d, T> {
pub fn new(adc: Peri<'d, T>) -> Self {
rcc::enable_and_reset::<T>();
#[cfg(not(stm32u3))]
let prescaler = from_ker_ck(T::frequency());
#[cfg(not(stm32u3))]
T::common_regs().ccr().modify(|w| w.set_presc(prescaler));
#[cfg(not(stm32u3))]
let frequency = T::frequency() / prescaler;
#[cfg(stm32u3)]
let frequency = T::frequency();
info!("ADC frequency set to {}", frequency);
if frequency > MAX_ADC_CLK_FREQ {
@ -270,12 +293,14 @@ impl<'d, T: Instance<Regs = crate::pac::adc::Adc>> Adc<'d, T> {
blocking_delay_us(10);
#[cfg(not(stm32u3))]
T::regs().difsel().modify(|w| {
for n in 0..20 {
w.set_difsel(n, Difsel::SINGLE_ENDED);
}
});
#[cfg(not(stm32u3))]
T::regs().cr().modify(|w| {
#[cfg(not(adc_u5))]
w.set_adcaldif(Adcaldif::SINGLE_ENDED);

View File

@ -160,7 +160,7 @@ pub enum TriggerSel {
}
/// Trigger selection for L4+, L5, U5, H7.
#[cfg(any(stm32l4_plus, stm32l5, stm32u5, stm32h7))]
#[cfg(any(stm32l4_plus, stm32l5, stm32u5, stm32u3, stm32h7))]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum TriggerSel {
@ -168,9 +168,11 @@ pub enum TriggerSel {
Tim1 = 1,
Tim2 = 2,
Tim4 = 3,
#[cfg(not(stm32u3))]
Tim5 = 4,
Tim6 = 5,
Tim7 = 6,
#[cfg(not(stm32u3))]
Tim8 = 7,
Tim15 = 8,
#[cfg(all(stm32h7, hrtim))]
@ -178,9 +180,9 @@ pub enum TriggerSel {
#[cfg(all(stm32h7, hrtim))]
Hrtim1DacTrg2 = 10,
Lptim1 = 11,
#[cfg(not(stm32u5))]
#[cfg(not(any(stm32u5, stm32u3)))]
Lptim2 = 12,
#[cfg(stm32u5)]
#[cfg(any(stm32u5, stm32u3))]
Lptim3 = 12,
Exti9 = 13,
#[cfg(any(stm32h7ax, stm32h7bx))]

View File

@ -34,11 +34,13 @@ fn cpu_regs() -> pac::exti::Exti {
EXTI
}
#[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, gpio_v1, exti_u5, exti_h5, exti_h50, exti_n6)))]
#[cfg(not(any(
exti_c0, exti_g0, exti_u0, exti_l5, gpio_v1, exti_u5, exti_u3, exti_h5, exti_h50, exti_n6
)))]
fn exticr_regs() -> pac::syscfg::Syscfg {
pac::SYSCFG
}
#[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6))]
#[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_u3, exti_h5, exti_h50, exti_n6))]
fn exticr_regs() -> pac::exti::Exti {
EXTI
}
@ -48,9 +50,9 @@ fn exticr_regs() -> pac::afio::Afio {
}
unsafe fn on_irq() {
#[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6)))]
#[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_u3, exti_h5, exti_h50, exti_n6)))]
let bits = EXTI.pr(0).read().0;
#[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6))]
#[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_u3, exti_h5, exti_h50, exti_n6))]
let bits = EXTI.rpr(0).read().0 | EXTI.fpr(0).read().0;
// We don't handle or change any EXTI lines above 16.
@ -65,9 +67,9 @@ unsafe fn on_irq() {
}
// Clear pending
#[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6)))]
#[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_u3, exti_h5, exti_h50, exti_n6)))]
EXTI.pr(0).write_value(Lines(bits));
#[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50, exti_n6))]
#[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_u3, exti_h5, exti_h50, exti_n6))]
{
EXTI.rpr(0).write_value(Lines(bits));
EXTI.fpr(0).write_value(Lines(bits));

View File

@ -271,11 +271,11 @@ pub struct Config {
/// which needs to be enabled before these pins can be used.
///
/// May increase power consumption. Defaults to true.
#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba))]
#[cfg(any(stm32l4, stm32l5, stm32u5, stm32u3, stm32wba))]
pub enable_independent_io_supply: bool,
/// On the U5 series all analog peripherals are powered by a separate supply.
#[cfg(stm32u5)]
#[cfg(any(stm32u5, stm32u3))]
pub enable_independent_analog_supply: bool,
/// BDMA interrupt priority.
@ -319,9 +319,9 @@ impl Default for Config {
min_stop_pause: embassy_time::Duration::from_millis(250),
#[cfg(dbgmcu)]
enable_debug_during_sleep: true,
#[cfg(any(stm32l4, stm32l5, stm32u5, stm32wba))]
#[cfg(any(stm32l4, stm32l5, stm32u5, stm32u3, stm32wba))]
enable_independent_io_supply: true,
#[cfg(stm32u5)]
#[cfg(any(stm32u5, stm32u3))]
enable_independent_analog_supply: true,
#[cfg(bdma)]
bdma_interrupt_priority: Priority::P0,
@ -393,7 +393,10 @@ mod dual_core {
///
/// The `shared_data` is used to coordinate the init with the second core. Read the [SharedData] docs
/// for more information on its requirements.
pub fn init_primary(config: Config, shared_data: &'static MaybeUninit<SharedData>) -> Peripherals {
pub fn init_primary(
config: Config,
shared_data: &'static MaybeUninit<SharedData>,
) -> Peripherals {
let shared_data = unsafe { shared_data.assume_init_ref() };
// Write the flag as soon as possible. Reading this flag uninitialized in the `init_secondary`
@ -406,7 +409,9 @@ mod dual_core {
unsafe { *shared_data.config.get() }.write(config.into());
shared_data.init_flag.store(INIT_DONE_FLAG, Ordering::SeqCst);
shared_data
.init_flag
.store(INIT_DONE_FLAG, Ordering::SeqCst);
p
}
@ -420,7 +425,9 @@ mod dual_core {
///
/// The `shared_data` is used to coordinate the init with the second core. Read the [SharedData] docs
/// for more information on its requirements.
pub fn try_init_secondary(shared_data: &'static MaybeUninit<SharedData>) -> Option<Peripherals> {
pub fn try_init_secondary(
shared_data: &'static MaybeUninit<SharedData>,
) -> Option<Peripherals> {
let shared_data = unsafe { shared_data.assume_init_ref() };
if shared_data.init_flag.load(Ordering::SeqCst) != INIT_DONE_FLAG {
@ -536,14 +543,17 @@ fn init_hw(config: Config) -> Peripherals {
cr.set_stop(config.enable_debug_during_sleep);
cr.set_standby(config.enable_debug_during_sleep);
}
#[cfg(any(dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u0, dbgmcu_u5, dbgmcu_wba, dbgmcu_l5))]
#[cfg(any(
dbgmcu_f0, dbgmcu_c0, dbgmcu_g0, dbgmcu_u0, dbgmcu_u3, dbgmcu_u5, dbgmcu_wba,
dbgmcu_l5
))]
{
cr.set_dbg_stop(config.enable_debug_during_sleep);
cr.set_dbg_standby(config.enable_debug_during_sleep);
}
#[cfg(any(
dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7, dbgmcu_l0, dbgmcu_l1,
dbgmcu_l4, dbgmcu_wb, dbgmcu_wl, dbgmcu_n6
dbgmcu_f1, dbgmcu_f2, dbgmcu_f3, dbgmcu_f4, dbgmcu_f7, dbgmcu_g4, dbgmcu_f7,
dbgmcu_l0, dbgmcu_l1, dbgmcu_l4, dbgmcu_wb, dbgmcu_wl, dbgmcu_n6
))]
{
cr.set_dbg_sleep(config.enable_debug_during_sleep);
@ -564,7 +574,10 @@ fn init_hw(config: Config) -> Peripherals {
rcc::enable_and_reset_with_cs::<peripherals::SYSCFG>(cs);
#[cfg(not(any(stm32h5, stm32h7, stm32h7rs, stm32wb, stm32wl)))]
rcc::enable_and_reset_with_cs::<peripherals::PWR>(cs);
#[cfg(all(flash, not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7, stm32h7rs))))]
#[cfg(all(
flash,
not(any(stm32f2, stm32f4, stm32f7, stm32l0, stm32h5, stm32h7, stm32h7rs))
))]
rcc::enable_and_reset_with_cs::<peripherals::FLASH>(cs);
// Enable the VDDIO2 power supply on chips that have it.
@ -589,7 +602,7 @@ fn init_hw(config: Config) -> Peripherals {
});
});
}
#[cfg(stm32u5)]
#[cfg(any(stm32u5, stm32u3))]
{
crate::pac::PWR.svmcr().modify(|w| {
w.set_io2sv(config.enable_independent_io_supply);

View File

@ -25,7 +25,7 @@ pub struct LseConfig {
pub frequency: Hertz,
pub mode: LseMode,
/// If peripherals other than RTC/TAMP or RCC functions need the lse this bit must be set
#[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba))]
#[cfg(any(rcc_l5, rcc_u5, rcc_u3, rcc_wle, rcc_wl5, rcc_wba))]
pub peripherals_clocked: bool,
}
@ -71,10 +71,10 @@ fn unlock() {
#[cfg(any(stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1))]
let cr = crate::pac::PWR.cr();
#[cfg(not(any(
stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1, stm32u5, stm32h5, stm32wba, stm32n6
stm32f0, stm32f1, stm32f2, stm32f3, stm32l0, stm32l1, stm32u5, stm32u3, stm32h5, stm32wba, stm32n6
)))]
let cr = crate::pac::PWR.cr1();
#[cfg(any(stm32u5, stm32h5, stm32wba, stm32n6))]
#[cfg(any(stm32u5, stm32u3, stm32h5, stm32wba, stm32n6))]
let cr = crate::pac::PWR.dbpcr();
cr.modify(|w| w.set_dbp(true));
@ -118,7 +118,7 @@ impl LsConfig {
lse: Some(LseConfig {
frequency: Hertz(32_768),
mode: LseMode::Oscillator(LseDrive::MediumHigh),
#[cfg(any(rcc_l5, rcc_u5, rcc_wle, rcc_wl5, rcc_wba))]
#[cfg(any(rcc_l5, rcc_u5, rcc_u3, rcc_wle, rcc_wl5, rcc_wba))]
peripherals_clocked: false,
}),
lsi: false,

View File

@ -39,9 +39,11 @@ pub(crate) fn init_hsi48(config: Hsi48Config) -> Hertz {
});
// Enable HSI48
#[cfg(not(any(stm32u5, stm32g0, stm32h5, stm32h7, stm32h7rs, stm32u5, stm32wba, stm32f0, stm32c071)))]
#[cfg(not(any(
stm32u5, stm32u3, stm32g0, stm32h5, stm32h7, stm32h7rs, stm32u5, stm32wba, stm32f0, stm32c071
)))]
let r = RCC.crrcr();
#[cfg(any(stm32u5, stm32g0, stm32h5, stm32h7, stm32h7rs, stm32u5, stm32wba, stm32c071))]
#[cfg(any(stm32u5, stm32u3, stm32g0, stm32h5, stm32h7, stm32h7rs, stm32u5, stm32wba, stm32c071))]
let r = RCC.cr();
#[cfg(any(stm32f0))]
let r = RCC.cr2();

View File

@ -4,6 +4,35 @@ use embassy_hal_internal::PeripheralType;
use crate::gpio::{AfType, OutputType, Speed};
use crate::pac::RCC;
#[cfg(any(
rcc_f2,
rcc_f410,
rcc_f4,
rcc_f7,
rcc_h50,
rcc_h5,
rcc_h7ab,
rcc_h7rm0433,
rcc_h7,
rcc_h7rs,
rcc_n6
))]
pub use crate::pac::rcc::vals::Mco1sel as Mco1Source;
#[cfg(any(
rcc_f2,
rcc_f410,
rcc_f4,
rcc_f7,
rcc_h50,
rcc_h5,
rcc_h7ab,
rcc_h7rm0433,
rcc_h7,
rcc_h7rs,
rcc_n6,
rcc_u3,
))]
pub use crate::pac::rcc::vals::Mco2sel as Mco2Source;
#[cfg(not(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37)))]
pub use crate::pac::rcc::vals::Mcopre as McoPrescaler;
#[cfg(not(any(
@ -20,20 +49,7 @@ pub use crate::pac::rcc::vals::Mcopre as McoPrescaler;
rcc_n6
)))]
pub use crate::pac::rcc::vals::Mcosel as McoSource;
#[cfg(any(
rcc_f2,
rcc_f410,
rcc_f4,
rcc_f7,
rcc_h50,
rcc_h5,
rcc_h7ab,
rcc_h7rm0433,
rcc_h7,
rcc_h7rs,
rcc_n6
))]
pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source};
use crate::{Peri, peripherals};
#[cfg(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37))]
@ -61,9 +77,9 @@ macro_rules! impl_peri {
type Source = $source;
unsafe fn _apply_clock_settings(source: Self::Source, _prescaler: McoPrescaler) {
#[cfg(not(any(stm32u5, stm32wba, stm32n6)))]
#[cfg(not(any(stm32u3, stm32u5, stm32wba, stm32n6)))]
let r = RCC.cfgr();
#[cfg(any(stm32u5, stm32wba))]
#[cfg(any(stm32u3, stm32u5, stm32wba))]
let r = RCC.cfgr1();
#[cfg(any(stm32n6))]
let r = RCC.ccipr5();

View File

@ -28,6 +28,7 @@ pub use hsi48::*;
#[cfg_attr(stm32g4, path = "g4.rs")]
#[cfg_attr(any(stm32h5, stm32h7, stm32h7rs), path = "h.rs")]
#[cfg_attr(any(stm32l0, stm32l1, stm32l4, stm32l5, stm32wb, stm32wl, stm32u0), path = "l.rs")]
#[cfg_attr(stm32u3, path = "u3.rs")]
#[cfg_attr(stm32u5, path = "u5.rs")]
#[cfg_attr(stm32wba, path = "wba.rs")]
#[cfg_attr(stm32n6, path = "n6.rs")]

555
embassy-stm32/src/rcc/u3.rs Normal file
View File

@ -0,0 +1,555 @@
use stm32_metapac::rcc::vals::{Msikdiv, Msisdiv, Msissel};
// pub use crate::pac::pwr::vals::Vosr as VoltageScale;
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler, Sw as Sysclk};
use crate::pac::rcc::vals::{Hseext, Msipllsel, Msirgsel};
use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::LSI_FREQ;
use crate::time::Hertz;
/// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000);
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum VoltageScale {
/// High performance range (system clock freq up to 96MHz)
RANGE1,
/// Low power range (system clock freq up to 48MHz)
RANGE2,
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum MSIRange {
/// MSIRC0
/// Range 0: 96 MHz
RANGE0_96MHZ,
/// Range 1: 48 MHz
RANGE1_48MHZ,
/// Range 2/4: 24 MHz
RANGE2_24MHZ,
/// Range 3/5: 12 MHz
RANGE3_12MHZ,
/// MSIRC1
/// Range 4: 24 MHz
RANGE4_24MHZ,
/// Range 5: 12 MHz
RANGE5_12MHZ,
/// Range 6: 6 MHz
RANGE6_6MHZ,
/// Range 7: 3 MHz
RANGE7_3MHZ,
}
impl From<MSIRange> for Msisdiv {
fn from(range: MSIRange) -> Self {
match range {
MSIRange::RANGE0_96MHZ => Msisdiv::DIV1,
MSIRange::RANGE1_48MHZ => Msisdiv::DIV2,
MSIRange::RANGE2_24MHZ => Msisdiv::DIV4,
MSIRange::RANGE3_12MHZ => Msisdiv::DIV8,
MSIRange::RANGE4_24MHZ => Msisdiv::DIV1,
MSIRange::RANGE5_12MHZ => Msisdiv::DIV2,
MSIRange::RANGE6_6MHZ => Msisdiv::DIV4,
MSIRange::RANGE7_3MHZ => Msisdiv::DIV8,
}
}
}
impl From<MSIRange> for Msikdiv {
fn from(range: MSIRange) -> Self {
match range {
MSIRange::RANGE0_96MHZ => Msikdiv::DIV1,
MSIRange::RANGE1_48MHZ => Msikdiv::DIV2,
MSIRange::RANGE2_24MHZ => Msikdiv::DIV4,
MSIRange::RANGE3_12MHZ => Msikdiv::DIV8,
MSIRange::RANGE4_24MHZ => Msikdiv::DIV1,
MSIRange::RANGE5_12MHZ => Msikdiv::DIV2,
MSIRange::RANGE6_6MHZ => Msikdiv::DIV4,
MSIRange::RANGE7_3MHZ => Msikdiv::DIV8,
}
}
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub enum HseMode {
/// crystal/ceramic oscillator (HSEBYP=0)
Oscillator,
/// external analog clock (low swing) (HSEBYP=1, HSEEXT=0)
Bypass,
/// external digital clock (full swing) (HSEBYP=1, HSEEXT=1)
BypassDigital,
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Hse {
/// HSE frequency.
pub freq: Hertz,
/// HSE mode.
pub mode: HseMode,
}
#[derive(Clone, Copy, PartialEq)]
pub enum MsiAutoCalibration {
/// MSI auto-calibration is disabled
Disabled,
/// MSIS is given priority for auto-calibration
MSIS,
/// MSIK is given priority for auto-calibration
MSIK,
/// MSIS with fast mode (always on)
MsisFast,
/// MSIK with fast mode (always on)
MsikFast,
}
impl MsiAutoCalibration {
const fn default() -> Self {
MsiAutoCalibration::Disabled
}
fn base_mode(&self) -> Self {
match self {
MsiAutoCalibration::Disabled => MsiAutoCalibration::Disabled,
MsiAutoCalibration::MSIS => MsiAutoCalibration::MSIS,
MsiAutoCalibration::MSIK => MsiAutoCalibration::MSIK,
MsiAutoCalibration::MsisFast => MsiAutoCalibration::MSIS,
MsiAutoCalibration::MsikFast => MsiAutoCalibration::MSIK,
}
}
fn is_fast(&self) -> bool {
matches!(
self,
MsiAutoCalibration::MsisFast | MsiAutoCalibration::MsikFast
)
}
}
impl Default for MsiAutoCalibration {
fn default() -> Self {
Self::default()
}
}
#[derive(Clone, Copy)]
pub struct Config {
// base clock sources
pub msis: Option<MSIRange>,
pub msik: Option<MSIRange>,
pub hsi: bool,
pub hse: Option<Hse>,
pub hsi48: Option<super::Hsi48Config>,
// sysclk, buses.
pub sys: Sysclk,
pub ahb_pre: AHBPrescaler,
pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler,
pub apb3_pre: APBPrescaler,
/// The voltage range influences the maximum clock frequencies for different parts of the
/// device. In particular, system clocks exceeding 48 MHz require `RANGE1`.
///
/// See RM0487 § 10.2.3 for clock source frequency limits.
pub voltage_range: VoltageScale,
pub ls: super::LsConfig,
/// Per-peripheral kernel clock selection muxes
pub mux: super::mux::ClockMux,
pub auto_calibration: MsiAutoCalibration,
}
impl Config {
pub const fn new() -> Self {
Self {
msis: Some(MSIRange::RANGE5_12MHZ),
msik: Some(MSIRange::RANGE5_12MHZ),
hse: None,
hsi: false,
hsi48: Some(crate::rcc::Hsi48Config::new()),
sys: Sysclk::MSIS,
ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1,
apb3_pre: APBPrescaler::DIV1,
voltage_range: VoltageScale::RANGE1,
ls: crate::rcc::LsConfig::new(),
mux: super::mux::ClockMux::default(),
auto_calibration: MsiAutoCalibration::default(),
}
}
}
impl Default for Config {
fn default() -> Self {
Self::new()
}
}
pub(crate) unsafe fn init(config: Config) {
// Set the requested power mode
// Voltage range enable bits must be at opposite values and can
// only be set once the current range is ready. See RM0487 § 9.5.4.
match config.voltage_range {
VoltageScale::RANGE1 => {
if PWR.vosr().read().r2en() {
while !PWR.vosr().read().r2rdy() {}
}
PWR.vosr().modify(|w| {
w.set_r1en(true);
w.set_r2en(false);
});
while !PWR.vosr().read().r1rdy() {}
}
VoltageScale::RANGE2 => {
if PWR.vosr().read().r1en() {
while !PWR.vosr().read().r1rdy() {}
}
PWR.vosr().modify(|w| {
w.set_r2en(true);
w.set_r1en(false);
});
while !PWR.vosr().read().r2rdy() {}
}
}
let lse_calibration_freq = if config.auto_calibration != MsiAutoCalibration::Disabled {
// LSE must be configured and peripherals clocked for MSI auto-calibration
let lse_config = config
.ls
.lse
.clone()
.expect("LSE must be configured for MSI auto-calibration");
assert!(lse_config.peripherals_clocked);
// Expect less than +/- 5% deviation for LSE frequency
if (31_100..=34_400).contains(&lse_config.frequency.0) {
// Check that the calibration is applied to an active clock
match (
config.auto_calibration.base_mode(),
config.msis.is_some(),
config.msik.is_some(),
) {
(MsiAutoCalibration::MSIS, true, _) => {
// MSIS is active and using LSE for auto-calibration
Some(lse_config.frequency)
}
(MsiAutoCalibration::MSIK, _, true) => {
// MSIK is active and using LSE for auto-calibration
Some(lse_config.frequency)
}
// improper configuration
_ => panic!(
"MSIx auto-calibration is enabled for a source that has not been configured."
),
}
} else {
panic!(
"LSE frequency more than 5% off from 32.768 kHz, cannot use for MSI auto-calibration"
);
}
} else {
None
};
let mut msis = config.msis.map(|range| {
// Check MSI output per RM0487 § 10.2.3 Table 98
match config.voltage_range {
VoltageScale::RANGE2 => {
assert!(msirange_to_hertz(range).0 <= 48_000_000);
}
_ => {}
}
// RM0487 § 10.5.2: spin until MSIS is off or MSIS is ready before setting its range
loop {
let cr = RCC.cr().read();
if cr.msison() == false || cr.msisrdy() == true {
break;
}
}
// Use MSIRC0 or MSIRC1 depending on requested range.
let msissel = if msirange_to_hertz(range).0 <= 24_000_000 {
Msissel::MSIRC1_24MHZ
} else {
Msissel::MSIRC0_96MHZ
};
RCC.icscr1().modify(|w| {
w.set_msissel(msissel);
w.set_msisdiv(range.into());
w.set_msirgsel(Msirgsel::RCC_ICSCR1);
});
RCC.cr().write(|w| {
// Out of reset MSIPLLxEN and MSIPLLSEL are 0
// and msison is true
w.set_msipll0en(false);
w.set_msipll1en(false);
w.set_msison(true);
});
let msis = if let (Some(freq), MsiAutoCalibration::MSIS) =
(lse_calibration_freq, config.auto_calibration.base_mode())
{
// Enable the MSIS auto-calibration feature
if msissel == Msissel::MSIRC0_96MHZ {
RCC.icscr1().modify(|w| w.set_msipll0sel(Msipllsel::LSE));
RCC.cr().modify(|w| w.set_msipll0en(true));
} else {
RCC.icscr1().modify(|w| w.set_msipll1sel(Msipllsel::LSE));
RCC.cr().modify(|w| w.set_msipll1en(true));
}
calculate_calibrated_msi_frequency(range, freq)
} else {
msirange_to_hertz(range)
};
while !RCC.cr().read().msisrdy() {}
msis
});
let mut msik = config.msik.map(|range| {
// Check MSI output per RM0456 § 11.4.10
match config.voltage_range {
VoltageScale::RANGE2 => {
assert!(msirange_to_hertz(range).0 <= 48_000_000);
}
_ => {}
}
// RM0456 § 11.8.2: spin until MSIK is off or MSIK is ready before setting its range
loop {
let cr = RCC.cr().read();
if cr.msikon() == false || cr.msikrdy() == true {
break;
}
}
RCC.icscr1().modify(|w| {
w.set_msikdiv(range.into());
w.set_msirgsel(Msirgsel::RCC_ICSCR1);
});
RCC.cr().modify(|w| {
w.set_msikon(true);
});
let msik = if let (Some(freq), MsiAutoCalibration::MSIK) =
(lse_calibration_freq, config.auto_calibration.base_mode())
{
// Enable the MSIK auto-calibration feature
// RCC.cr().modify(|w| w.set_msipllsel(Msipllsel::MSIK));
// RCC.cr().modify(|w| w.set_msipllen(true));
calculate_calibrated_msi_frequency(range, freq)
} else {
msirange_to_hertz(range)
};
while !RCC.cr().read().msikrdy() {}
msik
});
if let Some(lse_freq) = lse_calibration_freq {
// If both MSIS and MSIK are enabled, we need to check if they are using the same internal source.
if let (Some(msis_range), Some(msik_range)) = (config.msis, config.msik) {
if msis_range == msik_range {
// Clock source is shared, both will be auto calibrated, recalculate other frequency
match config.auto_calibration.base_mode() {
MsiAutoCalibration::MSIS => {
msik = Some(calculate_calibrated_msi_frequency(msik_range, lse_freq));
}
MsiAutoCalibration::MSIK => {
msis = Some(calculate_calibrated_msi_frequency(msis_range, lse_freq));
}
_ => {}
}
}
}
// Check if Fast mode should be used
if config.auto_calibration.is_fast() {
RCC.cr().modify(|w| {
// TODO clean this up to select the correct MSIPLLxFAST bit
w.set_msipll0fast(true);
// w.set_msipllfast(Msipllfast::FAST);
});
}
}
let hsi = config.hsi.then(|| {
RCC.cr().modify(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
HSI_FREQ
});
let hse = config.hse.map(|hse| {
// Check frequency limits per RM456 § 11.4.10
match config.voltage_range {
VoltageScale::RANGE1 => {
assert!(hse.freq.0 <= 50_000_000);
}
VoltageScale::RANGE2 => {
assert!(hse.freq.0 <= 48_000_000);
}
}
// Enable HSE, and wait for it to stabilize
RCC.cr().modify(|w| {
w.set_hseon(true);
w.set_hsebyp(hse.mode != HseMode::Oscillator);
w.set_hseext(match hse.mode {
HseMode::Oscillator | HseMode::Bypass => Hseext::ANALOG,
HseMode::BypassDigital => Hseext::DIGITAL,
});
});
while !RCC.cr().read().hserdy() {}
hse.freq
});
let hsi48 = config.hsi48.map(super::init_hsi48);
// let pll_input = PllInput { hse, hsi, msi: msis };
// let pll1 = init_pll(PllInstance::Pll1, config.pll1, &pll_input, config.voltage_range);
// let pll2 = init_pll(PllInstance::Pll2, config.pll2, &pll_input, config.voltage_range);
// let pll3 = init_pll(PllInstance::Pll3, config.pll3, &pll_input, config.voltage_range);
let sys_clk = match config.sys {
Sysclk::HSE => hse.unwrap(),
Sysclk::HSI16 => hsi.unwrap(),
Sysclk::MSIS => msis.unwrap(),
Sysclk::_RESERVED_3 => unreachable!(),
// Sysclk:: => pll1.r.unwrap(),
};
// Do we need the EPOD booster to reach the target clock speed per § 10.5.4?
if sys_clk >= Hertz::mhz(24) {
// Enable the booster
PWR.vosr().modify(|w| w.set_boosten(true));
while !PWR.vosr().read().boostrdy() {}
}
// The clock source is ready
// Calculate and set the flash wait states
// TODO: add wait states for low power modes
let wait_states = match config.voltage_range {
// VOS 1 range VCORE 1.26V - 1.40V
VoltageScale::RANGE1 => match sys_clk.0 {
..=32_000_000 => 0,
..=64_000_000 => 1,
..=96_000_000 => 2,
_ => 3,
},
// VOS 2 range VCORE 1.15V - 1.26V
VoltageScale::RANGE2 => match sys_clk.0 {
..=16_000_000 => 0,
..=32_000_000 => 1,
..=48_000_000 => 2,
_ => 3,
},
};
FLASH.acr().modify(|w| {
w.set_latency(wait_states);
});
// Switch the system clock source
RCC.cfgr1().modify(|w| w.set_sw(config.sys));
while RCC.cfgr1().read().sw() != config.sys {}
// Configure the bus prescalers
RCC.cfgr2().modify(|w| {
w.set_hpre(config.ahb_pre);
w.set_ppre1(config.apb1_pre);
w.set_ppre2(config.apb2_pre);
});
RCC.cfgr3().modify(|w| {
w.set_ppre3(config.apb3_pre);
});
let hclk = sys_clk / config.ahb_pre;
let hclk_max = match config.voltage_range {
VoltageScale::RANGE1 => Hertz::mhz(96),
VoltageScale::RANGE2 => Hertz::mhz(48),
};
assert!(hclk <= hclk_max);
let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk, config.apb1_pre);
let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk, config.apb2_pre);
let (pclk3, _) = super::util::calc_pclk(hclk, config.apb3_pre);
let rtc = config.ls.init();
let lse = config.ls.lse.map(|l| l.frequency);
let lsi = config.ls.lsi.then_some(LSI_FREQ);
config.mux.init();
set_clocks!(
sys: Some(sys_clk),
hclk1: Some(hclk),
hclk2: Some(hclk),
hclk3: Some(hclk),
pclk1: Some(pclk1),
pclk2: Some(pclk2),
pclk3: Some(pclk3),
pclk1_tim: Some(pclk1_tim),
pclk2_tim: Some(pclk2_tim),
msik: msik,
hsi48: hsi48,
rtc: rtc,
lse: lse,
lsi: lsi,
hse: hse,
hsi: hsi,
// TODO
audioclk: None,
shsi: None,
);
}
fn msirange_to_hertz(range: MSIRange) -> Hertz {
match range {
MSIRange::RANGE0_96MHZ => Hertz(96_000_000),
MSIRange::RANGE1_48MHZ => Hertz(48_000_000),
MSIRange::RANGE2_24MHZ => Hertz(24_000_000),
MSIRange::RANGE3_12MHZ => Hertz(12_000_000),
MSIRange::RANGE4_24MHZ => Hertz(12_000_000),
MSIRange::RANGE5_12MHZ => Hertz(12_000_000),
MSIRange::RANGE6_6MHZ => Hertz(6_000_000),
MSIRange::RANGE7_3MHZ => Hertz(3_000_000),
}
}
/// Fraction structure for MSI auto-calibration
/// Represents the multiplier as numerator/denominator that LSE frequency is multiplied by
#[derive(Debug, Clone, Copy)]
struct MsiFraction {
numerator: u32,
denominator: u32,
}
impl MsiFraction {
const fn new(numerator: u32, denominator: u32) -> Self {
Self {
numerator,
denominator,
}
}
/// Calculate the calibrated frequency given an LSE frequency
fn calculate_frequency(&self, lse_freq: Hertz) -> Hertz {
Hertz(lse_freq.0 * self.numerator / self.denominator)
}
}
fn get_msi_calibration_fraction(range: MSIRange) -> MsiFraction {
// Exploiting the MSIx internals to make calculations compact
let denominator = (range as u32 & 0x03) + 1;
// Base multipliers are deduced from Table 82: MSI oscillator characteristics in data sheet
let numerator = [1465, 122, 94, 12][range as usize >> 2];
MsiFraction::new(numerator, denominator)
}
/// Calculate the calibrated MSI frequency for a given range and LSE frequency
fn calculate_calibrated_msi_frequency(range: MSIRange, lse_freq: Hertz) -> Hertz {
let fraction = get_msi_calibration_fraction(range);
fraction.calculate_frequency(lse_freq)
}

View File

@ -78,7 +78,7 @@ fn common_init<T: Instance>() {
while !crate::pac::PWR.csr2().read().usb33rdy() {}
}
#[cfg(stm32u5)]
#[cfg(any(stm32u5, stm32u3))]
{
// Enable USB power
critical_section::with(|_| {

View File

@ -9,7 +9,8 @@ use embassy_hal_internal::PeripheralType;
use embassy_sync::waitqueue::AtomicWaker;
use embassy_usb_driver as driver;
use embassy_usb_driver::{
Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType, Event, Unsupported,
Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointInfo, EndpointType,
Event, Unsupported,
};
use crate::pac::USBRAM;
@ -208,7 +209,9 @@ mod btable {
pub(super) fn write_in_len_tx<T: Instance>(index: usize, addr: u16, len: u16) {
assert_eq!(addr & 0b11, 0);
USBRAM.mem(index * 2).write_value((addr as u32) | ((len as u32) << 16));
USBRAM
.mem(index * 2)
.write_value((addr as u32) | ((len as u32) << 16));
}
pub(super) fn write_in_len_rx<T: Instance>(index: usize, addr: u16, len: u16) {
@ -266,7 +269,9 @@ impl<T: Instance> EndpointBuffer<T> {
let val = u16::from_le_bytes(val);
#[cfg(any(usbram_32_2048, usbram_32_1024))]
let val = u32::from_le_bytes(val);
USBRAM.mem(self.addr as usize / USBRAM_ALIGN + i).write_value(val);
USBRAM
.mem(self.addr as usize / USBRAM_ALIGN + i)
.write_value(val);
}
}
}
@ -321,7 +326,9 @@ impl<'d, T: Instance> Driver<'d, T> {
});
// wait t_STARTUP = 1us
cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 / 1_000_000);
cortex_m::asm::delay(
unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 / 1_000_000,
);
#[cfg(not(usb_v4))]
regs.btable().write(|w| w.set_btable(0));
@ -647,7 +654,9 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
true => Stat::STALL,
};
let mut w = invariant(r);
w.set_stat_tx(Stat::from_bits(r.stat_tx().to_bits() ^ want_stat.to_bits()));
w.set_stat_tx(Stat::from_bits(
r.stat_tx().to_bits() ^ want_stat.to_bits(),
));
reg.write_value(w);
}
}
@ -666,7 +675,9 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
true => Stat::STALL,
};
let mut w = invariant(r);
w.set_stat_rx(Stat::from_bits(r.stat_rx().to_bits() ^ want_stat.to_bits()));
w.set_stat_rx(Stat::from_bits(
r.stat_rx().to_bits() ^ want_stat.to_bits(),
));
reg.write_value(w);
}
}
@ -1066,7 +1077,12 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
}
}
async fn data_out(&mut self, buf: &mut [u8], first: bool, last: bool) -> Result<usize, EndpointError> {
async fn data_out(
&mut self,
buf: &mut [u8],
first: bool,
last: bool,
) -> Result<usize, EndpointError> {
let regs = T::regs();
// When a SETUP is received, Stat/Stat is set to NAK.
@ -1208,8 +1224,12 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
let epr = regs.epr(0).read();
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
w.set_stat_rx(Stat::from_bits(epr.stat_rx().to_bits() ^ Stat::STALL.to_bits()));
w.set_stat_tx(Stat::from_bits(epr.stat_tx().to_bits() ^ Stat::VALID.to_bits()));
w.set_stat_rx(Stat::from_bits(
epr.stat_rx().to_bits() ^ Stat::STALL.to_bits(),
));
w.set_stat_tx(Stat::from_bits(
epr.stat_tx().to_bits() ^ Stat::VALID.to_bits(),
));
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
});
@ -1239,8 +1259,12 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
let epr = regs.epr(0).read();
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
w.set_stat_rx(Stat::from_bits(epr.stat_rx().to_bits() ^ Stat::STALL.to_bits()));
w.set_stat_tx(Stat::from_bits(epr.stat_tx().to_bits() ^ Stat::STALL.to_bits()));
w.set_stat_rx(Stat::from_bits(
epr.stat_rx().to_bits() ^ Stat::STALL.to_bits(),
));
w.set_stat_tx(Stat::from_bits(
epr.stat_tx().to_bits() ^ Stat::STALL.to_bits(),
));
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
});

View File

@ -46,6 +46,11 @@ impl<'d, T: Instance> VoltageReferenceBuffer<'d, T> {
use crate::pac::RCC;
RCC.apb3enr().modify(|w| w.set_vrefen(true));
}
#[cfg(rcc_u3)]
{
use crate::pac::RCC;
RCC.apb1enr1().modify(|w| w.set_vrefen(true));
}
#[cfg(any(rcc_h7rs, rcc_h7rm0433, rcc_h7ab, rcc_h7))]
{
use crate::pac::RCC;
@ -64,7 +69,9 @@ impl<'d, T: Instance> VoltageReferenceBuffer<'d, T> {
"Vrefbuf configured with voltage scale {} and impedance mode {}",
voltage_scale as u8, impedance_mode as u8,
);
VoltageReferenceBuffer { vrefbuf: PhantomData }
VoltageReferenceBuffer {
vrefbuf: PhantomData,
}
}
}