Skip to main content

esp_hal/timer/
systimer.rs

1//! # System Timer (SYSTIMER)
2//!
3//! ## Overview
4//! The System Timer is a
5#![cfg_attr(esp32s2, doc = "64-bit")]
6#![cfg_attr(not(esp32s2), doc = "52-bit")]
7//! timer which can be used, for example, to generate tick interrupts for an
8//! operating system, or simply as a general-purpose timer.
9//!
10//! ## Configuration
11//!
12//! The timer consists of two counters, `Unit0` and `Unit1`. The counter values
13//! can be monitored by 3 [`Alarm`]s
14//!
15//! It is recommended to pass the [`Alarm`]s into a high level driver like
16//! [`OneShotTimer`](super::OneShotTimer) and
17//! [`PeriodicTimer`](super::PeriodicTimer). Using the System timer directly is
18//! only possible through the low level [`Timer`](crate::timer::Timer) trait.
19
20use core::{fmt::Debug, marker::PhantomData, num::NonZeroU32};
21
22use esp_sync::RawMutex;
23
24use super::{Error, Timer as _};
25use crate::{
26    asynch::AtomicWaker,
27    interrupt::{self, InterruptHandler},
28    peripherals::{Interrupt, SYSTIMER},
29    system::{Cpu, Peripheral as PeripheralEnable, PeripheralClockControl},
30    time::{Duration, Instant},
31};
32
33// System Timer is only clocked by XTAL divided by 2 or 2.5 (or RC_FAST_CLK which is not supported
34// yet). Some XTAL options (most, in fact) divided by this value may not be an integer multiple of
35// 1_000_000. Because the timer API works with microseconds, we need to correct for this. To avoid
36// u64 division as much as possible, we use the two highest bits of the divisor to determine the
37// division method.
38// - If these flags are 0b00, we divide by the divisor.
39// - If these flags are 0b01, we multiply by a constant before dividing by the divisor to improve
40//   accuracy.
41// - If these flags are 0b10, we shift the timestamp by the lower bits.
42//
43// Apart from the S2, the System Timer clock divider outputs a 16MHz timer clock when using
44// the "default" XTAL configuration, so this method will commonly use the shifting based
45// division.
46//
47// On a 26MHz C2, the divider outputs 10.4MHz. On a 32MHz C3, the divider outputs 12.8MHz.
48//
49// Time is unreliable before `init_timestamp_scaler` is called.
50//
51// Because a single crate version can have "rt" enabled, `ESP_HAL_SYSTIMER_CORRECTION` needs
52// to be shared between versions. This aspect of this driver must be therefore kept stable.
53#[unsafe(no_mangle)]
54#[cfg(feature = "rt")]
55static mut ESP_HAL_SYSTIMER_CORRECTION: NonZeroU32 = NonZeroU32::new(SHIFT_TIMESTAMP_FLAG).unwrap(); // Shift-by-0 = no-op
56
57#[cfg(not(feature = "rt"))]
58unsafe extern "Rust" {
59    static mut ESP_HAL_SYSTIMER_CORRECTION: NonZeroU32;
60}
61
62const SHIFT_TIMESTAMP_FLAG: u32 = 0x8000_0000;
63const SHIFT_MASK: u32 = 0x0000_FFFF;
64// If the tick rate is not an integer number of microseconds: Since the divider is 2.5,
65// and we assume XTAL is an integer number of MHz, we can multiply by 5, then divide by
66// 5 to improve accuracy. On H2 the divider is 2, so we can multiply by 2, then divide by
67// 2.
68const UNEVEN_DIVIDER_FLAG: u32 = 0x4000_0000;
69const UNEVEN_MULTIPLIER: u32 = if cfg!(esp32h2) { 2 } else { 5 };
70const UNEVEN_DIVIDER_MASK: u32 = 0x0000_FFFF;
71
72/// The configuration of a unit.
73#[derive(Copy, Clone)]
74pub enum UnitConfig {
75    /// Unit is not counting.
76    Disabled,
77
78    /// Unit is counting unless the Cpu is stalled.
79    DisabledIfCpuIsStalled(Cpu),
80
81    /// Unit is counting.
82    Enabled,
83}
84
85/// System Timer driver.
86pub struct SystemTimer<'d> {
87    /// Alarm 0.
88    pub alarm0: Alarm<'d>,
89
90    /// Alarm 1.
91    pub alarm1: Alarm<'d>,
92
93    /// Alarm 2.
94    pub alarm2: Alarm<'d>,
95}
96
97impl<'d> SystemTimer<'d> {
98    cfg_if::cfg_if! {
99        if #[cfg(esp32s2)] {
100            /// Bitmask to be applied to the raw register value.
101            pub const BIT_MASK: u64 = u64::MAX;
102            // Bitmask to be applied to the raw period register value.
103            const PERIOD_MASK: u64 = 0x1FFF_FFFF;
104        } else {
105            /// Bitmask to be applied to the raw register value.
106            pub const BIT_MASK: u64 = 0xF_FFFF_FFFF_FFFF;
107            // Bitmask to be applied to the raw period register value.
108            const PERIOD_MASK: u64 = 0x3FF_FFFF;
109        }
110    }
111
112    /// One-time initialization for the timestamp conversion/scaling.
113    #[cfg(feature = "rt")]
114    pub(crate) fn init_timestamp_scaler() {
115        // Maximum tick rate is 80MHz (S2), which fits in a u32, so let's narrow the type.
116        let systimer_rate = Self::ticks_per_second();
117
118        // Select the optimal way to divide timestamps.
119        let packed_rate_and_method = if systimer_rate.is_multiple_of(1_000_000) {
120            let ticks_per_us = systimer_rate as u32 / 1_000_000;
121            if ticks_per_us.is_power_of_two() {
122                // Turn the division into a shift
123                SHIFT_TIMESTAMP_FLAG | (ticks_per_us.ilog2() & SHIFT_MASK)
124            } else {
125                // We need to divide by an integer :(
126                ticks_per_us
127            }
128        } else {
129            // The rate is not a multiple of 1 MHz, we need to scale it up to prevent precision
130            // loss.
131            let multiplied_ticks_per_us = (systimer_rate * UNEVEN_MULTIPLIER as u64) / 1_000_000;
132            UNEVEN_DIVIDER_FLAG | (multiplied_ticks_per_us as u32)
133        };
134
135        // Safety: we only ever write ESP_HAL_SYSTIMER_CORRECTION in `init_timestamp_scaler`, which
136        // is called once and only once during startup, from `time_init`.
137        unsafe {
138            let correction_ptr = &raw mut ESP_HAL_SYSTIMER_CORRECTION;
139            *correction_ptr = unwrap!(NonZeroU32::new(packed_rate_and_method));
140        }
141    }
142
143    #[inline]
144    pub(crate) fn ticks_to_us(ticks: u64) -> u64 {
145        // Safety: we only ever write ESP_HAL_SYSTIMER_CORRECTION in `init_timestamp_scaler`, which
146        // is called once and only once during startup.
147        let correction = unsafe { ESP_HAL_SYSTIMER_CORRECTION };
148
149        let correction = correction.get();
150        match correction & (SHIFT_TIMESTAMP_FLAG | UNEVEN_DIVIDER_FLAG) {
151            v if v == SHIFT_TIMESTAMP_FLAG => ticks >> (correction & SHIFT_MASK),
152            v if v == UNEVEN_DIVIDER_FLAG => {
153                // Not only that, but we need to multiply the timestamp first otherwise
154                // we'd count slower than the timer.
155                let multiplied = if UNEVEN_MULTIPLIER.is_power_of_two() {
156                    ticks << UNEVEN_MULTIPLIER.ilog2()
157                } else {
158                    ticks * UNEVEN_MULTIPLIER as u64
159                };
160
161                let divider = correction & UNEVEN_DIVIDER_MASK;
162                multiplied / divider as u64
163            }
164            _ => ticks / correction as u64,
165        }
166    }
167
168    #[inline]
169    fn us_to_ticks(us: u64) -> u64 {
170        // Safety: we only ever write ESP_HAL_SYSTIMER_CORRECTION in `init_timestamp_scaler`, which
171        // is called once and only once during startup.
172        let correction = unsafe { ESP_HAL_SYSTIMER_CORRECTION };
173
174        let correction = correction.get();
175        match correction & (SHIFT_TIMESTAMP_FLAG | UNEVEN_DIVIDER_FLAG) {
176            v if v == SHIFT_TIMESTAMP_FLAG => us << (correction & SHIFT_MASK),
177            v if v == UNEVEN_DIVIDER_FLAG => {
178                let multiplier = correction & UNEVEN_DIVIDER_MASK;
179                let multiplied = us * multiplier as u64;
180
181                // Not only that, but we need to divide the timestamp first otherwise
182                // we'd return a slightly too-big value.
183                if UNEVEN_MULTIPLIER.is_power_of_two() {
184                    multiplied >> UNEVEN_MULTIPLIER.ilog2()
185                } else {
186                    multiplied / UNEVEN_MULTIPLIER as u64
187                }
188            }
189            _ => us * correction as u64,
190        }
191    }
192
193    /// Returns the tick frequency of the underlying timer unit.
194    #[inline]
195    pub fn ticks_per_second() -> u64 {
196        // FIXME: this requires a critical section. We can probably do better, if we can formulate
197        // invariants well.
198        cfg_if::cfg_if! {
199            if #[cfg(esp32c5)] {
200                // Assuming SYSTIMER runs from XTAL, the hardware always runs at 16 MHz.
201                16_000_000
202            } else {
203                crate::soc::clocks::ClockTree::with(|clocks| {
204                    cfg_if::cfg_if! {
205                        if #[cfg(esp32s2)] {
206                            crate::soc::clocks::apb_clk_frequency(clocks) as u64
207                        } else if #[cfg(esp32h2)] {
208                            // The counters and comparators are driven using `XTAL_CLK`.
209                            // The average clock frequency is fXTAL_CLK/2, (16 MHz for XTAL = 32 MHz)
210                            (crate::soc::clocks::xtal_clk_frequency(clocks) / 2) as u64
211                        } else {
212                            // The counters and comparators are driven using `XTAL_CLK`.
213                            // The average clock frequency is fXTAL_CLK/2.5 (16 MHz for XTAL = 40 MHz)
214                            (crate::soc::clocks::xtal_clk_frequency(clocks) * 10 / 25) as u64
215                        }
216                    }
217                })
218            }
219        }
220    }
221
222    /// Create a new instance.
223    pub fn new(_systimer: SYSTIMER<'d>) -> Self {
224        // Don't reset Systimer as it will break `time::Instant::now`, only enable it
225        if PeripheralClockControl::enable(PeripheralEnable::Systimer) {
226            PeripheralClockControl::reset(PeripheralEnable::Systimer);
227        } else {
228            // Refcount was more than 0. Decrement to avoid overflow because we don't handle
229            // dropping the driver.
230            PeripheralClockControl::disable(PeripheralEnable::Systimer);
231        }
232
233        #[cfg(etm_driver_supported)]
234        etm::enable_etm();
235
236        Self {
237            alarm0: Alarm::new(Comparator::Comparator0),
238            alarm1: Alarm::new(Comparator::Comparator1),
239            alarm2: Alarm::new(Comparator::Comparator2),
240        }
241    }
242
243    /// Get the current count of the given unit in the System Timer.
244    #[inline]
245    pub fn unit_value(unit: Unit) -> u64 {
246        // This should be safe to access from multiple contexts
247        // worst case scenario the second accessor ends up reading
248        // an older time stamp
249
250        unit.read_count()
251    }
252
253    #[cfg(not(esp32s2))]
254    /// Configures when this counter can run.
255    /// It can be configured to stall or continue running when CPU stalls
256    /// or enters on-chip-debugging mode.
257    ///
258    /// # Safety
259    ///
260    /// - Disabling a `Unit` whilst [`Alarm`]s are using it will affect the [`Alarm`]s operation.
261    /// - Disabling Unit0 will affect [`Instant::now`].
262    pub unsafe fn configure_unit(unit: Unit, config: UnitConfig) {
263        unit.configure(config)
264    }
265
266    /// Set the value of the counter immediately. If the unit is at work,
267    /// the counter will continue to count up from the new reloaded value.
268    ///
269    /// This can be used to load back the sleep time recorded by RTC timer
270    /// via software after Light-sleep
271    ///
272    /// # Safety
273    ///
274    /// - Modifying a unit's count whilst [`Alarm`]s are using it may cause unexpected behaviour
275    /// - Any modification of the unit0 count will affect [`Instant::now`]
276    pub unsafe fn set_unit_value(unit: Unit, value: u64) {
277        unit.set_count(value)
278    }
279}
280
281/// A
282#[cfg_attr(esp32s2, doc = "64-bit")]
283#[cfg_attr(not(esp32s2), doc = "52-bit")]
284/// counter.
285#[derive(Copy, Clone, Debug, PartialEq, Eq)]
286#[cfg_attr(feature = "defmt", derive(defmt::Format))]
287pub enum Unit {
288    /// Unit 0
289    Unit0 = 0,
290    #[cfg(not(esp32s2))]
291    /// Unit 1
292    Unit1 = 1,
293}
294
295impl Unit {
296    #[inline]
297    fn channel(&self) -> u8 {
298        *self as _
299    }
300
301    #[cfg(not(esp32s2))]
302    fn configure(&self, config: UnitConfig) {
303        CONF_LOCK.lock(|| {
304            SYSTIMER::regs().conf().modify(|_, w| match config {
305                UnitConfig::Disabled => match self.channel() {
306                    0 => w.timer_unit0_work_en().clear_bit(),
307                    1 => w.timer_unit1_work_en().clear_bit(),
308                    _ => unreachable!(),
309                },
310                UnitConfig::DisabledIfCpuIsStalled(cpu) => match self.channel() {
311                    0 => {
312                        w.timer_unit0_work_en().set_bit();
313                        w.timer_unit0_core0_stall_en().bit(cpu == Cpu::ProCpu);
314                        w.timer_unit0_core1_stall_en().bit(cpu != Cpu::ProCpu)
315                    }
316                    1 => {
317                        w.timer_unit1_work_en().set_bit();
318                        w.timer_unit1_core0_stall_en().bit(cpu == Cpu::ProCpu);
319                        w.timer_unit1_core1_stall_en().bit(cpu != Cpu::ProCpu)
320                    }
321                    _ => unreachable!(),
322                },
323                UnitConfig::Enabled => match self.channel() {
324                    0 => {
325                        w.timer_unit0_work_en().set_bit();
326                        w.timer_unit0_core0_stall_en().clear_bit();
327                        w.timer_unit0_core1_stall_en().clear_bit()
328                    }
329                    1 => {
330                        w.timer_unit1_work_en().set_bit();
331                        w.timer_unit1_core0_stall_en().clear_bit();
332                        w.timer_unit1_core1_stall_en().clear_bit()
333                    }
334                    _ => unreachable!(),
335                },
336            });
337        });
338    }
339
340    fn set_count(&self, value: u64) {
341        let systimer = SYSTIMER::regs();
342        #[cfg(not(esp32s2))]
343        {
344            let unitload = systimer.unitload(self.channel() as _);
345            let unit_load = systimer.unit_load(self.channel() as _);
346
347            unitload.hi().write(|w| w.load_hi().set((value << 32) as _));
348            unitload
349                .lo()
350                .write(|w| w.load_lo().set((value & 0xFFFF_FFFF) as _));
351
352            unit_load.write(|w| w.load().set_bit());
353        }
354        #[cfg(esp32s2)]
355        {
356            systimer
357                .load_hi()
358                .write(|w| w.load_hi().set((value << 32) as _));
359            systimer
360                .load_lo()
361                .write(|w| w.load_lo().set((value & 0xFFFF_FFFF) as _));
362
363            systimer.load().write(|w| w.load().set_bit());
364        }
365    }
366
367    #[inline]
368    fn read_count(&self) -> u64 {
369        // This can be a shared reference as long as this type isn't Sync.
370
371        let channel = self.channel() as usize;
372        let systimer = SYSTIMER::regs();
373
374        systimer.unit_op(channel).write(|w| w.update().set_bit());
375        while !systimer.unit_op(channel).read().value_valid().bit_is_set() {}
376
377        // Read LO, HI, then LO again, check that LO returns the same value.
378        // This accounts for the case when an interrupt may happen between reading
379        // HI and LO values (or the other core updates the counter mid-read), and this
380        // function may get called from the ISR. In this case, the repeated read
381        // will return consistent values.
382        let unit_value = systimer.unit_value(channel);
383        let mut lo_prev = unit_value.lo().read().bits();
384        loop {
385            let lo = lo_prev;
386            let hi = unit_value.hi().read().bits();
387            lo_prev = unit_value.lo().read().bits();
388
389            if lo == lo_prev {
390                return ((hi as u64) << 32) | lo as u64;
391            }
392        }
393    }
394}
395
396#[derive(Debug, Clone, Copy, PartialEq, Eq)]
397#[cfg_attr(feature = "defmt", derive(defmt::Format))]
398enum Comparator {
399    Comparator0,
400    Comparator1,
401    Comparator2,
402}
403
404/// An alarm unit
405#[derive(Debug)]
406#[cfg_attr(feature = "defmt", derive(defmt::Format))]
407pub struct Alarm<'d> {
408    comp: Comparator,
409    unit: Unit,
410    _lifetime: PhantomData<&'d mut ()>,
411}
412
413impl Alarm<'_> {
414    const fn new(comp: Comparator) -> Self {
415        Alarm {
416            comp,
417            unit: Unit::Unit0,
418            _lifetime: PhantomData,
419        }
420    }
421
422    /// Unsafely clone this peripheral reference.
423    ///
424    /// # Safety
425    ///
426    /// You must ensure that you're only using one instance of this type at a
427    /// time.
428    pub unsafe fn clone_unchecked(&self) -> Self {
429        Self {
430            comp: self.comp,
431            unit: self.unit,
432            _lifetime: PhantomData,
433        }
434    }
435
436    /// Creates a new peripheral reference with a shorter lifetime.
437    ///
438    /// Use this method if you would like to keep working with the peripheral
439    /// after you dropped the driver that consumes this.
440    ///
441    /// See [Peripheral singleton] section for more information.
442    ///
443    /// [Peripheral singleton]: crate#peripheral-singletons
444    pub fn reborrow(&mut self) -> Alarm<'_> {
445        unsafe { self.clone_unchecked() }
446    }
447
448    /// Returns the comparator's number.
449    #[inline]
450    fn channel(&self) -> u8 {
451        self.comp as u8
452    }
453
454    /// Enables/disables the comparator. If enabled, this means
455    /// it will generate interrupt based on its configuration.
456    fn set_enable(&self, enable: bool) {
457        CONF_LOCK.lock(|| {
458            #[cfg(not(esp32s2))]
459            SYSTIMER::regs().conf().modify(|_, w| match self.channel() {
460                0 => w.target0_work_en().bit(enable),
461                1 => w.target1_work_en().bit(enable),
462                2 => w.target2_work_en().bit(enable),
463                _ => unreachable!(),
464            });
465        });
466
467        // Note: The ESP32-S2 doesn't require a lock because each
468        // comparator's enable bit in a different register.
469        #[cfg(esp32s2)]
470        SYSTIMER::regs()
471            .target_conf(self.channel() as usize)
472            .modify(|_r, w| w.work_en().bit(enable));
473    }
474
475    /// Returns true if the comparator has been enabled. This means
476    /// it will generate interrupt based on its configuration.
477    fn is_enabled(&self) -> bool {
478        #[cfg(not(esp32s2))]
479        match self.channel() {
480            0 => SYSTIMER::regs().conf().read().target0_work_en().bit(),
481            1 => SYSTIMER::regs().conf().read().target1_work_en().bit(),
482            2 => SYSTIMER::regs().conf().read().target2_work_en().bit(),
483            _ => unreachable!(),
484        }
485
486        #[cfg(esp32s2)]
487        SYSTIMER::regs()
488            .target_conf(self.channel() as usize)
489            .read()
490            .work_en()
491            .bit()
492    }
493
494    /// Sets the unit this comparator uses as a reference count.
495    #[cfg(not(esp32s2))]
496    pub fn set_unit(&self, unit: Unit) {
497        SYSTIMER::regs()
498            .target_conf(self.channel() as usize)
499            .modify(|_, w| w.timer_unit_sel().bit(matches!(unit, Unit::Unit1)));
500    }
501
502    /// Set the mode of the comparator to be either target or periodic.
503    fn set_mode(&self, mode: ComparatorMode) {
504        let is_period_mode = match mode {
505            ComparatorMode::Period => true,
506            ComparatorMode::Target => false,
507        };
508        SYSTIMER::regs()
509            .target_conf(self.channel() as usize)
510            .modify(|_, w| w.period_mode().bit(is_period_mode));
511    }
512
513    /// Get the current mode of the comparator, which is either target or
514    /// periodic.
515    fn mode(&self) -> ComparatorMode {
516        if SYSTIMER::regs()
517            .target_conf(self.channel() as usize)
518            .read()
519            .period_mode()
520            .bit()
521        {
522            ComparatorMode::Period
523        } else {
524            ComparatorMode::Target
525        }
526    }
527
528    /// Set how often the comparator should generate an interrupt when in
529    /// periodic mode.
530    fn set_period(&self, value: u32) {
531        let systimer = SYSTIMER::regs();
532        let tconf = systimer.target_conf(self.channel() as usize);
533        unsafe { tconf.modify(|_, w| w.period().bits(value)) };
534        #[cfg(not(esp32s2))]
535        {
536            let comp_load = systimer.comp_load(self.channel() as usize);
537            comp_load.write(|w| w.load().set_bit());
538        }
539    }
540
541    /// Set when the comparator should generate an interrupt in target mode.
542    fn set_target(&self, value: u64) {
543        let systimer = SYSTIMER::regs();
544        let target = systimer.trgt(self.channel() as usize);
545        target.hi().write(|w| w.hi().set((value >> 32) as u32));
546        target
547            .lo()
548            .write(|w| w.lo().set((value & 0xFFFF_FFFF) as u32));
549        #[cfg(not(esp32s2))]
550        {
551            let comp_load = systimer.comp_load(self.channel() as usize);
552            comp_load.write(|w| w.load().set_bit());
553        }
554    }
555
556    /// Set the interrupt handler for this comparator.
557    fn set_interrupt_handler(&self, handler: InterruptHandler) {
558        let interrupt = match self.channel() {
559            0 => Interrupt::SYSTIMER_TARGET0,
560            1 => Interrupt::SYSTIMER_TARGET1,
561            2 => Interrupt::SYSTIMER_TARGET2,
562            _ => unreachable!(),
563        };
564
565        for core in crate::system::Cpu::other() {
566            crate::interrupt::disable(core, interrupt);
567        }
568
569        #[cfg(not(esp32s2))]
570        interrupt::bind_handler(interrupt, handler);
571
572        #[cfg(esp32s2)]
573        {
574            // ESP32-S2 Systimer interrupts are edge triggered. Our interrupt
575            // handler calls each of the handlers, regardless of which one triggered the
576            // interrupt. This mess registers an intermediate handler that
577            // checks if an interrupt is active before calling the associated
578            // handler functions.
579
580            static mut HANDLERS: [Option<crate::interrupt::IsrCallback>; 3] = [None, None, None];
581
582            #[crate::ram]
583            extern "C" fn _handle_interrupt<const CH: u8>() {
584                if SYSTIMER::regs().int_raw().read().target(CH).bit_is_set() {
585                    let handler = unsafe { HANDLERS[CH as usize] };
586                    if let Some(handler) = handler {
587                        (handler.callback())();
588                    }
589                }
590            }
591
592            let priority = handler.priority();
593            unsafe {
594                HANDLERS[self.channel() as usize] = Some(handler.handler());
595            }
596            let handler = match self.channel() {
597                0 => _handle_interrupt::<0>,
598                1 => _handle_interrupt::<1>,
599                2 => _handle_interrupt::<2>,
600                _ => unreachable!(),
601            };
602            interrupt::bind_handler(
603                interrupt,
604                crate::interrupt::InterruptHandler::new(handler, priority),
605            );
606        }
607    }
608}
609
610/// The modes of a comparator.
611#[derive(Copy, Clone)]
612enum ComparatorMode {
613    /// The comparator will generate interrupts periodically.
614    Period,
615
616    /// The comparator will generate an interrupt when the unit reaches the
617    /// target.
618    Target,
619}
620
621impl super::Timer for Alarm<'_> {
622    fn start(&self) {
623        self.set_enable(true);
624    }
625
626    fn stop(&self) {
627        self.set_enable(false);
628    }
629
630    fn reset(&self) {
631        #[cfg(esp32s2)]
632        // Run at XTAL freq, not 80 * XTAL freq:
633        SYSTIMER::regs()
634            .step()
635            .modify(|_, w| unsafe { w.xtal_step().bits(0x1) });
636
637        #[cfg(not(esp32s2))]
638        SYSTIMER::regs()
639            .conf()
640            .modify(|_, w| w.timer_unit0_core0_stall_en().clear_bit());
641    }
642
643    fn is_running(&self) -> bool {
644        self.is_enabled()
645    }
646
647    fn now(&self) -> Instant {
648        // This should be safe to access from multiple contexts; worst case
649        // scenario the second accessor ends up reading an older time stamp.
650
651        let ticks = self.unit.read_count();
652
653        let us = SystemTimer::ticks_to_us(ticks);
654
655        Instant::from_ticks(us)
656    }
657
658    fn load_value(&self, value: Duration) -> Result<(), Error> {
659        let mode = self.mode();
660
661        let us = value.as_micros();
662        let ticks = SystemTimer::us_to_ticks(us);
663
664        if matches!(mode, ComparatorMode::Period) {
665            // Period mode
666
667            // The `SYSTIMER_TARGETx_PERIOD` field is 26-bits wide (or
668            // 29-bits on the ESP32-S2), so we must ensure that the provided
669            // value is not too wide:
670            if (ticks & !SystemTimer::PERIOD_MASK) != 0 {
671                return Err(Error::InvalidTimeout);
672            }
673
674            self.set_period(ticks as u32);
675
676            // Clear and then set SYSTIMER_TARGETx_PERIOD_MODE to configure COMPx into
677            // period mode
678            self.set_mode(ComparatorMode::Target);
679            self.set_mode(ComparatorMode::Period);
680        } else {
681            // Target mode
682
683            // The counters/comparators are 52-bits wide (except on ESP32-S2,
684            // which is 64-bits), so we must ensure that the provided value
685            // is not too wide:
686            #[cfg(not(esp32s2))]
687            if (ticks & !SystemTimer::BIT_MASK) != 0 {
688                return Err(Error::InvalidTimeout);
689            }
690
691            let v = self.unit.read_count();
692            let t = v + ticks;
693
694            self.set_target(t);
695        }
696
697        Ok(())
698    }
699
700    fn enable_auto_reload(&self, auto_reload: bool) {
701        // If `auto_reload` is true use Period Mode, otherwise use Target Mode:
702        let mode = if auto_reload {
703            ComparatorMode::Period
704        } else {
705            ComparatorMode::Target
706        };
707        self.set_mode(mode)
708    }
709
710    fn enable_interrupt(&self, state: bool) {
711        INT_ENA_LOCK.lock(|| {
712            SYSTIMER::regs()
713                .int_ena()
714                .modify(|_, w| w.target(self.channel()).bit(state));
715        });
716    }
717
718    fn clear_interrupt(&self) {
719        SYSTIMER::regs()
720            .int_clr()
721            .write(|w| w.target(self.channel()).clear_bit_by_one());
722    }
723
724    fn is_interrupt_set(&self) -> bool {
725        SYSTIMER::regs()
726            .int_raw()
727            .read()
728            .target(self.channel())
729            .bit_is_set()
730    }
731
732    fn async_interrupt_handler(&self) -> InterruptHandler {
733        match self.channel() {
734            0 => asynch::target0_handler,
735            1 => asynch::target1_handler,
736            2 => asynch::target2_handler,
737            _ => unreachable!(),
738        }
739    }
740
741    fn peripheral_interrupt(&self) -> Interrupt {
742        match self.channel() {
743            0 => Interrupt::SYSTIMER_TARGET0,
744            1 => Interrupt::SYSTIMER_TARGET1,
745            2 => Interrupt::SYSTIMER_TARGET2,
746            _ => unreachable!(),
747        }
748    }
749
750    fn set_interrupt_handler(&self, handler: InterruptHandler) {
751        self.set_interrupt_handler(handler)
752    }
753
754    fn waker(&self) -> &AtomicWaker {
755        asynch::waker(self)
756    }
757}
758
759impl crate::private::Sealed for Alarm<'_> {}
760
761static CONF_LOCK: RawMutex = RawMutex::new();
762static INT_ENA_LOCK: RawMutex = RawMutex::new();
763
764// Async functionality of the system timer.
765mod asynch {
766    use core::marker::PhantomData;
767
768    use procmacros::handler;
769
770    use super::*;
771    use crate::asynch::AtomicWaker;
772
773    const NUM_ALARMS: usize = 3;
774    static WAKERS: [AtomicWaker; NUM_ALARMS] = [const { AtomicWaker::new() }; NUM_ALARMS];
775
776    pub(super) fn waker(alarm: &Alarm<'_>) -> &'static AtomicWaker {
777        &WAKERS[alarm.channel() as usize]
778    }
779
780    #[inline]
781    fn handle_alarm(comp: Comparator) {
782        Alarm {
783            comp,
784            unit: Unit::Unit0,
785            _lifetime: PhantomData,
786        }
787        .enable_interrupt(false);
788
789        WAKERS[comp as usize].wake();
790    }
791
792    #[handler]
793    pub(crate) fn target0_handler() {
794        handle_alarm(Comparator::Comparator0);
795    }
796
797    #[handler]
798    pub(crate) fn target1_handler() {
799        handle_alarm(Comparator::Comparator1);
800    }
801
802    #[handler]
803    pub(crate) fn target2_handler() {
804        handle_alarm(Comparator::Comparator2);
805    }
806}
807
808#[cfg(etm_driver_supported)]
809pub mod etm {
810    #![cfg_attr(docsrs, procmacros::doc_replace)]
811    //! # Event Task Matrix Function
812    //!
813    //! ## Overview
814    //!
815    //! The system timer supports the Event Task Matrix (ETM) function, which
816    //! allows the system timer’s ETM events to trigger any peripherals’ ETM
817    //! tasks.
818    //!
819    //! The system timer can generate the following ETM events:
820    //! - SYSTIMER_EVT_CNT_CMPx: Indicates the alarm pulses generated by COMPx
821    //! ## Example
822    //! ```rust, no_run
823    //! # {before_snippet}
824    //! # use esp_hal::timer::systimer::{etm::Event, SystemTimer};
825    //! # use esp_hal::timer::PeriodicTimer;
826    //! # use esp_hal::etm::Etm;
827    //! # use esp_hal::gpio::{
828    //! #     etm::{Channels, OutputConfig},
829    //! #     Level,
830    //! #     Pull,
831    //! # };
832    //! let syst = SystemTimer::new(peripherals.SYSTIMER);
833    //! let etm = Etm::new(peripherals.ETM);
834    //! let gpio_ext = Channels::new(peripherals.GPIO_SD);
835    //! let alarm0 = syst.alarm0;
836    //! let mut led = peripherals.GPIO1;
837    //!
838    //! let timer_event = Event::new(&alarm0);
839    //! let led_task = gpio_ext.channel0_task.toggle(
840    //!     led,
841    //!     OutputConfig {
842    //!         open_drain: false,
843    //!         pull: Pull::None,
844    //!         initial_state: Level::High,
845    //!     },
846    //! );
847    //!
848    //! let _configured_etm_channel = etm.channel0.setup(&timer_event, &led_task);
849    //!
850    //! let timer = PeriodicTimer::new(alarm0);
851    //! // configure the timer as usual
852    //! // when it fires it will toggle the GPIO
853    //! # {after_snippet}
854    //! ```
855
856    use super::*;
857
858    /// An ETM controlled SYSTIMER event
859    pub struct Event {
860        id: u8,
861    }
862
863    impl Event {
864        /// Creates an ETM event from the given [Alarm]
865        pub fn new(alarm: &Alarm<'_>) -> Self {
866            Self {
867                id: 50 + alarm.channel(),
868            }
869        }
870    }
871
872    impl crate::private::Sealed for Event {}
873
874    impl crate::etm::EtmEvent for Event {
875        fn id(&self) -> u8 {
876            self.id
877        }
878    }
879
880    pub(super) fn enable_etm() {
881        SYSTIMER::regs().conf().modify(|_, w| w.etm_en().set_bit());
882    }
883}