diff options
| -rw-r--r-- | embassy-nrf/src/pdm.rs | 55 |
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; | |||
| 26 | pub use crate::pac::pdm::ratio::RATIO_A as Ratio; | 26 | pub use crate::pac::pdm::ratio::RATIO_A as Ratio; |
| 27 | use crate::{interrupt, Peripheral}; | 27 | use crate::{interrupt, Peripheral}; |
| 28 | 28 | ||
| 29 | /// Interrupt handler. | 29 | /// Interrupt handler |
| 30 | pub struct InterruptHandler<T: Instance> { | 30 | pub 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] |
| 63 | pub enum Error { | 63 | pub 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)] |
| 81 | pub enum SamplerState { | 81 | pub 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)] |
| 410 | pub enum OperationMode { | 407 | pub 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 |
| 480 | pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | 477 | pub 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 | ||
