diff --git a/esp-hal/src/gpio/dedicated.rs b/esp-hal/src/gpio/dedicated.rs index 7f18894a86a..34479693690 100644 --- a/esp-hal/src/gpio/dedicated.rs +++ b/esp-hal/src/gpio/dedicated.rs @@ -177,7 +177,14 @@ for_each_dedicated_gpio!( impl DedicatedGpio<'_> { #[cfg(dedicated_gpio_needs_initialization)] fn initialize() { - crate::system::PeripheralClockControl::enable(crate::system::Peripheral::DedicatedGpio); + use crate::system::{Peripheral, PeripheralClockControl}; + if PeripheralClockControl::enable(Peripheral::DedicatedGpio) { + PeripheralClockControl::reset(Peripheral::DedicatedGpio); + } else { + // Refcount was more than 0. Decrement to avoid overflow because we don't handle + // dropping the driver. + PeripheralClockControl::disable(Peripheral::DedicatedGpio); + } #[cfg(esp32s2)] { diff --git a/esp-hal/src/ledc/mod.rs b/esp-hal/src/ledc/mod.rs index 7d06834b0ba..2492fe51b3a 100644 --- a/esp-hal/src/ledc/mod.rs +++ b/esp-hal/src/ledc/mod.rs @@ -123,6 +123,10 @@ impl<'d> Ledc<'d> { pub fn new(_instance: LEDC<'d>) -> Self { if PeripheralClockControl::enable(PeripheralEnable::Ledc) { PeripheralClockControl::reset(PeripheralEnable::Ledc); + } else { + // Refcount was more than 0. Decrement to avoid overflow because we don't handle + // dropping the driver. + PeripheralClockControl::disable(PeripheralEnable::Ledc); } let ledc = LEDC::regs(); diff --git a/esp-hal/src/system.rs b/esp-hal/src/system.rs index 25414af87b5..bc9cb3e5ee1 100644 --- a/esp-hal/src/system.rs +++ b/esp-hal/src/system.rs @@ -65,10 +65,7 @@ pub(crate) struct PeripheralGuard { impl PeripheralGuard { pub(crate) fn new_with(p: Peripheral, init: fn()) -> Self { - if PeripheralClockControl::enable(p) { - PeripheralClockControl::reset(p); - init(); - } + PeripheralClockControl::request_peripheral(p, init); Self { peripheral: p } } @@ -100,14 +97,8 @@ pub(crate) struct GenericPeripheralGuard {} impl GenericPeripheralGuard

{ pub(crate) fn new_with(init: fn()) -> Self { - let peripheral = const { Peripheral::try_from(P).unwrap() }; - - PERIPHERAL_REF_COUNT.with(|ref_counts| { - if PeripheralClockControl::enable_with_counts(peripheral, ref_counts) { - unsafe { PeripheralClockControl::reset_racey(peripheral) }; - init(); - } - }); + let p = const { Peripheral::try_from(P).unwrap() }; + PeripheralClockControl::request_peripheral(p, init); Self {} } @@ -139,6 +130,15 @@ impl Drop for GenericPeripheralGuard

{ pub(crate) struct PeripheralClockControl; impl PeripheralClockControl { + fn request_peripheral(p: Peripheral, init: fn()) { + PERIPHERAL_REF_COUNT.with(|ref_counts| { + if Self::enable_with_counts(p, ref_counts) { + unsafe { Self::reset_racey(p) }; + init(); + } + }); + } + /// Enables the given peripheral. /// /// This keeps track of enabling a peripheral - i.e. a peripheral @@ -165,8 +165,6 @@ impl PeripheralClockControl { /// gets disabled when the number of enable/disable attempts is balanced. /// /// Returns `true` if it actually disabled the peripheral. - /// - /// Before disabling a peripheral it will also get reset pub(crate) fn disable(peripheral: Peripheral) -> bool { PERIPHERAL_REF_COUNT.with(|ref_counts| { Self::enable_forced_with_counts(peripheral, false, false, ref_counts) @@ -200,10 +198,6 @@ impl PeripheralClockControl { assert!(*ref_count == 0); } - if !enable { - unsafe { Self::reset_racey(peripheral) }; - } - debug!("Enable {:?} {}", peripheral, enable); unsafe { enable_internal_racey(peripheral, enable) }; diff --git a/esp-hal/src/timer/systimer.rs b/esp-hal/src/timer/systimer.rs index af8c28701a0..e041be720dc 100644 --- a/esp-hal/src/timer/systimer.rs +++ b/esp-hal/src/timer/systimer.rs @@ -222,7 +222,13 @@ impl<'d> SystemTimer<'d> { /// Create a new instance. pub fn new(_systimer: SYSTIMER<'d>) -> Self { // Don't reset Systimer as it will break `time::Instant::now`, only enable it - PeripheralClockControl::enable(PeripheralEnable::Systimer); + if PeripheralClockControl::enable(PeripheralEnable::Systimer) { + PeripheralClockControl::reset(PeripheralEnable::Systimer); + } else { + // Refcount was more than 0. Decrement to avoid overflow because we don't handle + // dropping the driver. + PeripheralClockControl::disable(PeripheralEnable::Systimer); + } #[cfg(etm_driver_supported)] etm::enable_etm(); diff --git a/esp-hal/src/timer/timg.rs b/esp-hal/src/timer/timg.rs index fc1d00397ff..91409df9fba 100644 --- a/esp-hal/src/timer/timg.rs +++ b/esp-hal/src/timer/timg.rs @@ -125,13 +125,7 @@ pub trait TimerGroupInstance { fn register_block() -> *const RegisterBlock; #[cfg(soc_has_clock_node_timg_function_clock)] fn clock_instance() -> clocks::TimgInstance; - fn enable_peripheral(); - fn reset_peripheral(); - #[cfg(soc_has_clock_node_timg_wdt_clock)] - fn configure_wdt_src_clk(src: TimgWdtClockConfig); - #[cfg(soc_has_clock_node_timg_wdt_clock)] - fn gate_wdt_src_clk(enable: bool); - fn wdt_src_frequency() -> Rate; + fn peripheral() -> crate::system::Peripheral; fn wdt_interrupt() -> Interrupt; } @@ -151,41 +145,8 @@ impl TimerGroupInstance for TIMG0<'_> { clocks::TimgInstance::Timg0 } - fn enable_peripheral() { - PeripheralClockControl::enable(crate::system::Peripheral::Timg0); - } - - fn reset_peripheral() { - // FIXME: for TIMG0 do nothing for now because the reset breaks - // `time::Instant::now` - } - - #[cfg(soc_has_clock_node_timg_wdt_clock)] - fn configure_wdt_src_clk(src: TimgWdtClockConfig) { - clocks::ClockTree::with(|clocks| Self::clock_instance().configure_wdt_clock(clocks, src)); - } - - #[cfg(soc_has_clock_node_timg_wdt_clock)] - fn gate_wdt_src_clk(enable: bool) { - clocks::ClockTree::with(|clocks| { - if enable { - Self::clock_instance().request_wdt_clock(clocks) - } else { - Self::clock_instance().release_wdt_clock(clocks) - } - }); - } - - fn wdt_src_frequency() -> Rate { - clocks::ClockTree::with(|clocks| { - cfg_if::cfg_if! { - if #[cfg(soc_has_clock_node_timg_wdt_clock)] { - Rate::from_hz(Self::clock_instance().wdt_clock_frequency(clocks)) - } else { - Rate::from_hz(clocks::apb_clk_frequency(clocks)) - } - } - }) + fn peripheral() -> crate::system::Peripheral { + crate::system::Peripheral::Timg0 } fn wdt_interrupt() -> Interrupt { @@ -209,40 +170,8 @@ impl TimerGroupInstance for crate::peripherals::TIMG1<'_> { clocks::TimgInstance::Timg1 } - fn enable_peripheral() { - PeripheralClockControl::enable(crate::system::Peripheral::Timg1); - } - - fn reset_peripheral() { - PeripheralClockControl::reset(crate::system::Peripheral::Timg1); - } - - #[cfg(soc_has_clock_node_timg_wdt_clock)] - fn configure_wdt_src_clk(src: TimgWdtClockConfig) { - clocks::ClockTree::with(|clocks| Self::clock_instance().configure_wdt_clock(clocks, src)); - } - - #[cfg(soc_has_clock_node_timg_wdt_clock)] - fn gate_wdt_src_clk(enable: bool) { - clocks::ClockTree::with(|clocks| { - if enable { - Self::clock_instance().request_wdt_clock(clocks) - } else { - Self::clock_instance().release_wdt_clock(clocks) - } - }); - } - - fn wdt_src_frequency() -> Rate { - clocks::ClockTree::with(|clocks| { - cfg_if::cfg_if! { - if #[cfg(soc_has_clock_node_timg_wdt_clock)] { - Rate::from_hz(Self::clock_instance().wdt_clock_frequency(clocks)) - } else { - Rate::from_hz(clocks::apb_clk_frequency(clocks)) - } - } - }) + fn peripheral() -> crate::system::Peripheral { + crate::system::Peripheral::Timg1 } fn wdt_interrupt() -> Interrupt { @@ -256,8 +185,14 @@ where { /// Construct a new instance of [`TimerGroup`] in blocking mode pub fn new(_timer_group: T) -> Self { - T::reset_peripheral(); - T::enable_peripheral(); + // TODO: use PeripheralGuard + if PeripheralClockControl::enable(T::peripheral()) { + PeripheralClockControl::reset(T::peripheral()); + } else { + // Refcount was more than 0. Decrement to avoid overflow because we don't handle + // dropping the driver. + PeripheralClockControl::disable(T::peripheral()); + } #[cfg(soc_has_clock_node_timg_function_clock)] clocks::ClockTree::with(|clocks| { @@ -665,7 +600,9 @@ where this.set_write_protection(false); #[cfg(soc_has_clock_node_timg_wdt_clock)] - TG::configure_wdt_src_clk(TimgWdtClockConfig::default()); + clocks::ClockTree::with(|clocks| { + TG::clock_instance().configure_wdt_clock(clocks, TimgWdtClockConfig::default()) + }); this.set_write_protection(true); this @@ -699,7 +636,7 @@ where #[cfg(soc_has_clock_node_timg_wdt_clock)] if enabled { - TG::gate_wdt_src_clk(true); + clocks::ClockTree::with(|clocks| TG::clock_instance().request_wdt_clock(clocks)); } reg_block @@ -724,7 +661,7 @@ where #[cfg(soc_has_clock_node_timg_wdt_clock)] if !enabled { - TG::gate_wdt_src_clk(false); + clocks::ClockTree::with(|clocks| TG::clock_instance().release_wdt_clock(clocks)); } self.set_write_protection(true); @@ -753,7 +690,16 @@ where /// Set the timeout, in microseconds, of the watchdog timer pub fn set_timeout(&mut self, stage: MwdtStage, timeout: Duration) { - let clk_src = TG::wdt_src_frequency(); + let clk_src = clocks::ClockTree::with(|clocks| { + cfg_if::cfg_if! { + if #[cfg(soc_has_clock_node_timg_wdt_clock)] { + Rate::from_hz(TG::clock_instance().wdt_clock_frequency(clocks)) + } else { + Rate::from_hz(clocks::apb_clk_frequency(clocks)) + } + } + }); + let timeout_ticks = timeout.as_micros() * clk_src.as_mhz() as u64; let reg_block = unsafe { &*TG::register_block() }; diff --git a/esp-hal/src/usb_serial_jtag.rs b/esp-hal/src/usb_serial_jtag.rs index 2de0bcd1444..29e68ff65ff 100644 --- a/esp-hal/src/usb_serial_jtag.rs +++ b/esp-hal/src/usb_serial_jtag.rs @@ -130,7 +130,7 @@ use crate::{ asynch::AtomicWaker, pac::usb_device::RegisterBlock, peripherals::USB_DEVICE, - system::PeripheralClockControl, + system::{Peripheral, PeripheralClockControl}, }; /// Custom USB serial error type @@ -351,7 +351,13 @@ where fn new_inner(usb_device: USB_DEVICE<'d>) -> Self { // Do NOT reset the peripheral. Doing so will result in a broken USB JTAG // connection. - PeripheralClockControl::enable(crate::system::Peripheral::UsbDevice); + if PeripheralClockControl::enable(Peripheral::UsbDevice) { + PeripheralClockControl::reset(Peripheral::UsbDevice); + } else { + // Refcount was more than 0. Decrement to avoid overflow because we don't handle + // dropping the driver. + PeripheralClockControl::disable(Peripheral::UsbDevice); + } usb_device.disable_tx_interrupts(); usb_device.disable_rx_interrupts();