1use core::{future::poll_fn, marker::PhantomData, task::Poll};
22
23use embassy_hal_internal::{Peri, interrupt::InterruptExt as _};
24
25use crate::{
26 event_link::IcuInterrupt as _,
27 gpio::{Flex, WithOpenDrain},
28 interrupt,
29 interrupt::typelevel::{Handler as InterruptHandler, Interrupt as InterruptType},
30 pac::gpt::{
31 regs::{Gtdnsr, Gtupsr},
32 vals::{Ccr, Nfcs},
33 },
34 pwm::{ChanA, ChanB, Divider, Instance, PwmPin},
35};
36
37#[cfg_attr(feature = "defmt", derive(defmt::Format))]
39#[non_exhaustive]
40pub struct Config {
41 pub divider: Divider,
43
44 pub debounce: Debounce,
46}
47
48#[cfg_attr(feature = "defmt", derive(defmt::Format))]
50#[derive(Copy, Clone, PartialEq)]
51pub enum Debounce {
52 Off,
54
55 Min1,
57
58 Min4,
60
61 Min16,
63
64 Min64,
66}
67
68#[cfg_attr(feature = "defmt", derive(defmt::Format))]
70#[derive(Copy, Clone, PartialEq)]
71pub enum Direction {
72 #[allow(missing_docs)]
73 Up,
74
75 #[allow(missing_docs)]
76 Down,
77
78 #[allow(missing_docs)]
79 Unknown,
80}
81
82#[allow(private_bounds)]
84pub struct Qdec<'d, I: Instance, Int: InterruptType> {
85 _instance: PhantomData<&'d I>,
86 _interrupt: PhantomData<Int>,
87 _pin_a: Flex<'d, WithOpenDrain>,
89 _pin_b: Flex<'d, WithOpenDrain>,
90}
91
92#[allow(private_bounds)]
94pub struct QdecInterruptHandler<I: Instance> {
95 _phantom: PhantomData<I>,
96}
97
98impl From<Debounce> for Nfcs {
99 fn from(value: Debounce) -> Self {
100 match value {
101 Debounce::Off => Self::Pclkd1,
103 Debounce::Min1 => Self::Pclkd1,
104 Debounce::Min4 => Self::Pclkd4,
105 Debounce::Min16 => Self::Pclkd16,
106 Debounce::Min64 => Self::Pclkd64,
107 }
108 }
109}
110
111impl Default for Config {
112 fn default() -> Self {
113 Self {
114 divider: Divider::Div1024,
115 debounce: Debounce::Min64,
116 }
117 }
118}
119
120impl<I: Instance, Int: InterruptType> InterruptHandler<Int> for QdecInterruptHandler<I> {
121 unsafe fn on_interrupt() {
122 Int::IRQ.icu_unpend();
123 I::cmpa_waker().wake()
124 }
125}
126
127#[allow(private_bounds)]
128impl<'d, I: Instance, Int: InterruptType> Qdec<'d, I, Int> {
129 pub fn new<A: PwmPin<I, ChanA>, B: PwmPin<I, ChanB>>(
131 peri: Peri<'d, I>,
132 pin_a: Peri<'d, A>,
133 pin_b: Peri<'d, B>,
134 config: Config,
135 irq: impl interrupt::typelevel::Binding<Int, QdecInterruptHandler<I>>,
136 ) -> Self {
137 let _ = peri;
138 let _ = irq;
139
140 let pwm = I::regs();
141
142 pwm.gticasr().modify(|r| {
143 r.set_ascarbl(true);
144 r.set_ascarbh(false);
145 r.set_ascafbl(true);
146 r.set_ascafbh(false);
147 });
148 pwm.gtcr().modify(|w| w.set_tpcs(config.divider.into()));
149 pwm.gtpr().write_value(0xFFFF);
150
151 pwm.gtupsr().write_value(Gtupsr(0x6900));
153 pwm.gtdnsr().write_value(Gtdnsr(0x9600));
154
155 let debounce_enable = config.debounce != Debounce::Off;
156
157 pwm.gtior().modify(|r| {
159 r.set_nfaen(debounce_enable);
160 r.set_nfcsa(config.debounce.into());
161 r.set_nfben(debounce_enable);
162 r.set_nfcsb(config.debounce.into());
163 });
164
165 pwm.gtcnt().write_value(0);
166 pwm.gtccra().write_value(0);
167 pwm.gtccrc().write_value(0);
168 pwm.gtber().modify(|w| w.set_ccra(Ccr::SingleBuffer));
169
170 pin_a.set_pfunc();
171 let pin_a = Flex::new(pin_a);
172
173 pin_b.set_pfunc();
174 let pin_b = Flex::new(pin_b);
175
176 unsafe {
177 Int::IRQ.enable();
178 Int::IRQ.icu_enable(I::CAPTURE_COMP_A_EVENT)
179 };
180
181 pwm.gtcr().modify(|w| w.set_cst(true));
182 pwm.gtst().modify(|r| r.set_tcfa(false));
183
184 Self {
185 _instance: PhantomData,
186 _interrupt: PhantomData,
187 _pin_a: pin_a,
188 _pin_b: pin_b,
189 }
190 }
191
192 pub fn count(&self) -> u32 {
194 let pwm = I::regs();
195 pwm.gtcnt().read()
197 }
198
199 pub async fn read(&self) -> Direction {
201 let pwm = I::regs();
202
203 poll_fn(|ctx| {
204 I::cmpa_waker().register(ctx.waker());
205
206 if pwm.gtst().read().tcfa() {
207 pwm.gtst().modify(|r| r.set_tcfa(false));
209
210 let count = pwm.gtcnt().read();
211 let prev_count = pwm.gtccra().read();
212
213 if count > prev_count {
214 Poll::Ready(Direction::Up)
215 } else if count < prev_count {
216 Poll::Ready(Direction::Down)
217 } else {
218 Poll::Ready(Direction::Unknown)
219 }
220 } else {
221 Poll::Pending
222 }
223 })
224 .await
225 }
226
227 pub fn reset(&mut self) {
229 let pwm = I::regs();
230
231 critical_section::with(|_| {
232 pwm.gtcnt().write_value(0);
233 pwm.gtccra().write_value(0);
234 pwm.gtccrc().write_value(0);
235 });
236 }
237}
238
239impl<'d, I: Instance, Int: InterruptType> Drop for Qdec<'d, I, Int> {
240 fn drop(&mut self) {
242 Int::IRQ.disable();
243 Int::IRQ.icu_disable();
244
245 let pwm = I::regs();
246 pwm.gtcr().modify(|w| w.set_cst(false));
247 }
248}