1use core::marker::PhantomData;
9
10use embassy_hal_internal::{Peri, PeripheralType};
11
12use crate::{
13 event_link::InterruptEvent,
14 module_stop::ModuleStop,
15 pac::gpt::{
16 regs::{Gtdnsr, Gtupsr},
17 vals::{Ccr, Mode, Tpcs, Ud},
18 },
19};
20
21#[allow(private_bounds)]
23pub trait Instance<Width: TimerWidth>: SealedInstance + ModuleStop + PeripheralType {
24 const COMP_A_EVENT: crate::event_link::InterruptEvent;
26
27 const COMP_B_EVENT: crate::event_link::InterruptEvent;
29
30 const COMP_C_EVENT: crate::event_link::InterruptEvent;
32
33 const OVERFLOW_EVENT: crate::event_link::InterruptEvent;
35
36 const UNDERFLOW_EVENT: crate::event_link::InterruptEvent;
38}
39
40pub(crate) trait SealedInstance: PeripheralType {
41 const INDEX: usize;
42
43 fn regs() -> crate::pac::gpt::Gpt;
44}
45
46pub(crate) trait TimerWidth: Into<u32> + Send + Sync + 'static {
47 fn max() -> u64;
48}
49
50impl TimerWidth for u32 {
51 #[inline(always)]
52 fn max() -> u64 {
53 u32::MAX.into()
54 }
55}
56
57impl TimerWidth for u16 {
58 #[inline(always)]
59 fn max() -> u64 {
60 u16::MAX.into()
61 }
62}
63
64#[allow(private_bounds)]
66pub struct InterruptTimer<'d, W: TimerWidth, I: Instance<W>> {
67 phantom_i: PhantomData<&'d I>,
68 phantom_w: PhantomData<W>,
69 triangle: bool,
70}
71
72#[allow(private_bounds)]
73impl<'d, W: TimerWidth, I: Instance<W>> InterruptTimer<'d, W, I> {
74 pub fn new(peri: Peri<'d, I>) -> Self {
76 let _ = peri;
77
78 I::start_module();
79
80 let gpt = I::regs();
81
82 gpt.gtupsr().write_value(Gtupsr(0));
84 gpt.gtdnsr().write_value(Gtdnsr(0));
85 gpt.gtcnt().write_value(0);
86 gpt.gtssr().modify(|r| r.set_cstrt(true));
87
88 Self {
89 phantom_i: PhantomData,
90 phantom_w: PhantomData,
91 triangle: false,
92 }
93 }
94
95 #[inline(always)]
97 pub fn set_frequency(&mut self, frequency: u32) {
98 let gpt = I::regs();
99
100 gpt.gtcr().modify(|r| r.set_tpcs(Tpcs::Div16));
102
103 let clocks = crate::clock::clock_status();
104
105 let mut period = (clocks.peripheral_d.to_Hz() as u64 / 16) / (frequency as u64);
106
107 if period > W::max() {
108 period /= 2;
109 self.triangle = true;
110 gpt.gtcr().modify(|r| r.set_md(Mode::TrianglePwm1));
111 gpt.gtber().modify(|w| w.set_ccra(Ccr::NoBuffer));
112 } else {
113 self.triangle = false;
114 gpt.gtcr().modify(|r| r.set_md(Mode::SawWaveOneShot));
115 }
116
117 assert!(period <= W::max());
118
119 self.set_period(period as u32);
120 }
121
122 #[inline(always)]
123 fn set_period(&mut self, period: u32) {
124 let gpt = I::regs();
125
126 gpt.gtpr().write_value(period);
128 }
129
130 #[inline]
133 pub fn start(&mut self) -> InterruptEvent {
134 let gpt = I::regs();
135
136 gpt.gtuddtyc().write(|r| {
137 r.set_udf(true);
138 r.set_ud(Ud::Up);
139 });
140 gpt.gtuddtyc().write(|r| {
141 r.set_udf(false);
142 r.set_ud(Ud::Up);
143 });
144
145 gpt.gtcnt().write_value(0);
146
147 gpt.gtstr().modify(|r| r.set_cstrt(I::INDEX, true));
149
150 if self.triangle {
151 I::UNDERFLOW_EVENT
152 } else {
153 I::OVERFLOW_EVENT
154 }
155 }
156
157 #[inline(always)]
159 pub fn stop(&mut self) {
160 let gpt = I::regs();
161
162 gpt.gtstr().modify(|r| r.set_cstrt(I::INDEX, false));
164 }
165}
166
167impl<'d, W: TimerWidth, I: Instance<W>> Drop for InterruptTimer<'d, W, I> {
168 fn drop(&mut self) {
169 error!(
170 "GPT{}: Drop not yet implemented, module will not be stopped",
171 I::INDEX
172 );
173 }
174}
175
176macro_rules! timer_instance {
177 ($peripheral:ident, $width:ident, $index:literal, $cmpa_int:ident, $cmpb_int:ident, $cmpc_int:ident, $overflow_int:ident, $underflow_int:ident) => {
178 impl crate::timer_gpt::Instance<$width> for crate::peripherals::$peripheral {
179 const COMP_A_EVENT: crate::event_link::InterruptEvent =
180 crate::event_link::InterruptEvent::$cmpa_int;
181 const COMP_B_EVENT: crate::event_link::InterruptEvent =
182 crate::event_link::InterruptEvent::$cmpb_int;
183 const COMP_C_EVENT: crate::event_link::InterruptEvent =
184 crate::event_link::InterruptEvent::$cmpc_int;
185 const OVERFLOW_EVENT: crate::event_link::InterruptEvent =
186 crate::event_link::InterruptEvent::$overflow_int;
187 const UNDERFLOW_EVENT: crate::event_link::InterruptEvent =
188 crate::event_link::InterruptEvent::$underflow_int;
189 }
190
191 impl crate::timer_gpt::SealedInstance for crate::peripherals::$peripheral {
192 const INDEX: usize = $index;
193
194 #[inline(always)]
195 fn regs() -> crate::pac::gpt::Gpt {
196 crate::pac::$peripheral
197 }
198 }
199 };
200}
201pub(crate) use timer_instance;