mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-12-29 21:00:46 +00:00
Initial commit which enables STM32U3
This commit is contained in:
parent
905bdfa766
commit
93b355f89b
@ -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" ]
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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))]
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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
555
embassy-stm32/src/rcc/u3.rs
Normal 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)
|
||||
}
|
||||
@ -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(|_| {
|
||||
|
||||
@ -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
|
||||
});
|
||||
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user