aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-02-17 01:47:18 +0000
committerGitHub <[email protected]>2024-02-17 01:47:18 +0000
commit6b0e4dfb2d920dc2d2cda987a46aea2e00dc420f (patch)
tree4190a43f67be8a80f7b2ed27e7b22e901452c945
parente19bed921d882b25b618afe29417b6f9c75e81a4 (diff)
parent7d111191689460ddfdce08dec7195cb9fa1b598b (diff)
Merge pull request #2584 from ohrlabs/fix-pdm-gain
embassy-nrf: Fix PDM gain register value derivation
-rw-r--r--embassy-nrf/src/pdm.rs55
1 files changed, 26 insertions, 29 deletions
diff --git a/embassy-nrf/src/pdm.rs b/embassy-nrf/src/pdm.rs
index 24fa29a4a..6ddc4dc0a 100644
--- a/embassy-nrf/src/pdm.rs
+++ b/embassy-nrf/src/pdm.rs
@@ -1,4 +1,4 @@
1//! Pulse Density Modulation (PDM) mirophone driver. 1//! Pulse Density Modulation (PDM) mirophone driver
2 2
3#![macro_use] 3#![macro_use]
4 4
@@ -26,7 +26,7 @@ pub use crate::pac::pdm::pdmclkctrl::FREQ_A as Frequency;
26pub use crate::pac::pdm::ratio::RATIO_A as Ratio; 26pub use crate::pac::pdm::ratio::RATIO_A as Ratio;
27use crate::{interrupt, Peripheral}; 27use crate::{interrupt, Peripheral};
28 28
29/// Interrupt handler. 29/// Interrupt handler
30pub struct InterruptHandler<T: Instance> { 30pub struct InterruptHandler<T: Instance> {
31 _phantom: PhantomData<T>, 31 _phantom: PhantomData<T>,
32} 32}
@@ -56,12 +56,12 @@ pub struct Pdm<'d, T: Instance> {
56 _peri: PeripheralRef<'d, T>, 56 _peri: PeripheralRef<'d, T>,
57} 57}
58 58
59/// PDM error. 59/// PDM error
60#[derive(Debug, Clone, Copy, PartialEq, Eq)] 60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61#[cfg_attr(feature = "defmt", derive(defmt::Format))] 61#[cfg_attr(feature = "defmt", derive(defmt::Format))]
62#[non_exhaustive] 62#[non_exhaustive]
63pub enum Error { 63pub enum Error {
64 /// Buffer is too long. 64 /// Buffer is too long
65 BufferTooLong, 65 BufferTooLong,
66 /// Buffer is empty 66 /// Buffer is empty
67 BufferZeroLength, 67 BufferZeroLength,
@@ -75,13 +75,13 @@ static DUMMY_BUFFER: [i16; 1] = [0; 1];
75 75
76/// The state of a continuously running sampler. While it reflects 76/// The state of a continuously running sampler. While it reflects
77/// the progress of a sampler, it also signals what should be done 77/// the progress of a sampler, it also signals what should be done
78/// next. For example, if the sampler has stopped then the Pdm implementation 78/// next. For example, if the sampler has stopped then the PDM implementation
79/// can then tear down its infrastructure. 79/// can then tear down its infrastructure
80#[derive(PartialEq)] 80#[derive(PartialEq)]
81pub enum SamplerState { 81pub enum SamplerState {
82 /// The sampler processed the samples and is ready for more. 82 /// The sampler processed the samples and is ready for more
83 Sampled, 83 Sampled,
84 /// The sampler is done processing samples. 84 /// The sampler is done processing samples
85 Stopped, 85 Stopped,
86} 86}
87 87
@@ -145,15 +145,12 @@ impl<'d, T: Instance> Pdm<'d, T> {
145 } 145 }
146 146
147 fn _set_gain(r: &crate::pac::pdm::RegisterBlock, gain_left: I7F1, gain_right: I7F1) { 147 fn _set_gain(r: &crate::pac::pdm::RegisterBlock, gain_left: I7F1, gain_right: I7F1) {
148 let gain_left = gain_left 148 let gain_to_bits = |gain: I7F1| -> u8 {
149 .saturating_add(I7F1::from_bits(40)) 149 let gain = gain.saturating_add(I7F1::from_bits(0x28)).to_bits().clamp(0, 0x50);
150 .saturating_to_num::<u8>() 150 unsafe { core::mem::transmute(gain) }
151 .clamp(0, 0x50); 151 };
152 let gain_right = gain_right 152 let gain_left = gain_to_bits(gain_left);
153 .saturating_add(I7F1::from_bits(40)) 153 let gain_right = gain_to_bits(gain_right);
154 .saturating_to_num::<u8>()
155 .clamp(0, 0x50);
156
157 r.gainl.write(|w| unsafe { w.gainl().bits(gain_left) }); 154 r.gainl.write(|w| unsafe { w.gainl().bits(gain_left) });
158 r.gainr.write(|w| unsafe { w.gainr().bits(gain_right) }); 155 r.gainr.write(|w| unsafe { w.gainr().bits(gain_right) });
159 } 156 }
@@ -163,12 +160,12 @@ impl<'d, T: Instance> Pdm<'d, T> {
163 Self::_set_gain(T::regs(), gain_left, gain_right) 160 Self::_set_gain(T::regs(), gain_left, gain_right)
164 } 161 }
165 162
166 /// Start sampling microphon data into a dummy buffer 163 /// Start sampling microphone data into a dummy buffer.
167 /// Usefull to start the microphon and keep it active between recording samples 164 /// Useful to start the microphone and keep it active between recording samples.
168 pub async fn start(&mut self) { 165 pub async fn start(&mut self) {
169 let r = T::regs(); 166 let r = T::regs();
170 167
171 // start dummy sampling because microphon needs some setup time 168 // start dummy sampling because microphone needs some setup time
172 r.sample 169 r.sample
173 .ptr 170 .ptr
174 .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) }); 171 .write(|w| unsafe { w.sampleptr().bits(DUMMY_BUFFER.as_ptr() as u32) });
@@ -179,14 +176,14 @@ impl<'d, T: Instance> Pdm<'d, T> {
179 r.tasks_start.write(|w| unsafe { w.bits(1) }); 176 r.tasks_start.write(|w| unsafe { w.bits(1) });
180 } 177 }
181 178
182 /// Stop sampling microphon data inta a dummy buffer 179 /// Stop sampling microphone data inta a dummy buffer
183 pub async fn stop(&mut self) { 180 pub async fn stop(&mut self) {
184 let r = T::regs(); 181 let r = T::regs();
185 r.tasks_stop.write(|w| unsafe { w.bits(1) }); 182 r.tasks_stop.write(|w| unsafe { w.bits(1) });
186 r.events_started.reset(); 183 r.events_started.reset();
187 } 184 }
188 185
189 /// Sample data into the given buffer. 186 /// Sample data into the given buffer
190 pub async fn sample(&mut self, buffer: &mut [i16]) -> Result<(), Error> { 187 pub async fn sample(&mut self, buffer: &mut [i16]) -> Result<(), Error> {
191 if buffer.len() == 0 { 188 if buffer.len() == 0 {
192 return Err(Error::BufferZeroLength); 189 return Err(Error::BufferZeroLength);
@@ -303,7 +300,7 @@ impl<'d, T: Instance> Pdm<'d, T> {
303 }); 300 });
304 301
305 // Don't reorder the start event before the previous writes. Hopefully self 302 // Don't reorder the start event before the previous writes. Hopefully self
306 // wouldn't happen anyway. 303 // wouldn't happen anyway
307 compiler_fence(Ordering::SeqCst); 304 compiler_fence(Ordering::SeqCst);
308 305
309 r.tasks_start.write(|w| unsafe { w.bits(1) }); 306 r.tasks_start.write(|w| unsafe { w.bits(1) });
@@ -314,11 +311,11 @@ impl<'d, T: Instance> Pdm<'d, T> {
314 311
315 let drop = OnDrop::new(|| { 312 let drop = OnDrop::new(|| {
316 r.tasks_stop.write(|w| unsafe { w.bits(1) }); 313 r.tasks_stop.write(|w| unsafe { w.bits(1) });
317 // N.B. It would be better if this were async, but Drop only support sync code. 314 // N.B. It would be better if this were async, but Drop only support sync code
318 while r.events_stopped.read().bits() != 0 {} 315 while r.events_stopped.read().bits() != 0 {}
319 }); 316 });
320 317
321 // Wait for events and complete when the sampler indicates it has had enough. 318 // Wait for events and complete when the sampler indicates it has had enough
322 poll_fn(|cx| { 319 poll_fn(|cx| {
323 let r = T::regs(); 320 let r = T::regs();
324 321
@@ -331,7 +328,7 @@ impl<'d, T: Instance> Pdm<'d, T> {
331 r.intenset.write(|w| w.end().set()); 328 r.intenset.write(|w| w.end().set());
332 329
333 if !done { 330 if !done {
334 // Discard the last buffer after the user requested a stop. 331 // Discard the last buffer after the user requested a stop
335 if sampler(&bufs[current_buffer]) == SamplerState::Sampled { 332 if sampler(&bufs[current_buffer]) == SamplerState::Sampled {
336 let next_buffer = 1 - current_buffer; 333 let next_buffer = 1 - current_buffer;
337 current_buffer = next_buffer; 334 current_buffer = next_buffer;
@@ -405,7 +402,7 @@ impl Default for Config {
405 } 402 }
406} 403}
407 404
408/// PDM operation mode. 405/// PDM operation mode
409#[derive(PartialEq)] 406#[derive(PartialEq)]
410pub enum OperationMode { 407pub enum OperationMode {
411 /// Mono (1 channel) 408 /// Mono (1 channel)
@@ -476,9 +473,9 @@ pub(crate) mod sealed {
476 } 473 }
477} 474}
478 475
479/// PDM peripheral instance. 476/// PDM peripheral instance
480pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { 477pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
481 /// Interrupt for this peripheral. 478 /// Interrupt for this peripheral
482 type Interrupt: interrupt::typelevel::Interrupt; 479 type Interrupt: interrupt::typelevel::Interrupt;
483} 480}
484 481