From eeb6ffce4cfa0e0055da8d6738f6d28c3fa43f15 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 20 May 2024 23:36:21 +0200 Subject: [PATCH] stm32/rcc: add ClockEnableBit struct. --- embassy-stm32/build.rs | 32 +++++++++++++++++++++++ embassy-stm32/src/rcc/mod.rs | 50 +++++++++++++++++++++++++++++++++++- 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index dbc8f9153..f17c6bef6 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -7,6 +7,7 @@ use std::{env, fs}; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; +use stm32_metapac::metadata::ir::BitOffset; use stm32_metapac::metadata::{ MemoryRegionKind, PeripheralRccKernelClock, PeripheralRccRegister, PeripheralRegisters, StopMode, METADATA, }; @@ -359,12 +360,17 @@ fn main() { // ======== // Extract the rcc registers + let rcc_registers = METADATA .peripherals .iter() .filter_map(|p| p.registers.as_ref()) .find(|r| r.kind == "rcc") .unwrap(); + for b in rcc_registers.ir.blocks { + eprintln!("{}", b.name); + } + let rcc_block = rcc_registers.ir.blocks.iter().find(|b| b.name == "Rcc").unwrap(); // ======== // Generate RccPeripheral impls @@ -540,6 +546,29 @@ fn main() { let pname = format_ident!("{}", p.name); let en_reg = format_ident!("{}", en.register.to_ascii_lowercase()); let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase()); + let en_reg_offs = rcc_block + .items + .iter() + .find(|i| i.name.eq_ignore_ascii_case(en.register)) + .unwrap() + .byte_offset; + let en_reg_offs: u8 = (en_reg_offs / 4).try_into().unwrap(); + + let en_bit_offs = &rcc_registers + .ir + .fieldsets + .iter() + .find(|i| i.name.eq_ignore_ascii_case(en.register)) + .unwrap() + .fields + .iter() + .find(|i| i.name.eq_ignore_ascii_case(en.field)) + .unwrap() + .bit_offset; + let BitOffset::Regular(en_bit_offs) = en_bit_offs else { + panic!("cursed bit offset") + }; + let en_bit_offs: u8 = en_bit_offs.offset.try_into().unwrap(); let refcount = clock_gen.force_refcount.contains(ptype) || *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1; @@ -624,6 +653,9 @@ fn main() { crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false)); #decr_stop_refcount } + fn enable_bit() -> crate::rcc::ClockEnableBit { + unsafe { crate::rcc::ClockEnableBit::new(#en_reg_offs, #en_bit_offs) } + } } impl crate::rcc::RccPeripheral for peripherals::#pname {} diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index a585940bc..c413b62ef 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -31,6 +31,7 @@ pub use hsi48::*; mod _version; pub use _version::*; +use stm32_metapac::RCC; pub use crate::_generated::{mux, Clocks}; use crate::time::Hertz; @@ -66,9 +67,10 @@ pub(crate) unsafe fn get_freqs() -> &'static Clocks { } pub(crate) trait SealedRccPeripheral { - fn frequency() -> crate::time::Hertz; + fn frequency() -> Hertz; fn enable_and_reset_with_cs(cs: CriticalSection); fn disable_with_cs(cs: CriticalSection); + fn enable_bit() -> ClockEnableBit; fn enable_and_reset() { critical_section::with(|cs| Self::enable_and_reset_with_cs(cs)) @@ -137,3 +139,49 @@ pub unsafe fn enable_and_reset() { pub unsafe fn disable() { T::disable(); } + +/// Struct representing some clock enable bit (xxxENR.xxEN), only known at runtime. +#[derive(Clone, Copy)] +pub(crate) struct ClockEnableBit { + /// offset in 32bit words of the xxxENR register into the RCC register block. + offset: u8, + /// bit within the register (0..=31) + bit: u8, +} + +impl ClockEnableBit { + /// Safety: offset+bit must correspond to a valid xxxEN bit. + pub(crate) unsafe fn new(offset: u8, bit: u8) -> Self { + Self { offset, bit } + } + + fn ptr(self) -> *mut u32 { + unsafe { (RCC.as_ptr() as *mut u32).add(self.offset as _) } + } + + #[allow(unused)] + pub(crate) fn enable_with_cs(self, _cs: CriticalSection) { + let p = self.ptr(); + unsafe { + let val = p.read_volatile(); + p.write_volatile(val | 1u32 << self.bit); + } + } + + pub(crate) fn disable_with_cs(self, _cs: CriticalSection) { + let p = self.ptr(); + unsafe { + let val = p.read_volatile(); + p.write_volatile(val & !(1u32 << self.bit)); + } + } + + #[allow(unused)] + pub(crate) fn enable(self) { + critical_section::with(|cs| self.enable_with_cs(cs)) + } + + pub(crate) fn disable(self) { + critical_section::with(|cs| self.disable_with_cs(cs)) + } +}