1#![doc = crate::before_snippet!()]
29#![doc = crate::before_snippet!()]
54use core::marker::PhantomData;
70
71use super::Error;
72#[cfg(timg1)]
73use crate::peripherals::TIMG1;
74#[cfg(any(esp32c6, esp32h2))]
75use crate::soc::constants::TIMG_DEFAULT_CLK_SRC;
76use crate::{
77 asynch::AtomicWaker,
78 clock::Clocks,
79 interrupt::{self, InterruptConfigurable, InterruptHandler},
80 pac::timg0::RegisterBlock,
81 peripheral::Peripheral,
82 peripherals::{Interrupt, TIMG0},
83 private::Sealed,
84 system::PeripheralClockControl,
85 time::{Duration, Instant, Rate},
86};
87
88const NUM_TIMG: usize = 1 + cfg!(timg1) as usize;
89
90cfg_if::cfg_if! {
91 if #[cfg(all(timg_timer1, not(any(esp32, esp32s2))))] {
95 use crate::sync::{lock, RawMutex};
96 static INT_ENA_LOCK: [RawMutex; NUM_TIMG] = [const { RawMutex::new() }; NUM_TIMG];
97 }
98}
99
100#[cfg_attr(not(timg_timer1), doc = "a general purpose timer")]
102#[cfg_attr(timg_timer1, doc = "2 timers")]
103pub struct TimerGroup<T>
105where
106 T: TimerGroupInstance,
107{
108 _timer_group: PhantomData<T>,
109 pub timer0: Timer,
111 #[cfg(timg_timer1)]
113 pub timer1: Timer,
114 pub wdt: Wdt<T>,
116}
117
118#[doc(hidden)]
119pub trait TimerGroupInstance {
120 fn id() -> u8;
121 fn register_block() -> *const RegisterBlock;
122 fn configure_src_clk();
123 fn enable_peripheral();
124 fn reset_peripheral();
125 fn configure_wdt_src_clk();
126 fn wdt_interrupt() -> Interrupt;
127}
128
129impl TimerGroupInstance for TIMG0 {
130 fn id() -> u8 {
131 0
132 }
133
134 #[inline(always)]
135 fn register_block() -> *const RegisterBlock {
136 Self::regs()
137 }
138
139 fn configure_src_clk() {
140 cfg_if::cfg_if! {
141 if #[cfg(esp32)] {
142 } else if #[cfg(any(esp32c2, esp32c3, esp32s2, esp32s3))] {
144 unsafe {
145 (*<Self as TimerGroupInstance>::register_block())
146 .t(0)
147 .config()
148 .modify(|_, w| w.use_xtal().clear_bit());
149 }
150 } else if #[cfg(any(esp32c6, esp32h2))] {
151 crate::peripherals::PCR::regs()
152 .timergroup0_timer_clk_conf()
153 .modify(|_, w| unsafe { w.tg0_timer_clk_sel().bits(TIMG_DEFAULT_CLK_SRC) });
154 }
155 }
156 }
157
158 fn enable_peripheral() {
159 PeripheralClockControl::enable(crate::system::Peripheral::Timg0);
160 }
161
162 fn reset_peripheral() {
163 }
166
167 fn configure_wdt_src_clk() {
168 cfg_if::cfg_if! {
169 if #[cfg(any(esp32, esp32s2, esp32s3))] {
170 } else if #[cfg(any(esp32c2, esp32c3))] {
172 unsafe {
173 (*<Self as TimerGroupInstance>::register_block())
174 .wdtconfig0()
175 .modify(|_, w| w.wdt_use_xtal().clear_bit());
176 }
177 } else if #[cfg(any(esp32c6, esp32h2))] {
178 crate::peripherals::PCR::regs()
179 .timergroup0_wdt_clk_conf()
180 .modify(|_, w| unsafe { w.tg0_wdt_clk_sel().bits(1) });
181 }
182 }
183 }
184
185 fn wdt_interrupt() -> Interrupt {
186 Interrupt::TG0_WDT_LEVEL
187 }
188}
189
190#[cfg(timg1)]
191impl TimerGroupInstance for crate::peripherals::TIMG1 {
192 fn id() -> u8 {
193 1
194 }
195
196 #[inline(always)]
197 fn register_block() -> *const RegisterBlock {
198 Self::regs()
199 }
200
201 fn configure_src_clk() {
202 cfg_if::cfg_if! {
203 if #[cfg(any(esp32, esp32c2, esp32c3))] {
204 } else if #[cfg(any(esp32c6, esp32h2))] {
207 crate::peripherals::PCR::regs()
208 .timergroup1_timer_clk_conf()
209 .modify(|_, w| unsafe { w.tg1_timer_clk_sel().bits(TIMG_DEFAULT_CLK_SRC) });
210 } else if #[cfg(any(esp32s2, esp32s3))] {
211 unsafe {
212 (*<Self as TimerGroupInstance>::register_block())
213 .t(1)
214 .config()
215 .modify(|_, w| w.use_xtal().clear_bit());
216 }
217 }
218 }
219 }
220
221 fn enable_peripheral() {
222 PeripheralClockControl::enable(crate::system::Peripheral::Timg1);
223 }
224
225 fn reset_peripheral() {
226 PeripheralClockControl::reset(crate::system::Peripheral::Timg1)
227 }
228
229 fn configure_wdt_src_clk() {
230 cfg_if::cfg_if! {
231 if #[cfg(any(esp32, esp32s2, esp32s3, esp32c2, esp32c3))] {
232 } else if #[cfg(any(esp32c6, esp32h2))] {
235 crate::peripherals::PCR::regs()
236 .timergroup1_wdt_clk_conf()
237 .modify(|_, w| unsafe { w.tg1_wdt_clk_sel().bits(TIMG_DEFAULT_CLK_SRC) });
238 }
239 }
240 }
241
242 fn wdt_interrupt() -> Interrupt {
243 Interrupt::TG1_WDT_LEVEL
244 }
245}
246
247impl<T> TimerGroup<T>
248where
249 T: TimerGroupInstance,
250{
251 pub fn new(_timer_group: T) -> Self {
253 T::reset_peripheral();
254 T::enable_peripheral();
255
256 T::configure_src_clk();
257
258 Self {
259 _timer_group: PhantomData,
260 timer0: Timer {
261 timer: 0,
262 tg: T::id(),
263 register_block: T::register_block(),
264 },
265 #[cfg(timg_timer1)]
266 timer1: Timer {
267 timer: 1,
268 tg: T::id(),
269 register_block: T::register_block(),
270 },
271 wdt: Wdt::new(),
272 }
273 }
274}
275
276impl super::Timer for Timer {
277 fn start(&self) {
278 self.set_counter_active(false);
279 self.set_alarm_active(false);
280
281 self.reset_counter();
282 self.set_counter_decrementing(false);
283
284 self.set_counter_active(true);
285 self.set_alarm_active(true);
286 }
287
288 fn stop(&self) {
289 self.set_counter_active(false);
290 }
291
292 fn reset(&self) {
293 self.reset_counter()
294 }
295
296 fn is_running(&self) -> bool {
297 self.is_counter_active()
298 }
299
300 fn now(&self) -> Instant {
301 self.now()
302 }
303
304 fn load_value(&self, value: Duration) -> Result<(), Error> {
305 self.load_value(value)
306 }
307
308 fn enable_auto_reload(&self, auto_reload: bool) {
309 self.set_auto_reload(auto_reload)
310 }
311
312 fn enable_interrupt(&self, state: bool) {
313 self.set_interrupt_enabled(state);
314 }
315
316 fn clear_interrupt(&self) {
317 self.clear_interrupt()
318 }
319
320 fn is_interrupt_set(&self) -> bool {
321 self.is_interrupt_set()
322 }
323
324 fn async_interrupt_handler(&self) -> InterruptHandler {
325 match (self.timer_group(), self.timer_number()) {
326 (0, 0) => asynch::timg0_timer0_handler,
327 #[cfg(timg_timer1)]
328 (0, 1) => asynch::timg0_timer1_handler,
329 #[cfg(timg1)]
330 (1, 0) => asynch::timg1_timer0_handler,
331 #[cfg(all(timg_timer1, timg1))]
332 (1, 1) => asynch::timg1_timer1_handler,
333 _ => unreachable!(),
334 }
335 }
336
337 fn peripheral_interrupt(&self) -> Interrupt {
338 match (self.timer_group(), self.timer_number()) {
339 (0, 0) => Interrupt::TG0_T0_LEVEL,
340 #[cfg(timg_timer1)]
341 (0, 1) => Interrupt::TG0_T1_LEVEL,
342 #[cfg(timg1)]
343 (1, 0) => Interrupt::TG1_T0_LEVEL,
344 #[cfg(all(timg_timer1, timg1))]
345 (1, 1) => Interrupt::TG1_T1_LEVEL,
346 _ => unreachable!(),
347 }
348 }
349
350 fn set_interrupt_handler(&self, handler: InterruptHandler) {
351 self.set_interrupt_handler(handler)
352 }
353
354 fn waker(&self) -> &AtomicWaker {
355 asynch::waker(self)
356 }
357}
358
359impl Peripheral for Timer {
360 type P = Self;
361
362 #[inline]
363 unsafe fn clone_unchecked(&self) -> Self::P {
364 core::ptr::read(self as *const _)
365 }
366}
367
368#[derive(Debug)]
370#[cfg_attr(feature = "defmt", derive(defmt::Format))]
371pub struct Timer {
372 register_block: *const RegisterBlock,
373 timer: u8,
374 tg: u8,
375}
376
377impl Sealed for Timer {}
378unsafe impl Send for Timer {}
379
380impl Timer {
382 pub(crate) fn set_interrupt_handler(&self, handler: InterruptHandler) {
383 let interrupt = match (self.timer_group(), self.timer_number()) {
384 (0, 0) => Interrupt::TG0_T0_LEVEL,
385 #[cfg(timg_timer1)]
386 (0, 1) => Interrupt::TG0_T1_LEVEL,
387 #[cfg(timg1)]
388 (1, 0) => Interrupt::TG1_T0_LEVEL,
389 #[cfg(all(timg_timer1, timg1))]
390 (1, 1) => Interrupt::TG1_T1_LEVEL,
391 _ => unreachable!(),
392 };
393
394 for core in crate::system::Cpu::other() {
395 crate::interrupt::disable(core, interrupt);
396 }
397 unsafe { interrupt::bind_interrupt(interrupt, handler.handler()) };
398 unwrap!(interrupt::enable(interrupt, handler.priority()));
399 }
400
401 fn register_block(&self) -> &RegisterBlock {
402 unsafe { &*self.register_block }
403 }
404
405 fn timer_group(&self) -> u8 {
406 self.tg
407 }
408
409 fn timer_number(&self) -> u8 {
410 self.timer
411 }
412
413 fn t(&self) -> &crate::pac::timg0::T {
414 self.register_block().t(self.timer_number().into())
415 }
416
417 fn reset_counter(&self) {
418 let t = self.t();
419
420 t.loadlo().write(|w| unsafe { w.load_lo().bits(0) });
421 t.loadhi().write(|w| unsafe { w.load_hi().bits(0) });
422
423 t.load().write(|w| unsafe { w.load().bits(1) });
424 }
425
426 fn set_counter_active(&self, state: bool) {
427 self.t().config().modify(|_, w| w.en().bit(state));
428 }
429
430 fn is_counter_active(&self) -> bool {
431 self.t().config().read().en().bit_is_set()
432 }
433
434 fn set_counter_decrementing(&self, decrementing: bool) {
435 self.t()
436 .config()
437 .modify(|_, w| w.increase().bit(!decrementing));
438 }
439
440 fn set_auto_reload(&self, auto_reload: bool) {
441 self.t()
442 .config()
443 .modify(|_, w| w.autoreload().bit(auto_reload));
444 }
445
446 fn set_alarm_active(&self, state: bool) {
447 self.t().config().modify(|_, w| w.alarm_en().bit(state));
448 }
449
450 fn load_value(&self, value: Duration) -> Result<(), Error> {
451 cfg_if::cfg_if! {
452 if #[cfg(esp32h2)] {
453 let clk_src = Clocks::get().pll_48m_clock;
455 } else {
456 let clk_src = Clocks::get().apb_clock;
457 }
458 }
459 let ticks = timeout_to_ticks(value, clk_src, self.divider());
460
461 if (ticks & !0x3F_FFFF_FFFF_FFFF) != 0 {
464 return Err(Error::InvalidTimeout);
465 }
466
467 let high = (ticks >> 32) as u32;
468 let low = (ticks & 0xFFFF_FFFF) as u32;
469
470 let t = self.t();
471
472 t.alarmlo().write(|w| unsafe { w.alarm_lo().bits(low) });
473 t.alarmhi().write(|w| unsafe { w.alarm_hi().bits(high) });
474
475 Ok(())
476 }
477
478 fn clear_interrupt(&self) {
479 self.register_block()
480 .int_clr()
481 .write(|w| w.t(self.timer).clear_bit_by_one());
482 let periodic = self.t().config().read().autoreload().bit_is_set();
483 self.set_alarm_active(periodic);
484 }
485
486 fn now(&self) -> Instant {
487 let t = self.t();
488
489 t.update().write(|w| w.update().set_bit());
490 while t.update().read().update().bit_is_set() {
491 }
493
494 let value_lo = t.lo().read().bits() as u64;
495 let value_hi = t.hi().read().bits() as u64;
496
497 let ticks = (value_hi << 32) | value_lo;
498 cfg_if::cfg_if! {
499 if #[cfg(esp32h2)] {
500 let clk_src = Clocks::get().pll_48m_clock;
502 } else {
503 let clk_src = Clocks::get().apb_clock;
504 }
505 }
506 let micros = ticks_to_timeout(ticks, clk_src, self.divider());
507
508 Instant::from_ticks(micros)
509 }
510
511 fn divider(&self) -> u32 {
512 let t = self.t();
513
514 match t.config().read().divider().bits() {
521 0 => 65536,
522 1 | 2 => 2,
523 n => n as u32,
524 }
525 }
526
527 fn is_interrupt_set(&self) -> bool {
528 self.register_block()
529 .int_raw()
530 .read()
531 .t(self.timer)
532 .bit_is_set()
533 }
534
535 fn set_interrupt_enabled(&self, state: bool) {
536 cfg_if::cfg_if! {
537 if #[cfg(any(esp32, esp32s2))] {
538 self.register_block()
542 .t(self.timer as usize)
543 .config()
544 .modify(|_, w| w.level_int_en().bit(state));
545 } else if #[cfg(timg_timer1)] {
546 lock(&INT_ENA_LOCK[self.timer_group() as usize], || {
547 self.register_block()
548 .int_ena()
549 .modify(|_, w| w.t(self.timer_number()).bit(state));
550 });
551 } else {
552 self.register_block()
553 .int_ena()
554 .modify(|_, w| w.t(0).bit(state));
555 }
556 }
557 }
558}
559
560fn ticks_to_timeout(ticks: u64, clock: Rate, divider: u32) -> u64 {
561 let period: u64 = 1_000_000 * 1_000_000 / (clock.as_hz() as u64 / divider as u64);
563
564 ticks * period / 1_000_000
565}
566
567fn timeout_to_ticks(timeout: Duration, clock: Rate, divider: u32) -> u64 {
568 let micros = timeout.as_micros();
569
570 let period: u64 = 1_000_000 * 1_000_000 / ((clock.as_hz() / divider) as u64);
572
573 (1_000_000 * micros) / period
574}
575
576#[allow(unused)]
578#[derive(Debug, Clone, Copy)]
579pub enum MwdtStageAction {
580 Off = 0,
582 Interrupt = 1,
584 ResetCpu = 2,
586 ResetSystem = 3,
588}
589
590#[derive(Debug, Clone, Copy)]
595pub enum MwdtStage {
596 Stage0,
598 Stage1,
600 Stage2,
602 Stage3,
604}
605
606pub struct Wdt<TG> {
608 phantom: PhantomData<TG>,
609}
610
611impl<TG> Wdt<TG>
613where
614 TG: TimerGroupInstance,
615{
616 pub fn new() -> Self {
618 TG::configure_wdt_src_clk();
619
620 Self {
621 phantom: PhantomData,
622 }
623 }
624
625 pub fn enable(&mut self) {
627 unsafe { self.set_wdt_enabled(true) };
630 }
631
632 pub fn disable(&mut self) {
634 unsafe { self.set_wdt_enabled(false) };
637 }
638
639 pub unsafe fn set_wdt_enabled(&mut self, enabled: bool) {
647 let reg_block = unsafe { &*TG::register_block() };
648
649 self.set_write_protection(false);
650
651 if !enabled {
652 reg_block.wdtconfig0().write(|w| unsafe { w.bits(0) });
653 } else {
654 reg_block.wdtconfig0().write(|w| w.wdt_en().bit(true));
655
656 reg_block
657 .wdtconfig0()
658 .write(|w| w.wdt_flashboot_mod_en().bit(false));
659
660 #[cfg_attr(esp32, allow(unused_unsafe))]
661 reg_block.wdtconfig0().write(|w| unsafe {
662 w.wdt_en()
663 .bit(true)
664 .wdt_stg0()
665 .bits(MwdtStageAction::ResetSystem as u8)
666 .wdt_cpu_reset_length()
667 .bits(7)
668 .wdt_sys_reset_length()
669 .bits(7)
670 .wdt_stg1()
671 .bits(MwdtStageAction::Off as u8)
672 .wdt_stg2()
673 .bits(MwdtStageAction::Off as u8)
674 .wdt_stg3()
675 .bits(MwdtStageAction::Off as u8)
676 });
677
678 #[cfg(any(esp32c2, esp32c3, esp32c6))]
679 reg_block
680 .wdtconfig0()
681 .modify(|_, w| w.wdt_conf_update_en().set_bit());
682 }
683
684 self.set_write_protection(true);
685 }
686
687 pub fn feed(&mut self) {
689 let reg_block = unsafe { &*TG::register_block() };
690
691 self.set_write_protection(false);
692
693 reg_block.wdtfeed().write(|w| unsafe { w.bits(1) });
694
695 self.set_write_protection(true);
696 }
697
698 fn set_write_protection(&mut self, enable: bool) {
699 let reg_block = unsafe { &*TG::register_block() };
700
701 let wkey = if enable { 0u32 } else { 0x50D8_3AA1u32 };
702
703 reg_block
704 .wdtwprotect()
705 .write(|w| unsafe { w.wdt_wkey().bits(wkey) });
706 }
707
708 pub fn set_timeout(&mut self, stage: MwdtStage, timeout: Duration) {
710 let timeout_raw = (timeout.as_micros() * 10_000 / 125) as u32;
711
712 let reg_block = unsafe { &*TG::register_block() };
713
714 self.set_write_protection(false);
715
716 reg_block
717 .wdtconfig1()
718 .write(|w| unsafe { w.wdt_clk_prescale().bits(1) });
719
720 unsafe {
721 match stage {
722 MwdtStage::Stage0 => reg_block
723 .wdtconfig2()
724 .write(|w| w.wdt_stg0_hold().bits(timeout_raw)),
725 MwdtStage::Stage1 => reg_block
726 .wdtconfig3()
727 .write(|w| w.wdt_stg1_hold().bits(timeout_raw)),
728 MwdtStage::Stage2 => reg_block
729 .wdtconfig4()
730 .write(|w| w.wdt_stg2_hold().bits(timeout_raw)),
731 MwdtStage::Stage3 => reg_block
732 .wdtconfig5()
733 .write(|w| w.wdt_stg3_hold().bits(timeout_raw)),
734 };
735 }
736
737 #[cfg(any(esp32c2, esp32c3, esp32c6))]
738 reg_block
739 .wdtconfig0()
740 .modify(|_, w| w.wdt_conf_update_en().set_bit());
741
742 self.set_write_protection(true);
743 }
744
745 pub fn set_stage_action(&mut self, stage: MwdtStage, action: MwdtStageAction) {
752 let reg_block = unsafe { &*TG::register_block() };
753
754 self.set_write_protection(false);
755
756 match stage {
757 MwdtStage::Stage0 => {
758 reg_block
759 .wdtconfig0()
760 .modify(|_, w| unsafe { w.wdt_stg0().bits(action as u8) });
761 }
762 MwdtStage::Stage1 => {
763 reg_block
764 .wdtconfig0()
765 .modify(|_, w| unsafe { w.wdt_stg1().bits(action as u8) });
766 }
767 MwdtStage::Stage2 => {
768 reg_block
769 .wdtconfig0()
770 .modify(|_, w| unsafe { w.wdt_stg2().bits(action as u8) });
771 }
772 MwdtStage::Stage3 => {
773 reg_block
774 .wdtconfig0()
775 .modify(|_, w| unsafe { w.wdt_stg3().bits(action as u8) });
776 }
777 }
778
779 self.set_write_protection(true);
780 }
781}
782
783impl<TG> crate::private::Sealed for Wdt<TG> where TG: TimerGroupInstance {}
784
785impl<TG> InterruptConfigurable for Wdt<TG>
786where
787 TG: TimerGroupInstance,
788{
789 fn set_interrupt_handler(&mut self, handler: interrupt::InterruptHandler) {
790 let interrupt = TG::wdt_interrupt();
791 unsafe {
792 interrupt::bind_interrupt(interrupt, handler.handler());
793 interrupt::enable(interrupt, handler.priority()).unwrap();
794 }
795 }
796}
797
798impl<TG> Default for Wdt<TG>
799where
800 TG: TimerGroupInstance,
801{
802 fn default() -> Self {
803 Self::new()
804 }
805}
806
807mod asynch {
809 use procmacros::handler;
810
811 use super::*;
812 use crate::asynch::AtomicWaker;
813
814 const NUM_WAKERS: usize = {
815 let timer_per_group = 1 + cfg!(timg_timer1) as usize;
816 NUM_TIMG * timer_per_group
817 };
818
819 static WAKERS: [AtomicWaker; NUM_WAKERS] = [const { AtomicWaker::new() }; NUM_WAKERS];
820
821 pub(super) fn waker(timer: &Timer) -> &AtomicWaker {
822 let index = (timer.timer_number() << 1) | timer.timer_group();
823 &WAKERS[index as usize]
824 }
825
826 #[inline]
827 fn handle_irq(timer: Timer) {
828 timer.set_interrupt_enabled(false);
829 waker(&timer).wake();
830 }
831
832 #[handler]
837 pub(crate) fn timg0_timer0_handler() {
838 handle_irq(Timer {
839 register_block: TIMG0::regs(),
840 timer: 0,
841 tg: 0,
842 });
843 }
844
845 #[cfg(timg1)]
846 #[handler]
847 pub(crate) fn timg1_timer0_handler() {
848 handle_irq(Timer {
849 register_block: TIMG1::regs(),
850 timer: 0,
851 tg: 1,
852 });
853 }
854
855 #[cfg(timg_timer1)]
856 #[handler]
857 pub(crate) fn timg0_timer1_handler() {
858 handle_irq(Timer {
859 register_block: TIMG0::regs(),
860 timer: 1,
861 tg: 0,
862 });
863 }
864
865 #[cfg(all(timg1, timg_timer1))]
866 #[handler]
867 pub(crate) fn timg1_timer1_handler() {
868 handle_irq(Timer {
869 register_block: TIMG1::regs(),
870 timer: 1,
871 tg: 1,
872 });
873 }
874}
875
876#[cfg(soc_etm)]
878pub mod etm {
879 use super::*;
880 use crate::etm::{EtmEvent, EtmTask};
881
882 pub struct Event {
884 id: u8,
885 }
886
887 pub struct Task {
889 id: u8,
890 }
891
892 impl EtmEvent for Event {
893 fn id(&self) -> u8 {
894 self.id
895 }
896 }
897
898 impl Sealed for Event {}
899
900 impl EtmTask for Task {
901 fn id(&self) -> u8 {
902 self.id
903 }
904 }
905
906 impl Sealed for Task {}
907
908 pub trait Events {
910 fn on_alarm(&self) -> Event;
912 }
913
914 pub trait Tasks {
916 fn cnt_start(&self) -> Task;
918
919 fn cnt_stop(&self) -> Task;
921
922 fn cnt_reload(&self) -> Task;
924
925 fn cnt_cap(&self) -> Task;
927
928 fn alarm_start(&self) -> Task;
931 }
932
933 impl Events for Timer {
934 fn on_alarm(&self) -> Event {
935 Event {
936 id: 48 + self.timer_group(),
937 }
938 }
939 }
940
941 impl Tasks for Timer {
942 fn cnt_start(&self) -> Task {
943 Task {
944 id: 88 + self.timer_group(),
945 }
946 }
947
948 fn alarm_start(&self) -> Task {
949 Task {
950 id: 90 + self.timer_group(),
951 }
952 }
953
954 fn cnt_stop(&self) -> Task {
955 Task {
956 id: 92 + self.timer_group(),
957 }
958 }
959
960 fn cnt_reload(&self) -> Task {
961 Task {
962 id: 94 + self.timer_group(),
963 }
964 }
965
966 fn cnt_cap(&self) -> Task {
967 Task {
968 id: 96 + self.timer_group(),
969 }
970 }
971 }
972}