1#![macro_use]
4
5use core::future::poll_fn;
6use core::marker::PhantomData;
7use core::task::Poll;
8
9use embassy_hal_internal::{Peri, PeripheralType};
10use embassy_sync::waitqueue::AtomicWaker;
11
12use crate::gpio::{AnyPin, Pin as GpioPin, SealedPin as _};
13use crate::interrupt::typelevel::Interrupt;
14use crate::pac::gpio::vals as gpiovals;
15use crate::pac::qdec::vals;
16use crate::{interrupt, pac};
17
18pub struct Qdec<'d> {
20 r: pac::qdec::Qdec,
21 state: &'static State,
22 _phantom: PhantomData<&'d ()>,
23}
24
25#[non_exhaustive]
27pub struct Config {
28 pub num_samples: NumSamples,
30 pub period: SamplePeriod,
32 pub led_polarity: LedPolarity,
34 pub debounce: bool,
36 pub led_pre_usecs: u16,
38}
39
40impl Default for Config {
41 fn default() -> Self {
42 Self {
43 num_samples: NumSamples::_1smpl,
44 period: SamplePeriod::_256us,
45 led_polarity: LedPolarity::ActiveHigh,
46 debounce: true,
47 led_pre_usecs: 0,
48 }
49 }
50}
51
52pub struct InterruptHandler<T: Instance> {
54 _phantom: PhantomData<T>,
55}
56
57impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
58 unsafe fn on_interrupt() {
59 T::regs().intenclr().write(|w| w.set_reportrdy(true));
60 T::state().waker.wake();
61 }
62}
63
64impl<'d> Qdec<'d> {
65 pub fn new<T: Instance>(
67 qdec: Peri<'d, T>,
68 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
69 a: Peri<'d, impl GpioPin>,
70 b: Peri<'d, impl GpioPin>,
71 config: Config,
72 ) -> Self {
73 Self::new_inner(qdec, a.into(), b.into(), None, config)
74 }
75
76 pub fn new_with_led<T: Instance>(
78 qdec: Peri<'d, T>,
79 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
80 a: Peri<'d, impl GpioPin>,
81 b: Peri<'d, impl GpioPin>,
82 led: Peri<'d, impl GpioPin>,
83 config: Config,
84 ) -> Self {
85 Self::new_inner(qdec, a.into(), b.into(), Some(led.into()), config)
86 }
87
88 fn new_inner<T: Instance>(
89 _p: Peri<'d, T>,
90 a: Peri<'d, AnyPin>,
91 b: Peri<'d, AnyPin>,
92 led: Option<Peri<'d, AnyPin>>,
93 config: Config,
94 ) -> Self {
95 let r = T::regs();
96
97 a.conf().write(|w| {
99 w.set_input(gpiovals::Input::CONNECT);
100 w.set_pull(gpiovals::Pull::PULLUP);
101 });
102 b.conf().write(|w| {
103 w.set_input(gpiovals::Input::CONNECT);
104 w.set_pull(gpiovals::Pull::PULLUP);
105 });
106 r.psel().a().write_value(a.psel_bits());
107 r.psel().b().write_value(b.psel_bits());
108 if let Some(led_pin) = &led {
109 led_pin.conf().write(|w| w.set_dir(gpiovals::Dir::OUTPUT));
110 r.psel().led().write_value(led_pin.psel_bits());
111 }
112
113 r.dbfen().write(|w| match config.debounce {
115 true => w.set_dbfen(true),
116 false => w.set_dbfen(false),
117 });
118
119 r.ledpol().write(|w| match config.led_polarity {
121 LedPolarity::ActiveHigh => w.set_ledpol(vals::Ledpol::ACTIVE_HIGH),
122 LedPolarity::ActiveLow => w.set_ledpol(vals::Ledpol::ACTIVE_LOW),
123 });
124
125 r.ledpre().write(|w| w.set_ledpre(config.led_pre_usecs.min(511)));
127
128 r.sampleper().write(|w| match config.period {
130 SamplePeriod::_128us => w.set_sampleper(vals::Sampleper::_128US),
131 SamplePeriod::_256us => w.set_sampleper(vals::Sampleper::_256US),
132 SamplePeriod::_512us => w.set_sampleper(vals::Sampleper::_512US),
133 SamplePeriod::_1024us => w.set_sampleper(vals::Sampleper::_1024US),
134 SamplePeriod::_2048us => w.set_sampleper(vals::Sampleper::_2048US),
135 SamplePeriod::_4096us => w.set_sampleper(vals::Sampleper::_4096US),
136 SamplePeriod::_8192us => w.set_sampleper(vals::Sampleper::_8192US),
137 SamplePeriod::_16384us => w.set_sampleper(vals::Sampleper::_16384US),
138 SamplePeriod::_32ms => w.set_sampleper(vals::Sampleper::_32MS),
139 SamplePeriod::_65ms => w.set_sampleper(vals::Sampleper::_65MS),
140 SamplePeriod::_131ms => w.set_sampleper(vals::Sampleper::_131MS),
141 });
142
143 T::Interrupt::unpend();
144 unsafe { T::Interrupt::enable() };
145
146 r.enable().write(|w| w.set_enable(true));
148
149 r.tasks_start().write_value(1);
151
152 Self {
153 r: T::regs(),
154 state: T::state(),
155 _phantom: PhantomData,
156 }
157 }
158
159 pub async fn read(&mut self) -> i16 {
182 self.r.intenset().write(|w| w.set_reportrdy(true));
183 self.r.tasks_readclracc().write_value(1);
184
185 let state = self.state;
186 let r = self.r;
187 poll_fn(move |cx| {
188 state.waker.register(cx.waker());
189 if r.events_reportrdy().read() == 0 {
190 Poll::Pending
191 } else {
192 r.events_reportrdy().write_value(0);
193 let acc = r.accread().read();
194 Poll::Ready(acc as i16)
195 }
196 })
197 .await
198 }
199}
200
201#[derive(Debug, Eq, PartialEq, Clone, Copy)]
203pub enum SamplePeriod {
204 _128us,
206 _256us,
208 _512us,
210 _1024us,
212 _2048us,
214 _4096us,
216 _8192us,
218 _16384us,
220 _32ms,
222 _65ms,
224 _131ms,
226}
227
228#[derive(Debug, Eq, PartialEq, Clone, Copy)]
230pub enum NumSamples {
231 _10smpl,
233 _40smpl,
235 _80smpl,
237 _120smpl,
239 _160smpl,
241 _200smpl,
243 _240smpl,
245 _280smpl,
247 _1smpl,
249}
250
251#[derive(Debug, Eq, PartialEq, Clone, Copy)]
253pub enum LedPolarity {
254 ActiveHigh,
256 ActiveLow,
258}
259
260pub(crate) struct State {
262 waker: AtomicWaker,
263}
264
265impl State {
266 pub(crate) const fn new() -> Self {
267 Self {
268 waker: AtomicWaker::new(),
269 }
270 }
271}
272
273pub(crate) trait SealedInstance {
274 fn regs() -> pac::qdec::Qdec;
275 fn state() -> &'static State;
276}
277
278#[allow(private_bounds)]
280pub trait Instance: SealedInstance + PeripheralType + 'static + Send {
281 type Interrupt: interrupt::typelevel::Interrupt;
283}
284
285macro_rules! impl_qdec {
286 ($type:ident, $pac_type:ident, $irq:ident) => {
287 impl crate::qdec::SealedInstance for peripherals::$type {
288 fn regs() -> pac::qdec::Qdec {
289 pac::$pac_type
290 }
291 fn state() -> &'static crate::qdec::State {
292 static STATE: crate::qdec::State = crate::qdec::State::new();
293 &STATE
294 }
295 }
296 impl crate::qdec::Instance for peripherals::$type {
297 type Interrupt = crate::interrupt::typelevel::$irq;
298 }
299 };
300}