1#![macro_use]
4
5use core::future::poll_fn;
6use core::marker::PhantomData;
7use core::sync::atomic::{compiler_fence, Ordering};
8use core::task::Poll;
9
10use embassy_hal_internal::drop::OnDrop;
11use embassy_hal_internal::{Peri, PeripheralType};
12use embassy_sync::waitqueue::AtomicWaker;
13use fixed::types::I7F1;
14
15use crate::chip::EASY_DMA_SIZE;
16use crate::gpio::{AnyPin, Pin as GpioPin, SealedPin, DISCONNECTED};
17use crate::interrupt::typelevel::Interrupt;
18use crate::pac::gpio::vals as gpiovals;
19use crate::pac::pdm::vals;
20pub use crate::pac::pdm::vals::Freq as Frequency;
21#[cfg(any(
22 feature = "nrf52840",
23 feature = "nrf52833",
24 feature = "_nrf5340-app",
25 feature = "_nrf91",
26))]
27pub use crate::pac::pdm::vals::Ratio;
28use crate::{interrupt, pac};
29
30pub struct InterruptHandler<T: Instance> {
32 _phantom: PhantomData<T>,
33}
34
35impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
36 unsafe fn on_interrupt() {
37 let r = T::regs();
38
39 if r.events_end().read() != 0 {
40 r.intenclr().write(|w| w.set_end(true));
41 }
42
43 if r.events_started().read() != 0 {
44 r.intenclr().write(|w| w.set_started(true));
45 }
46
47 if r.events_stopped().read() != 0 {
48 r.intenclr().write(|w| w.set_stopped(true));
49 }
50
51 T::state().waker.wake();
52 }
53}
54
55pub struct Pdm<'d> {
57 r: pac::pdm::Pdm,
58 state: &'static State,
59 _phantom: PhantomData<&'d ()>,
60}
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
64#[cfg_attr(feature = "defmt", derive(defmt::Format))]
65#[non_exhaustive]
66pub enum Error {
67 BufferTooLong,
69 BufferZeroLength,
71 NotRunning,
73 AlreadyRunning,
75}
76
77static DUMMY_BUFFER: [i16; 1] = [0; 1];
78
79#[derive(PartialEq)]
84pub enum SamplerState {
85 Sampled,
87 Stopped,
89}
90
91impl<'d> Pdm<'d> {
92 pub fn new<T: Instance>(
94 pdm: Peri<'d, T>,
95 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
96 clk: Peri<'d, impl GpioPin>,
97 din: Peri<'d, impl GpioPin>,
98 config: Config,
99 ) -> Self {
100 Self::new_inner(pdm, clk.into(), din.into(), config)
101 }
102
103 fn new_inner<T: Instance>(_pdm: Peri<'d, T>, clk: Peri<'d, AnyPin>, din: Peri<'d, AnyPin>, config: Config) -> Self {
104 let r = T::regs();
105
106 din.conf().write(|w| w.set_input(gpiovals::Input::CONNECT));
108 r.psel().din().write_value(din.psel_bits());
109 clk.set_low();
110 clk.conf().write(|w| w.set_dir(gpiovals::Dir::OUTPUT));
111 r.psel().clk().write_value(clk.psel_bits());
112
113 r.pdmclkctrl().write(|w| w.set_freq(config.frequency));
115 #[cfg(any(
116 feature = "nrf52840",
117 feature = "nrf52833",
118 feature = "_nrf5340-app",
119 feature = "_nrf91",
120 ))]
121 r.ratio().write(|w| w.set_ratio(config.ratio));
122 r.mode().write(|w| {
123 w.set_operation(config.operation_mode.into());
124 w.set_edge(config.edge.into());
125 });
126
127 Self::_set_gain(r, config.gain_left, config.gain_right);
128
129 r.intenclr().write(|w| w.0 = 0x003F_FFFF);
131
132 T::Interrupt::unpend();
134 unsafe { T::Interrupt::enable() };
135
136 r.enable().write(|w| w.set_enable(true));
137
138 Self {
139 r: T::regs(),
140 state: T::state(),
141 _phantom: PhantomData,
142 }
143 }
144
145 fn _set_gain(r: pac::pdm::Pdm, gain_left: I7F1, gain_right: I7F1) {
146 let gain_to_bits = |gain: I7F1| -> vals::Gain {
147 let gain: i8 = gain.saturating_add(I7F1::from_bits(0x28)).to_bits().clamp(0, 0x50);
148 vals::Gain::from_bits(gain as u8)
149 };
150 r.gainl().write(|w| w.set_gainl(gain_to_bits(gain_left)));
151 r.gainr().write(|w| w.set_gainr(gain_to_bits(gain_right)));
152 }
153
154 pub fn set_gain(&mut self, gain_left: I7F1, gain_right: I7F1) {
156 Self::_set_gain(self.r, gain_left, gain_right)
157 }
158
159 pub async fn start(&mut self) {
162 self.r.sample().ptr().write_value(DUMMY_BUFFER.as_ptr() as u32);
164 self.r
165 .sample()
166 .maxcnt()
167 .write(|w| w.set_buffsize(DUMMY_BUFFER.len() as _));
168
169 self.r.tasks_start().write_value(1);
170 }
171
172 pub async fn stop(&mut self) {
174 self.r.tasks_stop().write_value(1);
175 self.r.events_started().write_value(0);
176 }
177
178 pub async fn sample(&mut self, buffer: &mut [i16]) -> Result<(), Error> {
180 if buffer.is_empty() {
181 return Err(Error::BufferZeroLength);
182 }
183 if buffer.len() > EASY_DMA_SIZE {
184 return Err(Error::BufferTooLong);
185 }
186
187 if self.r.events_started().read() == 0 {
188 return Err(Error::NotRunning);
189 }
190
191 let r = self.r;
192 let drop = OnDrop::new(move || {
193 r.intenclr().write(|w| w.set_end(true));
194 r.events_stopped().write_value(0);
195
196 r.sample().ptr().write_value(DUMMY_BUFFER.as_ptr() as u32);
198 r.sample().maxcnt().write(|w| w.set_buffsize(DUMMY_BUFFER.len() as _));
199
200 while r.events_stopped().read() == 0 {}
201 });
202
203 let ptr = buffer.as_ptr();
205 let len = buffer.len();
206 self.r.sample().ptr().write_value(ptr as u32);
207 self.r.sample().maxcnt().write(|w| w.set_buffsize(len as _));
208
209 self.wait_for_sample().await;
211
212 self.r.sample().ptr().write_value(DUMMY_BUFFER.as_ptr() as u32);
214 self.r
215 .sample()
216 .maxcnt()
217 .write(|w| w.set_buffsize(DUMMY_BUFFER.len() as _));
218
219 self.wait_for_sample().await;
221
222 drop.defuse();
223
224 Ok(())
225 }
226
227 async fn wait_for_sample(&mut self) {
228 self.r.events_end().write_value(0);
229 self.r.intenset().write(|w| w.set_end(true));
230
231 compiler_fence(Ordering::SeqCst);
232
233 let state = self.state;
234 let r = self.r;
235 poll_fn(|cx| {
236 state.waker.register(cx.waker());
237 if r.events_end().read() != 0 {
238 return Poll::Ready(());
239 }
240 Poll::Pending
241 })
242 .await;
243
244 compiler_fence(Ordering::SeqCst);
245 }
246
247 pub async fn run_task_sampler<S, const N: usize>(
259 &mut self,
260 bufs: &mut [[i16; N]; 2],
261 mut sampler: S,
262 ) -> Result<(), Error>
263 where
264 S: FnMut(&[i16; N]) -> SamplerState,
265 {
266 if self.r.events_started().read() != 0 {
267 return Err(Error::AlreadyRunning);
268 }
269
270 self.r.sample().ptr().write_value(bufs[0].as_mut_ptr() as u32);
271 self.r.sample().maxcnt().write(|w| w.set_buffsize(N as _));
272
273 self.r.events_end().write_value(0);
275 self.r.events_started().write_value(0);
276 self.r.events_stopped().write_value(0);
277 self.r.intenset().write(|w| {
278 w.set_end(true);
279 w.set_started(true);
280 w.set_stopped(true);
281 });
282
283 compiler_fence(Ordering::SeqCst);
286
287 self.r.tasks_start().write_value(1);
288
289 let mut current_buffer = 0;
290
291 let mut done = false;
292
293 let r = self.r;
294 let drop = OnDrop::new(move || {
295 r.tasks_stop().write_value(1);
296 while r.events_stopped().read() != 0 {}
298 });
299
300 let state = self.state;
301 let r = self.r;
302 poll_fn(|cx| {
304 state.waker.register(cx.waker());
305
306 if r.events_end().read() != 0 {
307 compiler_fence(Ordering::SeqCst);
308
309 r.events_end().write_value(0);
310 r.intenset().write(|w| w.set_end(true));
311
312 if !done {
313 if sampler(&bufs[current_buffer]) == SamplerState::Sampled {
315 let next_buffer = 1 - current_buffer;
316 current_buffer = next_buffer;
317 } else {
318 r.tasks_stop().write_value(1);
319 done = true;
320 };
321 };
322 }
323
324 if r.events_started().read() != 0 {
325 r.events_started().write_value(0);
326 r.intenset().write(|w| w.set_started(true));
327
328 let next_buffer = 1 - current_buffer;
329 r.sample().ptr().write_value(bufs[next_buffer].as_mut_ptr() as u32);
330 }
331
332 if r.events_stopped().read() != 0 {
333 return Poll::Ready(());
334 }
335
336 Poll::Pending
337 })
338 .await;
339 drop.defuse();
340 Ok(())
341 }
342}
343
344pub struct Config {
346 pub operation_mode: OperationMode,
348 pub edge: Edge,
350 pub frequency: Frequency,
352 #[cfg(any(
354 feature = "nrf52840",
355 feature = "nrf52833",
356 feature = "_nrf5340-app",
357 feature = "_nrf91",
358 ))]
359 pub ratio: Ratio,
360 pub gain_left: I7F1,
362 pub gain_right: I7F1,
364}
365
366impl Default for Config {
367 fn default() -> Self {
368 Self {
369 operation_mode: OperationMode::Mono,
370 edge: Edge::LeftFalling,
371 frequency: Frequency::DEFAULT,
372 #[cfg(any(
373 feature = "nrf52840",
374 feature = "nrf52833",
375 feature = "_nrf5340-app",
376 feature = "_nrf91",
377 ))]
378 ratio: Ratio::RATIO80,
379 gain_left: I7F1::ZERO,
380 gain_right: I7F1::ZERO,
381 }
382 }
383}
384
385#[derive(PartialEq)]
387pub enum OperationMode {
388 Mono,
390 Stereo,
392}
393
394impl From<OperationMode> for vals::Operation {
395 fn from(mode: OperationMode) -> Self {
396 match mode {
397 OperationMode::Mono => vals::Operation::MONO,
398 OperationMode::Stereo => vals::Operation::STEREO,
399 }
400 }
401}
402
403#[derive(PartialEq)]
405pub enum Edge {
406 LeftRising,
408 LeftFalling,
410}
411
412impl From<Edge> for vals::Edge {
413 fn from(edge: Edge) -> Self {
414 match edge {
415 Edge::LeftRising => vals::Edge::LEFT_RISING,
416 Edge::LeftFalling => vals::Edge::LEFT_FALLING,
417 }
418 }
419}
420
421impl<'d> Drop for Pdm<'d> {
422 fn drop(&mut self) {
423 self.r.tasks_stop().write_value(1);
424
425 self.r.enable().write(|w| w.set_enable(false));
426
427 self.r.psel().din().write_value(DISCONNECTED);
428 self.r.psel().clk().write_value(DISCONNECTED);
429 }
430}
431
432pub(crate) struct State {
434 waker: AtomicWaker,
435}
436
437impl State {
438 pub(crate) const fn new() -> Self {
439 Self {
440 waker: AtomicWaker::new(),
441 }
442 }
443}
444
445pub(crate) trait SealedInstance {
446 fn regs() -> crate::pac::pdm::Pdm;
447 fn state() -> &'static State;
448}
449
450#[allow(private_bounds)]
452pub trait Instance: SealedInstance + PeripheralType + 'static + Send {
453 type Interrupt: interrupt::typelevel::Interrupt;
455}
456
457macro_rules! impl_pdm {
458 ($type:ident, $pac_type:ident, $irq:ident) => {
459 impl crate::pdm::SealedInstance for peripherals::$type {
460 fn regs() -> crate::pac::pdm::Pdm {
461 pac::$pac_type
462 }
463 fn state() -> &'static crate::pdm::State {
464 static STATE: crate::pdm::State = crate::pdm::State::new();
465 &STATE
466 }
467 }
468 impl crate::pdm::Instance for peripherals::$type {
469 type Interrupt = crate::interrupt::typelevel::$irq;
470 }
471 };
472}