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, T: Instance> {
20 _p: Peri<'d, T>,
21}
22
23#[non_exhaustive]
25pub struct Config {
26 pub num_samples: NumSamples,
28 pub period: SamplePeriod,
30 pub led_polarity: LedPolarity,
32 pub debounce: bool,
34 pub led_pre_usecs: u16,
36}
37
38impl Default for Config {
39 fn default() -> Self {
40 Self {
41 num_samples: NumSamples::_1smpl,
42 period: SamplePeriod::_256us,
43 led_polarity: LedPolarity::ActiveHigh,
44 debounce: true,
45 led_pre_usecs: 0,
46 }
47 }
48}
49
50pub struct InterruptHandler<T: Instance> {
52 _phantom: PhantomData<T>,
53}
54
55impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
56 unsafe fn on_interrupt() {
57 T::regs().intenclr().write(|w| w.set_reportrdy(true));
58 T::state().waker.wake();
59 }
60}
61
62impl<'d, T: Instance> Qdec<'d, T> {
63 pub fn new(
65 qdec: Peri<'d, T>,
66 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
67 a: Peri<'d, impl GpioPin>,
68 b: Peri<'d, impl GpioPin>,
69 config: Config,
70 ) -> Self {
71 Self::new_inner(qdec, a.into(), b.into(), None, config)
72 }
73
74 pub fn new_with_led(
76 qdec: Peri<'d, T>,
77 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
78 a: Peri<'d, impl GpioPin>,
79 b: Peri<'d, impl GpioPin>,
80 led: Peri<'d, impl GpioPin>,
81 config: Config,
82 ) -> Self {
83 Self::new_inner(qdec, a.into(), b.into(), Some(led.into()), config)
84 }
85
86 fn new_inner(
87 p: Peri<'d, T>,
88 a: Peri<'d, AnyPin>,
89 b: Peri<'d, AnyPin>,
90 led: Option<Peri<'d, AnyPin>>,
91 config: Config,
92 ) -> Self {
93 let r = T::regs();
94
95 a.conf().write(|w| {
97 w.set_input(gpiovals::Input::CONNECT);
98 w.set_pull(gpiovals::Pull::PULLUP);
99 });
100 b.conf().write(|w| {
101 w.set_input(gpiovals::Input::CONNECT);
102 w.set_pull(gpiovals::Pull::PULLUP);
103 });
104 r.psel().a().write_value(a.psel_bits());
105 r.psel().b().write_value(b.psel_bits());
106 if let Some(led_pin) = &led {
107 led_pin.conf().write(|w| w.set_dir(gpiovals::Dir::OUTPUT));
108 r.psel().led().write_value(led_pin.psel_bits());
109 }
110
111 r.dbfen().write(|w| match config.debounce {
113 true => w.set_dbfen(true),
114 false => w.set_dbfen(false),
115 });
116
117 r.ledpol().write(|w| match config.led_polarity {
119 LedPolarity::ActiveHigh => w.set_ledpol(vals::Ledpol::ACTIVE_HIGH),
120 LedPolarity::ActiveLow => w.set_ledpol(vals::Ledpol::ACTIVE_LOW),
121 });
122
123 r.ledpre().write(|w| w.set_ledpre(config.led_pre_usecs.min(511)));
125
126 r.sampleper().write(|w| match config.period {
128 SamplePeriod::_128us => w.set_sampleper(vals::Sampleper::_128US),
129 SamplePeriod::_256us => w.set_sampleper(vals::Sampleper::_256US),
130 SamplePeriod::_512us => w.set_sampleper(vals::Sampleper::_512US),
131 SamplePeriod::_1024us => w.set_sampleper(vals::Sampleper::_1024US),
132 SamplePeriod::_2048us => w.set_sampleper(vals::Sampleper::_2048US),
133 SamplePeriod::_4096us => w.set_sampleper(vals::Sampleper::_4096US),
134 SamplePeriod::_8192us => w.set_sampleper(vals::Sampleper::_8192US),
135 SamplePeriod::_16384us => w.set_sampleper(vals::Sampleper::_16384US),
136 SamplePeriod::_32ms => w.set_sampleper(vals::Sampleper::_32MS),
137 SamplePeriod::_65ms => w.set_sampleper(vals::Sampleper::_65MS),
138 SamplePeriod::_131ms => w.set_sampleper(vals::Sampleper::_131MS),
139 });
140
141 T::Interrupt::unpend();
142 unsafe { T::Interrupt::enable() };
143
144 r.enable().write(|w| w.set_enable(true));
146
147 r.tasks_start().write_value(1);
149
150 Self { _p: p }
151 }
152
153 pub async fn read(&mut self) -> i16 {
176 let t = T::regs();
177 t.intenset().write(|w| w.set_reportrdy(true));
178 t.tasks_readclracc().write_value(1);
179
180 poll_fn(|cx| {
181 T::state().waker.register(cx.waker());
182 if t.events_reportrdy().read() == 0 {
183 Poll::Pending
184 } else {
185 t.events_reportrdy().write_value(0);
186 let acc = t.accread().read();
187 Poll::Ready(acc as i16)
188 }
189 })
190 .await
191 }
192}
193
194#[derive(Debug, Eq, PartialEq, Clone, Copy)]
196pub enum SamplePeriod {
197 _128us,
199 _256us,
201 _512us,
203 _1024us,
205 _2048us,
207 _4096us,
209 _8192us,
211 _16384us,
213 _32ms,
215 _65ms,
217 _131ms,
219}
220
221#[derive(Debug, Eq, PartialEq, Clone, Copy)]
223pub enum NumSamples {
224 _10smpl,
226 _40smpl,
228 _80smpl,
230 _120smpl,
232 _160smpl,
234 _200smpl,
236 _240smpl,
238 _280smpl,
240 _1smpl,
242}
243
244#[derive(Debug, Eq, PartialEq, Clone, Copy)]
246pub enum LedPolarity {
247 ActiveHigh,
249 ActiveLow,
251}
252
253pub(crate) struct State {
255 waker: AtomicWaker,
256}
257
258impl State {
259 pub(crate) const fn new() -> Self {
260 Self {
261 waker: AtomicWaker::new(),
262 }
263 }
264}
265
266pub(crate) trait SealedInstance {
267 fn regs() -> pac::qdec::Qdec;
268 fn state() -> &'static State;
269}
270
271#[allow(private_bounds)]
273pub trait Instance: SealedInstance + PeripheralType + 'static + Send {
274 type Interrupt: interrupt::typelevel::Interrupt;
276}
277
278macro_rules! impl_qdec {
279 ($type:ident, $pac_type:ident, $irq:ident) => {
280 impl crate::qdec::SealedInstance for peripherals::$type {
281 fn regs() -> pac::qdec::Qdec {
282 pac::$pac_type
283 }
284 fn state() -> &'static crate::qdec::State {
285 static STATE: crate::qdec::State = crate::qdec::State::new();
286 &STATE
287 }
288 }
289 impl crate::qdec::Instance for peripherals::$type {
290 type Interrupt = crate::interrupt::typelevel::$irq;
291 }
292 };
293}