Add missing parts and Cleanup
This commit is contained in:
		
							parent
							
								
									1ed260b105
								
							
						
					
					
						commit
						6b88057aef
					
				| @ -1,27 +1,27 @@ | |||||||
| #![macro_use] | #![macro_use] | ||||||
| 
 | 
 | ||||||
| //! I2S
 | //! Support for I2S audio
 | ||||||
| 
 | 
 | ||||||
| use core::future::poll_fn; | use core::future::poll_fn; | ||||||
| use core::marker::PhantomData; | use core::marker::PhantomData; | ||||||
| use core::sync::atomic::{compiler_fence, Ordering}; | use core::sync::atomic::{compiler_fence, Ordering}; | ||||||
| use core::task::Poll; | use core::task::Poll; | ||||||
| 
 | 
 | ||||||
| use embassy_cortex_m::interrupt::{InterruptExt, Priority}; | use embassy_cortex_m::interrupt::InterruptExt; | ||||||
| use embassy_hal_common::drop::OnDrop; | use embassy_hal_common::drop::OnDrop; | ||||||
| use embassy_hal_common::{into_ref, PeripheralRef}; | use embassy_hal_common::{into_ref, PeripheralRef}; | ||||||
| 
 | 
 | ||||||
| use crate::gpio::{AnyPin, Pin as GpioPin}; | use crate::gpio::{AnyPin, Pin as GpioPin}; | ||||||
| use crate::interrupt::Interrupt; | use crate::interrupt::Interrupt; | ||||||
| use crate::pac::i2s::{RegisterBlock, CONFIG, PSEL}; | use crate::pac::i2s::RegisterBlock; | ||||||
| use crate::Peripheral; | use crate::Peripheral; | ||||||
| 
 | 
 | ||||||
| // TODO: Define those in lib.rs somewhere else
 | // TODO: Define those in lib.rs somewhere else
 | ||||||
| //
 | 
 | ||||||
| // I2S EasyDMA MAXCNT bit length = 14
 | /// I2S EasyDMA MAXCNT bit length = 14
 | ||||||
| const MAX_DMA_MAXCNT: u32 = 1 << 14; | const MAX_DMA_MAXCNT: u32 = 1 << 14; | ||||||
| 
 | 
 | ||||||
| // Limits for Easy DMA - it can only read from data ram
 | /// Limits for Easy DMA - it can only read from data ram
 | ||||||
| pub const SRAM_LOWER: usize = 0x2000_0000; | pub const SRAM_LOWER: usize = 0x2000_0000; | ||||||
| pub const SRAM_UPPER: usize = 0x3000_0000; | pub const SRAM_UPPER: usize = 0x3000_0000; | ||||||
| 
 | 
 | ||||||
| @ -36,35 +36,144 @@ pub enum Error { | |||||||
|     BufferLengthMisaligned, |     BufferLengthMisaligned, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub const MODE_MASTER_8000: Mode = Mode::Master { | /// Approximate sample rates.
 | ||||||
|     freq: MckFreq::_32MDiv125, | ///
 | ||||||
|     ratio: Ratio::_32x, | /// Those are common sample rates that can not be configured without an small error.
 | ||||||
| }; // error = 0
 | ///
 | ||||||
| pub const MODE_MASTER_11025: Mode = Mode::Master { | /// For custom master clock configuration, please refer to [Mode].
 | ||||||
|     freq: MckFreq::_32MDiv15, | #[derive(Clone, Copy)] | ||||||
|     ratio: Ratio::_192x, | pub enum ApproxSampleRate { | ||||||
| }; // error = 86
 |     _11025, | ||||||
| pub const MODE_MASTER_16000: Mode = Mode::Master { |     _16000, | ||||||
|     freq: MckFreq::_32MDiv21, |     _22050, | ||||||
|     ratio: Ratio::_96x, |     _32000, | ||||||
| }; // error = 127
 |     _44100, | ||||||
| pub const MODE_MASTER_22050: Mode = Mode::Master { |     _48000, | ||||||
|     freq: MckFreq::_32MDiv15, | } | ||||||
|     ratio: Ratio::_96x, |  | ||||||
| }; // error = 172
 |  | ||||||
| pub const MODE_MASTER_32000: Mode = Mode::Master { |  | ||||||
|     freq: MckFreq::_32MDiv21, |  | ||||||
|     ratio: Ratio::_48x, |  | ||||||
| }; // error = 254
 |  | ||||||
| pub const MODE_MASTER_44100: Mode = Mode::Master { |  | ||||||
|     freq: MckFreq::_32MDiv15, |  | ||||||
|     ratio: Ratio::_48x, |  | ||||||
| }; // error = 344
 |  | ||||||
| pub const MODE_MASTER_48000: Mode = Mode::Master { |  | ||||||
|     freq: MckFreq::_32MDiv21, |  | ||||||
|     ratio: Ratio::_32x, |  | ||||||
| }; // error = 381
 |  | ||||||
| 
 | 
 | ||||||
|  | impl From<ApproxSampleRate> for Mode { | ||||||
|  |     fn from(value: ApproxSampleRate) -> Self { | ||||||
|  |         match value { | ||||||
|  |             // error = 86
 | ||||||
|  |             ApproxSampleRate::_11025 => Mode::Master { | ||||||
|  |                 freq: MckFreq::_32MDiv15, | ||||||
|  |                 ratio: Ratio::_192x, | ||||||
|  |             }, | ||||||
|  |             // error = 127
 | ||||||
|  |             ApproxSampleRate::_16000 => Mode::Master { | ||||||
|  |                 freq: MckFreq::_32MDiv21, | ||||||
|  |                 ratio: Ratio::_96x, | ||||||
|  |             }, | ||||||
|  |             // error = 172
 | ||||||
|  |             ApproxSampleRate::_22050 => Mode::Master { | ||||||
|  |                 freq: MckFreq::_32MDiv15, | ||||||
|  |                 ratio: Ratio::_96x, | ||||||
|  |             }, | ||||||
|  |             // error = 254
 | ||||||
|  |             ApproxSampleRate::_32000 => Mode::Master { | ||||||
|  |                 freq: MckFreq::_32MDiv21, | ||||||
|  |                 ratio: Ratio::_48x, | ||||||
|  |             }, | ||||||
|  |             // error = 344
 | ||||||
|  |             ApproxSampleRate::_44100 => Mode::Master { | ||||||
|  |                 freq: MckFreq::_32MDiv15, | ||||||
|  |                 ratio: Ratio::_48x, | ||||||
|  |             }, | ||||||
|  |             // error = 381
 | ||||||
|  |             ApproxSampleRate::_48000 => Mode::Master { | ||||||
|  |                 freq: MckFreq::_32MDiv21, | ||||||
|  |                 ratio: Ratio::_32x, | ||||||
|  |             }, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl ApproxSampleRate { | ||||||
|  |     pub fn sample_rate(&self) -> u32 { | ||||||
|  |         // This will always provide a Master mode, so it is safe to unwrap.
 | ||||||
|  |         Mode::from(*self).sample_rate().unwrap() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Exact sample rates.
 | ||||||
|  | ///
 | ||||||
|  | /// Those are non standard sample rates that can be configured without error.
 | ||||||
|  | ///
 | ||||||
|  | /// For custom master clock configuration, please refer to [Mode].
 | ||||||
|  | #[derive(Clone, Copy)] | ||||||
|  | pub enum ExactSampleRate { | ||||||
|  |     _8000, | ||||||
|  |     _10582, | ||||||
|  |     _12500, | ||||||
|  |     _15625, | ||||||
|  |     _15873, | ||||||
|  |     _25000, | ||||||
|  |     _31250, | ||||||
|  |     _50000, | ||||||
|  |     _62500, | ||||||
|  |     _100000, | ||||||
|  |     _125000, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl ExactSampleRate { | ||||||
|  |     pub fn sample_rate(&self) -> u32 { | ||||||
|  |         // This will always provide a Master mode, so it is safe to unwrap.
 | ||||||
|  |         Mode::from(*self).sample_rate().unwrap() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl From<ExactSampleRate> for Mode { | ||||||
|  |     fn from(value: ExactSampleRate) -> Self { | ||||||
|  |         match value { | ||||||
|  |             ExactSampleRate::_8000 => Mode::Master { | ||||||
|  |                 freq: MckFreq::_32MDiv125, | ||||||
|  |                 ratio: Ratio::_32x, | ||||||
|  |             }, | ||||||
|  |             ExactSampleRate::_10582 => Mode::Master { | ||||||
|  |                 freq: MckFreq::_32MDiv63, | ||||||
|  |                 ratio: Ratio::_48x, | ||||||
|  |             }, | ||||||
|  |             ExactSampleRate::_12500 => Mode::Master { | ||||||
|  |                 freq: MckFreq::_32MDiv10, | ||||||
|  |                 ratio: Ratio::_256x, | ||||||
|  |             }, | ||||||
|  |             ExactSampleRate::_15625 => Mode::Master { | ||||||
|  |                 freq: MckFreq::_32MDiv32, | ||||||
|  |                 ratio: Ratio::_64x, | ||||||
|  |             }, | ||||||
|  |             ExactSampleRate::_15873 => Mode::Master { | ||||||
|  |                 freq: MckFreq::_32MDiv63, | ||||||
|  |                 ratio: Ratio::_32x, | ||||||
|  |             }, | ||||||
|  |             ExactSampleRate::_25000 => Mode::Master { | ||||||
|  |                 freq: MckFreq::_32MDiv10, | ||||||
|  |                 ratio: Ratio::_128x, | ||||||
|  |             }, | ||||||
|  |             ExactSampleRate::_31250 => Mode::Master { | ||||||
|  |                 freq: MckFreq::_32MDiv32, | ||||||
|  |                 ratio: Ratio::_32x, | ||||||
|  |             }, | ||||||
|  |             ExactSampleRate::_50000 => Mode::Master { | ||||||
|  |                 freq: MckFreq::_32MDiv10, | ||||||
|  |                 ratio: Ratio::_64x, | ||||||
|  |             }, | ||||||
|  |             ExactSampleRate::_62500 => Mode::Master { | ||||||
|  |                 freq: MckFreq::_32MDiv16, | ||||||
|  |                 ratio: Ratio::_32x, | ||||||
|  |             }, | ||||||
|  |             ExactSampleRate::_100000 => Mode::Master { | ||||||
|  |                 freq: MckFreq::_32MDiv10, | ||||||
|  |                 ratio: Ratio::_32x, | ||||||
|  |             }, | ||||||
|  |             ExactSampleRate::_125000 => Mode::Master { | ||||||
|  |                 freq: MckFreq::_32MDiv8, | ||||||
|  |                 ratio: Ratio::_32x, | ||||||
|  |             }, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// I2S configuration.
 | ||||||
| #[derive(Clone)] | #[derive(Clone)] | ||||||
| #[non_exhaustive] | #[non_exhaustive] | ||||||
| pub struct Config { | pub struct Config { | ||||||
| @ -78,7 +187,7 @@ pub struct Config { | |||||||
| impl Default for Config { | impl Default for Config { | ||||||
|     fn default() -> Self { |     fn default() -> Self { | ||||||
|         Self { |         Self { | ||||||
|             mode: MODE_MASTER_32000, |             mode: ExactSampleRate::_31250.into(), | ||||||
|             swidth: SampleWidth::_16bit, |             swidth: SampleWidth::_16bit, | ||||||
|             align: Align::Left, |             align: Align::Left, | ||||||
|             format: Format::I2S, |             format: Format::I2S, | ||||||
| @ -132,10 +241,12 @@ impl MckFreq { | |||||||
|         256000, |         256000, | ||||||
|     ]; |     ]; | ||||||
| 
 | 
 | ||||||
|  |     /// Return the value that needs to be written to the register.
 | ||||||
|     pub fn to_register_value(&self) -> u32 { |     pub fn to_register_value(&self) -> u32 { | ||||||
|         Self::REGISTER_VALUES[usize::from(*self)] |         Self::REGISTER_VALUES[usize::from(*self)] | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// Return the master clock frequency.
 | ||||||
|     pub fn to_frequency(&self) -> u32 { |     pub fn to_frequency(&self) -> u32 { | ||||||
|         Self::FREQUENCIES[usize::from(*self)] |         Self::FREQUENCIES[usize::from(*self)] | ||||||
|     } |     } | ||||||
| @ -147,7 +258,10 @@ impl From<MckFreq> for usize { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// MCK / LRCK ratio.
 | /// Master clock frequency ratio
 | ||||||
|  | ///
 | ||||||
|  | /// Sample Rate = LRCK = MCK / Ratio
 | ||||||
|  | ///
 | ||||||
| #[derive(Debug, Eq, PartialEq, Clone, Copy)] | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | ||||||
| pub enum Ratio { | pub enum Ratio { | ||||||
|     _32x, |     _32x, | ||||||
| @ -175,6 +289,7 @@ impl From<Ratio> for u8 { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Sample width.
 | ||||||
| #[derive(Debug, Eq, PartialEq, Clone, Copy)] | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | ||||||
| pub enum SampleWidth { | pub enum SampleWidth { | ||||||
|     _8bit, |     _8bit, | ||||||
| @ -188,7 +303,7 @@ impl From<SampleWidth> for u8 { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Alignment of sample within a frame.
 | /// Channel used for the most significant sample value in a frame.
 | ||||||
| #[derive(Debug, Eq, PartialEq, Clone, Copy)] | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | ||||||
| pub enum Align { | pub enum Align { | ||||||
|     Left, |     Left, | ||||||
| @ -220,11 +335,13 @@ impl From<Format> for bool { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Enable channels.
 | /// Channels
 | ||||||
| #[derive(Debug, Eq, PartialEq, Clone, Copy)] | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | ||||||
| pub enum Channels { | pub enum Channels { | ||||||
|     Stereo, |     Stereo, | ||||||
|  |     /// Mono left
 | ||||||
|     Left, |     Left, | ||||||
|  |     /// Mono right
 | ||||||
|     Right, |     Right, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -235,8 +352,6 @@ impl From<Channels> for u8 { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Interface to the I2S peripheral using EasyDMA to offload the transmission and reception workload.
 | /// Interface to the I2S peripheral using EasyDMA to offload the transmission and reception workload.
 | ||||||
| ///
 |  | ||||||
| /// For more details about EasyDMA, consult the module documentation.
 |  | ||||||
| pub struct I2S<'d, T: Instance> { | pub struct I2S<'d, T: Instance> { | ||||||
|     _p: PeripheralRef<'d, T>, |     _p: PeripheralRef<'d, T>, | ||||||
| } | } | ||||||
| @ -278,29 +393,32 @@ impl<'d, T: Instance> I2S<'d, T> { | |||||||
|     ) -> Self { |     ) -> Self { | ||||||
|         into_ref!(i2s, irq, mck, sck, lrck, sdin, sdout); |         into_ref!(i2s, irq, mck, sck, lrck, sdin, sdout); | ||||||
| 
 | 
 | ||||||
|         let r = T::regs(); |         Self::apply_config(&config); | ||||||
|         Self::apply_config(&r.config, &config); |         Self::select_pins(mck, sck, lrck, sdin, sdout); | ||||||
|         Self::select_pins(&r.psel, mck, sck, lrck, sdin, sdout); |         Self::setup_interrupt(irq); | ||||||
|         Self::setup_interrupt(irq, r); |  | ||||||
| 
 | 
 | ||||||
|         r.enable.write(|w| w.enable().enabled()); |         T::regs().enable.write(|w| w.enable().enabled()); | ||||||
| 
 | 
 | ||||||
|         Self { _p: i2s } |         Self { _p: i2s } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// I2S output only
 | ||||||
|     pub fn output(self) -> Output<'d, T> { |     pub fn output(self) -> Output<'d, T> { | ||||||
|         Output { _p: self._p } |         Output { _p: self._p } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// I2S input only
 | ||||||
|     pub fn input(self) -> Input<'d, T> { |     pub fn input(self) -> Input<'d, T> { | ||||||
|         Input { _p: self._p } |         Input { _p: self._p } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /// I2S full duplex (input and output)
 | ||||||
|     pub fn full_duplex(self) -> FullDuplex<'d, T> { |     pub fn full_duplex(self) -> FullDuplex<'d, T> { | ||||||
|         FullDuplex { _p: self._p } |         FullDuplex { _p: self._p } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn apply_config(c: &CONFIG, config: &Config) { |     fn apply_config(config: &Config) { | ||||||
|  |         let c = &T::regs().config; | ||||||
|         match config.mode { |         match config.mode { | ||||||
|             Mode::Master { freq, ratio } => { |             Mode::Master { freq, ratio } => { | ||||||
|                 c.mode.write(|w| w.mode().master()); |                 c.mode.write(|w| w.mode().master()); | ||||||
| @ -322,13 +440,14 @@ impl<'d, T: Instance> I2S<'d, T> { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn select_pins( |     fn select_pins( | ||||||
|         psel: &PSEL, |  | ||||||
|         mck: PeripheralRef<'d, AnyPin>, |         mck: PeripheralRef<'d, AnyPin>, | ||||||
|         sck: PeripheralRef<'d, AnyPin>, |         sck: PeripheralRef<'d, AnyPin>, | ||||||
|         lrck: PeripheralRef<'d, AnyPin>, |         lrck: PeripheralRef<'d, AnyPin>, | ||||||
|         sdin: PeripheralRef<'d, AnyPin>, |         sdin: PeripheralRef<'d, AnyPin>, | ||||||
|         sdout: PeripheralRef<'d, AnyPin>, |         sdout: PeripheralRef<'d, AnyPin>, | ||||||
|     ) { |     ) { | ||||||
|  |         let psel = &T::regs().psel; | ||||||
|  | 
 | ||||||
|         psel.mck.write(|w| { |         psel.mck.write(|w| { | ||||||
|             unsafe { w.bits(mck.psel_bits()) }; |             unsafe { w.bits(mck.psel_bits()) }; | ||||||
|             w.connect().connected() |             w.connect().connected() | ||||||
| @ -355,21 +474,23 @@ impl<'d, T: Instance> I2S<'d, T> { | |||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn setup_interrupt(irq: PeripheralRef<'d, T::Interrupt>, r: &RegisterBlock) { |     fn setup_interrupt(irq: PeripheralRef<'d, T::Interrupt>) { | ||||||
|         irq.set_handler(Self::on_interrupt); |         irq.set_handler(Self::on_interrupt); | ||||||
|         // irq.set_priority(Priority::P1); // TODO review priorities
 |  | ||||||
|         irq.unpend(); |         irq.unpend(); | ||||||
|         irq.enable(); |         irq.enable(); | ||||||
| 
 | 
 | ||||||
|         let device = Device::<T>::new(); |         let device = Device::<T>::new(); | ||||||
|         device.disable_tx_ptr_interrupt(); |         device.disable_tx_ptr_interrupt(); | ||||||
|         device.disable_rx_ptr_interrupt(); |         device.disable_rx_ptr_interrupt(); | ||||||
|  |         device.disable_stopped_interrupt(); | ||||||
| 
 | 
 | ||||||
|         device.reset_tx_ptr_event(); |         device.reset_tx_ptr_event(); | ||||||
|         device.reset_rx_ptr_event(); |         device.reset_rx_ptr_event(); | ||||||
|  |         device.reset_stopped_event(); | ||||||
| 
 | 
 | ||||||
|         device.enable_tx_ptr_interrupt(); |         device.enable_tx_ptr_interrupt(); | ||||||
|         device.enable_rx_ptr_interrupt(); |         device.enable_rx_ptr_interrupt(); | ||||||
|  |         device.enable_stopped_interrupt(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn on_interrupt(_: *mut ()) { |     fn on_interrupt(_: *mut ()) { | ||||||
| @ -387,41 +508,40 @@ impl<'d, T: Instance> I2S<'d, T> { | |||||||
|             s.rx_waker.wake(); |             s.rx_waker.wake(); | ||||||
|             device.disable_rx_ptr_interrupt(); |             device.disable_rx_ptr_interrupt(); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         if device.is_stopped() { | ||||||
|  |             trace!("STOPPED INT"); | ||||||
|  |             s.stop_waker.wake(); | ||||||
|  |             device.disable_stopped_interrupt(); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| pub struct Output<'d, T: Instance> { |     async fn stop() { | ||||||
|     _p: PeripheralRef<'d, T>, |         compiler_fence(Ordering::SeqCst); | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<'d, T: Instance> Output<'d, T> { |  | ||||||
|     /// Starts I2S transfer.
 |  | ||||||
|     #[inline(always)] |  | ||||||
|     pub fn start<B>(&self, buffer: B) -> Result<(), Error> |  | ||||||
|     where |  | ||||||
|         B: Buffer, |  | ||||||
|     { |  | ||||||
|         // TODO what to do if it is started already?
 |  | ||||||
| 
 | 
 | ||||||
|         let device = Device::<T>::new(); |         let device = Device::<T>::new(); | ||||||
|         device.enable(); |         device.stop(); | ||||||
|         device.set_tx_buffer(buffer)?; |  | ||||||
|         device.enable_tx(); |  | ||||||
|         device.start(); |  | ||||||
| 
 | 
 | ||||||
|         Ok(()) |         T::state().started.store(false, Ordering::Relaxed); | ||||||
|  | 
 | ||||||
|  |         poll_fn(|cx| { | ||||||
|  |             T::state().stop_waker.register(cx.waker()); | ||||||
|  | 
 | ||||||
|  |             if device.is_stopped() { | ||||||
|  |                 trace!("STOP: Ready"); | ||||||
|  |                 device.reset_stopped_event(); | ||||||
|  |                 Poll::Ready(()) | ||||||
|  |             } else { | ||||||
|  |                 trace!("STOP: Pending"); | ||||||
|  |                 Poll::Pending | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |         .await; | ||||||
|  | 
 | ||||||
|  |         device.disable(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Stops the I2S transfer and waits until it has stopped.
 |     async fn send<B>(buffer: B) -> Result<(), Error> | ||||||
|     #[inline(always)] |  | ||||||
|     pub async fn stop(&self) { |  | ||||||
|         todo!() |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// Transmits the given `buffer`.
 |  | ||||||
|     /// Buffer address must be 4 byte aligned and located in RAM.
 |  | ||||||
|     #[allow(unused_mut)] |  | ||||||
|     pub async fn send<B>(&mut self, buffer: B) -> Result<(), Error> |  | ||||||
|     where |     where | ||||||
|         B: Buffer, |         B: Buffer, | ||||||
|     { |     { | ||||||
| @ -454,24 +574,191 @@ impl<'d, T: Instance> Output<'d, T> { | |||||||
| 
 | 
 | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     async fn receive<B>(buffer: B) -> Result<(), Error> | ||||||
|  |     where | ||||||
|  |         B: Buffer, | ||||||
|  |     { | ||||||
|  |         trace!("RECEIVE: {}", buffer.bytes_ptr() as u32); | ||||||
|  | 
 | ||||||
|  |         let device = Device::<T>::new(); | ||||||
|  |         let drop = device.on_rx_drop(); | ||||||
|  | 
 | ||||||
|  |         compiler_fence(Ordering::SeqCst); | ||||||
|  | 
 | ||||||
|  |         poll_fn(|cx| { | ||||||
|  |             T::state().rx_waker.register(cx.waker()); | ||||||
|  | 
 | ||||||
|  |             if device.is_rx_ptr_updated() { | ||||||
|  |                 trace!("RX POLL: Ready"); | ||||||
|  |                 device.reset_rx_ptr_event(); | ||||||
|  |                 device.enable_rx_ptr_interrupt(); | ||||||
|  |                 Poll::Ready(()) | ||||||
|  |             } else { | ||||||
|  |                 trace!("RX POLL: Pending"); | ||||||
|  |                 Poll::Pending | ||||||
|  |             } | ||||||
|  |         }) | ||||||
|  |         .await; | ||||||
|  | 
 | ||||||
|  |         device.set_rx_buffer(buffer)?; | ||||||
|  | 
 | ||||||
|  |         compiler_fence(Ordering::SeqCst); | ||||||
|  |         drop.defuse(); | ||||||
|  | 
 | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// I2S output
 | ||||||
|  | pub struct Output<'d, T: Instance> { | ||||||
|  |     _p: PeripheralRef<'d, T>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'d, T: Instance> Output<'d, T> { | ||||||
|  |     /// Prepare the initial buffer and start the I2S transfer.
 | ||||||
|  |     pub async fn start<B>(&self, buffer: B) -> Result<(), Error> | ||||||
|  |     where | ||||||
|  |         B: Buffer, | ||||||
|  |     { | ||||||
|  |         let device = Device::<T>::new(); | ||||||
|  | 
 | ||||||
|  |         let s = T::state(); | ||||||
|  |         if s.started.load(Ordering::Relaxed) { | ||||||
|  |             self.stop().await; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         device.enable(); | ||||||
|  |         device.enable_tx(); | ||||||
|  |         device.set_tx_buffer(buffer)?; | ||||||
|  | 
 | ||||||
|  |         s.started.store(true, Ordering::Relaxed); | ||||||
|  | 
 | ||||||
|  |         device.start(); | ||||||
|  | 
 | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Stops the I2S transfer and waits until it has stopped.
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub async fn stop(&self) { | ||||||
|  |         I2S::<T>::stop().await | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Sets the given `buffer` for transmission in the DMA.
 | ||||||
|  |     /// Buffer address must be 4 byte aligned and located in RAM.
 | ||||||
|  |     /// The buffer must not be written while being used by the DMA,
 | ||||||
|  |     /// which takes two other `send`s being awaited.
 | ||||||
|  |     #[allow(unused_mut)] | ||||||
|  |     pub async fn send<B>(&mut self, buffer: B) -> Result<(), Error> | ||||||
|  |     where | ||||||
|  |         B: Buffer, | ||||||
|  |     { | ||||||
|  |         I2S::<T>::send(buffer).await | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// I2S input
 | ||||||
| pub struct Input<'d, T: Instance> { | pub struct Input<'d, T: Instance> { | ||||||
|     _p: PeripheralRef<'d, T>, |     _p: PeripheralRef<'d, T>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<'d, T: Instance> Input<'d, T> { | impl<'d, T: Instance> Input<'d, T> { | ||||||
|     // TODO
 |     /// Prepare the initial buffer and start the I2S transfer.
 | ||||||
|  |     pub async fn start<B>(&self, buffer: B) -> Result<(), Error> | ||||||
|  |     where | ||||||
|  |         B: Buffer, | ||||||
|  |     { | ||||||
|  |         let device = Device::<T>::new(); | ||||||
|  | 
 | ||||||
|  |         let s = T::state(); | ||||||
|  |         if s.started.load(Ordering::Relaxed) { | ||||||
|  |             self.stop().await; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         device.enable(); | ||||||
|  |         device.enable_rx(); | ||||||
|  |         device.set_rx_buffer(buffer)?; | ||||||
|  | 
 | ||||||
|  |         s.started.store(true, Ordering::Relaxed); | ||||||
|  | 
 | ||||||
|  |         device.start(); | ||||||
|  | 
 | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Stops the I2S transfer and waits until it has stopped.
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub async fn stop(&self) { | ||||||
|  |         I2S::<T>::stop().await | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Sets the given `buffer` for reception from the DMA.
 | ||||||
|  |     /// Buffer address must be 4 byte aligned and located in RAM.
 | ||||||
|  |     /// The buffer must not be read while being used by the DMA,
 | ||||||
|  |     /// which takes two other `receive`s being awaited.
 | ||||||
|  |     #[allow(unused_mut)] | ||||||
|  |     pub async fn receive<B>(&mut self, buffer: B) -> Result<(), Error> | ||||||
|  |     where | ||||||
|  |         B: Buffer, | ||||||
|  |     { | ||||||
|  |         I2S::<T>::receive(buffer).await | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// I2S ful duplex (input & output)
 | ||||||
| pub struct FullDuplex<'d, T: Instance> { | pub struct FullDuplex<'d, T: Instance> { | ||||||
|     _p: PeripheralRef<'d, T>, |     _p: PeripheralRef<'d, T>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<'d, T: Instance> FullDuplex<'d, T> { | impl<'d, T: Instance> FullDuplex<'d, T> { | ||||||
|     // TODO
 |     /// Prepare the initial buffers and start the I2S transfer.
 | ||||||
|  |     pub async fn start<B>(&self, buffer_out: B, buffer_in: B) -> Result<(), Error> | ||||||
|  |     where | ||||||
|  |         B: Buffer, | ||||||
|  |     { | ||||||
|  |         let device = Device::<T>::new(); | ||||||
|  | 
 | ||||||
|  |         let s = T::state(); | ||||||
|  |         if s.started.load(Ordering::Relaxed) { | ||||||
|  |             self.stop().await; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         device.enable(); | ||||||
|  |         device.enable_tx(); | ||||||
|  |         device.enable_rx(); | ||||||
|  |         device.set_tx_buffer(buffer_out)?; | ||||||
|  |         device.set_rx_buffer(buffer_in)?; | ||||||
|  | 
 | ||||||
|  |         s.started.store(true, Ordering::Relaxed); | ||||||
|  | 
 | ||||||
|  |         device.start(); | ||||||
|  | 
 | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Stops the I2S transfer and waits until it has stopped.
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     pub async fn stop(&self) { | ||||||
|  |         I2S::<T>::stop().await | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Sets the given `buffer_out` and `buffer_in` for transmission/reception from the DMA.
 | ||||||
|  |     /// Buffer address must be 4 byte aligned and located in RAM.
 | ||||||
|  |     /// The buffers must not be written/read while being used by the DMA,
 | ||||||
|  |     /// which takes two other `send_and_receive` operations being awaited.
 | ||||||
|  |     #[allow(unused_mut)] | ||||||
|  |     pub async fn send_and_receive<B>(&mut self, buffer_out: B, buffer_in: B) -> Result<(), Error> | ||||||
|  |     where | ||||||
|  |         B: Buffer, | ||||||
|  |     { | ||||||
|  |         I2S::<T>::send(buffer_out).await?; | ||||||
|  |         I2S::<T>::receive(buffer_in).await?; | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Helper encapsulating common I2S device operations.
 | ||||||
| struct Device<T>(&'static RegisterBlock, PhantomData<T>); | struct Device<T>(&'static RegisterBlock, PhantomData<T>); | ||||||
| 
 | 
 | ||||||
| impl<T: Instance> Device<T> { | impl<T: Instance> Device<T> { | ||||||
| @ -521,6 +808,34 @@ impl<T: Instance> Device<T> { | |||||||
|         self.0.tasks_start.write(|w| unsafe { w.bits(1) }); |         self.0.tasks_start.write(|w| unsafe { w.bits(1) }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     fn stop(&self) { | ||||||
|  |         self.0.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     fn is_stopped(&self) -> bool { | ||||||
|  |         self.0.events_stopped.read().bits() != 0 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     fn reset_stopped_event(&self) { | ||||||
|  |         trace!("STOPPED EVENT: Reset"); | ||||||
|  |         self.0.events_stopped.reset(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     fn disable_stopped_interrupt(&self) { | ||||||
|  |         trace!("STOPPED INTERRUPT: Disabled"); | ||||||
|  |         self.0.intenclr.write(|w| w.stopped().clear()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     fn enable_stopped_interrupt(&self) { | ||||||
|  |         trace!("STOPPED INTERRUPT: Enabled"); | ||||||
|  |         self.0.intenset.write(|w| w.stopped().set()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     #[inline] |     #[inline] | ||||||
|     fn set_tx_buffer<B>(&self, buffer: B) -> Result<(), Error> |     fn set_tx_buffer<B>(&self, buffer: B) -> Result<(), Error> | ||||||
|     where |     where | ||||||
| @ -606,6 +921,23 @@ impl<T: Instance> Device<T> { | |||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     #[inline] | ||||||
|  |     fn on_rx_drop(&self) -> OnDrop<fn()> { | ||||||
|  |         OnDrop::new(move || { | ||||||
|  |             trace!("RX DROP: Stopping"); | ||||||
|  | 
 | ||||||
|  |             let device = Device::<T>::new(); | ||||||
|  |             device.disable_rx_ptr_interrupt(); | ||||||
|  |             device.reset_rx_ptr_event(); | ||||||
|  |             device.disable_rx(); | ||||||
|  | 
 | ||||||
|  |             // TX is stopped almost instantly, spinning is fine.
 | ||||||
|  |             while !device.is_rx_ptr_updated() {} | ||||||
|  | 
 | ||||||
|  |             trace!("RX DROP: Stopped"); | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     fn validate_buffer<B>(buffer: B) -> Result<(u32, u32), Error> |     fn validate_buffer<B>(buffer: B) -> Result<(u32, u32), Error> | ||||||
|     where |     where | ||||||
|         B: Buffer, |         B: Buffer, | ||||||
| @ -632,6 +964,56 @@ impl<T: Instance> Device<T> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Sample details
 | ||||||
|  | pub trait Sample: Sized + Copy + Default { | ||||||
|  |     const WIDTH: usize; | ||||||
|  |     const SCALE: Self; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Sample for i8 { | ||||||
|  |     const WIDTH: usize = 8; | ||||||
|  |     const SCALE: Self = 1 << (Self::WIDTH - 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Sample for i16 { | ||||||
|  |     const WIDTH: usize = 16; | ||||||
|  |     const SCALE: Self = 1 << (Self::WIDTH - 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Sample for i32 { | ||||||
|  |     const WIDTH: usize = 24; | ||||||
|  |     const SCALE: Self = 1 << (Self::WIDTH - 1); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// A 4-bytes aligned [Buffer].
 | ||||||
|  | #[repr(align(4))] | ||||||
|  | pub struct AlignedBuffer<T: Sample, const N: usize>([T; N]); | ||||||
|  | 
 | ||||||
|  | impl<T: Sample, const N: usize> AlignedBuffer<T, N> { | ||||||
|  |     pub fn new(array: [T; N]) -> Self { | ||||||
|  |         Self(array) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: Sample, const N: usize> Default for AlignedBuffer<T, N> { | ||||||
|  |     fn default() -> Self { | ||||||
|  |         Self([T::default(); N]) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: Sample, const N: usize> AsRef<[T]> for AlignedBuffer<T, N> { | ||||||
|  |     fn as_ref(&self) -> &[T] { | ||||||
|  |         self.0.as_slice() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<T: Sample, const N: usize> AsMut<[T]> for AlignedBuffer<T, N> { | ||||||
|  |     fn as_mut(&mut self) -> &mut [T] { | ||||||
|  |         self.0.as_mut_slice() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Common operations required for a buffer to be used by the DMA
 | ||||||
| pub trait Buffer: Sized { | pub trait Buffer: Sized { | ||||||
|     fn bytes_ptr(&self) -> *const u8; |     fn bytes_ptr(&self) -> *const u8; | ||||||
|     fn bytes_len(&self) -> usize; |     fn bytes_len(&self) -> usize; | ||||||
| @ -674,22 +1056,25 @@ impl Buffer for &[i32] { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub(crate) mod sealed { | pub(crate) mod sealed { | ||||||
|     use core::sync::atomic::AtomicI32; |     use core::sync::atomic::AtomicBool; | ||||||
| 
 | 
 | ||||||
|     use embassy_sync::waitqueue::AtomicWaker; |     use embassy_sync::waitqueue::AtomicWaker; | ||||||
| 
 | 
 | ||||||
|     use super::*; |     /// Peripheral static state
 | ||||||
| 
 |  | ||||||
|     pub struct State { |     pub struct State { | ||||||
|  |         pub started: AtomicBool, | ||||||
|         pub rx_waker: AtomicWaker, |         pub rx_waker: AtomicWaker, | ||||||
|         pub tx_waker: AtomicWaker, |         pub tx_waker: AtomicWaker, | ||||||
|  |         pub stop_waker: AtomicWaker, | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     impl State { |     impl State { | ||||||
|         pub const fn new() -> Self { |         pub const fn new() -> Self { | ||||||
|             Self { |             Self { | ||||||
|  |                 started: AtomicBool::new(false), | ||||||
|                 rx_waker: AtomicWaker::new(), |                 rx_waker: AtomicWaker::new(), | ||||||
|                 tx_waker: AtomicWaker::new(), |                 tx_waker: AtomicWaker::new(), | ||||||
|  |                 stop_waker: AtomicWaker::new(), | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -704,8 +1089,6 @@ pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | |||||||
|     type Interrupt: Interrupt; |     type Interrupt: Interrupt; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // TODO: Unsure why this macro is flagged as unused by CI when in fact it's used elsewhere?
 |  | ||||||
| #[allow(unused_macros)] |  | ||||||
| macro_rules! impl_i2s { | macro_rules! impl_i2s { | ||||||
|     ($type:ident, $pac_type:ident, $irq:ident) => { |     ($type:ident, $pac_type:ident, $irq:ident) => { | ||||||
|         impl crate::i2s::sealed::Instance for peripherals::$type { |         impl crate::i2s::sealed::Instance for peripherals::$type { | ||||||
|  | |||||||
| @ -4,59 +4,41 @@ | |||||||
| 
 | 
 | ||||||
| use core::f32::consts::PI; | use core::f32::consts::PI; | ||||||
| 
 | 
 | ||||||
| use defmt::{error, info, trace}; | use defmt::{error, info}; | ||||||
| use embassy_executor::Spawner; | use embassy_executor::Spawner; | ||||||
| use embassy_nrf::gpio::{Input, Pin, Pull}; | use embassy_nrf::i2s::{self, Sample as _}; | ||||||
| use embassy_nrf::i2s::{Channels, MckFreq, Mode, Ratio, SampleWidth, MODE_MASTER_32000}; | use embassy_nrf::interrupt; | ||||||
| use embassy_nrf::pac::ficr::info; |  | ||||||
| use embassy_nrf::{i2s, interrupt}; |  | ||||||
| use {defmt_rtt as _, panic_probe as _}; | use {defmt_rtt as _, panic_probe as _}; | ||||||
| 
 | 
 | ||||||
| #[repr(align(4))] |  | ||||||
| pub struct AlignedBuffer<T: ?Sized>(T); |  | ||||||
| 
 |  | ||||||
| impl<T> AsRef<T> for AlignedBuffer<T> { |  | ||||||
|     fn as_ref(&self) -> &T { |  | ||||||
|         &self.0 |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<T> AsMut<T> for AlignedBuffer<T> { |  | ||||||
|     fn as_mut(&mut self) -> &mut T { |  | ||||||
|         &mut self.0 |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #[embassy_executor::main] | #[embassy_executor::main] | ||||||
| async fn main(_spawner: Spawner) { | async fn main(_spawner: Spawner) { | ||||||
|     let p = embassy_nrf::init(Default::default()); |     let p = embassy_nrf::init(Default::default()); | ||||||
|  | 
 | ||||||
|     let mut config = i2s::Config::default(); |     let mut config = i2s::Config::default(); | ||||||
|     config.mode = MODE_MASTER_32000; |     config.mode = i2s::ExactSampleRate::_50000.into(); | ||||||
|     // config.mode = Mode::Master {
 |     config.channels = i2s::Channels::Left; | ||||||
|     //     freq: MckFreq::_32MDiv10,
 |     config.swidth = i2s::SampleWidth::_16bit; | ||||||
|     //     ratio: Ratio::_256x,
 |  | ||||||
|     // }; // 12500 Hz
 |  | ||||||
|     config.channels = Channels::Left; |  | ||||||
|     config.swidth = SampleWidth::_16bit; |  | ||||||
|     let sample_rate = config.mode.sample_rate().expect("I2S Master"); |     let sample_rate = config.mode.sample_rate().expect("I2S Master"); | ||||||
|     let inv_sample_rate = 1.0 / sample_rate as f32; |     let inv_sample_rate = 1.0 / sample_rate as f32; | ||||||
| 
 | 
 | ||||||
|     info!("Sample rate: {}", sample_rate); |     info!("Sample rate: {}", sample_rate); | ||||||
| 
 | 
 | ||||||
|     // Wait for a button press
 |     // Wait for a button press
 | ||||||
|  |     // use embassy_nrf::gpio::{Input, Pin, Pull};
 | ||||||
|     // let mut btn1 = Input::new(p.P1_00.degrade(), Pull::Up);
 |     // let mut btn1 = Input::new(p.P1_00.degrade(), Pull::Up);
 | ||||||
|     // btn1.wait_for_low().await;
 |     // btn1.wait_for_low().await;
 | ||||||
| 
 | 
 | ||||||
|     let irq = interrupt::take!(I2S); |     let irq = interrupt::take!(I2S); | ||||||
|     let mut i2s = i2s::I2S::new(p.I2S, irq, p.P0_28, p.P0_29, p.P0_31, p.P0_11, p.P0_30, config).output(); |     let mut i2s = i2s::I2S::new(p.I2S, irq, p.P0_28, p.P0_29, p.P0_31, p.P0_27, p.P0_30, config) | ||||||
|  |         .output(); | ||||||
| 
 | 
 | ||||||
|     type Sample = i16; |     type Sample = i16; | ||||||
|     const MAX_UNIPOLAR_VALUE: Sample = (1 << 15) as Sample; |     const NUM_SAMPLES: usize = 6000; | ||||||
|     const NUM_SAMPLES: usize = 2000; | 
 | ||||||
|     let mut buffers: [AlignedBuffer<[Sample; NUM_SAMPLES]>; 3] = [ |     let mut buffers: [i2s::AlignedBuffer<Sample, NUM_SAMPLES>; 3] = [ | ||||||
|         AlignedBuffer([0; NUM_SAMPLES]), |         i2s::AlignedBuffer::default(), | ||||||
|         AlignedBuffer([0; NUM_SAMPLES]), |         i2s::AlignedBuffer::default(), | ||||||
|         AlignedBuffer([0; NUM_SAMPLES]), |         i2s::AlignedBuffer::default(), | ||||||
|     ]; |     ]; | ||||||
| 
 | 
 | ||||||
|     let mut carrier = SineOsc::new(); |     let mut carrier = SineOsc::new(); | ||||||
| @ -66,32 +48,29 @@ async fn main(_spawner: Spawner) { | |||||||
|     freq_mod.set_amplitude(1.0); |     freq_mod.set_amplitude(1.0); | ||||||
| 
 | 
 | ||||||
|     let mut amp_mod = SineOsc::new(); |     let mut amp_mod = SineOsc::new(); | ||||||
|     amp_mod.set_frequency(4.0, inv_sample_rate); |     amp_mod.set_frequency(16.0, inv_sample_rate); | ||||||
|     amp_mod.set_amplitude(0.5); |     amp_mod.set_amplitude(0.5); | ||||||
| 
 | 
 | ||||||
|     let mut generate = |buf: &mut [Sample]| { |     let mut generate = |buf: &mut [Sample]| { | ||||||
|         let ptr = buf as *const [Sample] as *const Sample as u32; |         for sample in &mut buf.chunks_mut(1) { | ||||||
|         trace!("GEN: {}", ptr); |  | ||||||
| 
 |  | ||||||
|         for sample in &mut buf.as_mut().chunks_mut(1) { |  | ||||||
|             let signal = carrier.generate(); |  | ||||||
|             let freq_modulation = bipolar_to_unipolar(freq_mod.generate()); |             let freq_modulation = bipolar_to_unipolar(freq_mod.generate()); | ||||||
|             carrier.set_frequency(220.0 + 220.0 * freq_modulation, inv_sample_rate); |             carrier.set_frequency(220.0 + 440.0 * freq_modulation, inv_sample_rate); | ||||||
|             let amp_modulation = bipolar_to_unipolar(amp_mod.generate()); |             let amp_modulation = bipolar_to_unipolar(amp_mod.generate()); | ||||||
|             carrier.set_amplitude(amp_modulation); |             carrier.set_amplitude(amp_modulation); | ||||||
|             let value = (MAX_UNIPOLAR_VALUE as f32 * signal) as Sample; |             let signal = carrier.generate(); | ||||||
|  |             let value = (Sample::SCALE as f32 * signal) as Sample; | ||||||
|             sample[0] = value; |             sample[0] = value; | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     generate(buffers[0].as_mut().as_mut_slice()); |     generate(buffers[0].as_mut()); | ||||||
|     generate(buffers[1].as_mut().as_mut_slice()); |     generate(buffers[1].as_mut()); | ||||||
| 
 | 
 | ||||||
|     i2s.start(buffers[0].as_ref().as_slice()).expect("I2S Start"); |     i2s.start(buffers[0].as_ref()).await.expect("I2S Start"); | ||||||
| 
 | 
 | ||||||
|     let mut index = 1; |     let mut index = 1; | ||||||
|     loop { |     loop { | ||||||
|         if let Err(err) = i2s.send(buffers[index].as_ref().as_slice()).await { |         if let Err(err) = i2s.send(buffers[index].as_ref()).await { | ||||||
|             error!("{}", err); |             error!("{}", err); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -99,7 +78,7 @@ async fn main(_spawner: Spawner) { | |||||||
|         if index >= 3 { |         if index >= 3 { | ||||||
|             index = 0; |             index = 0; | ||||||
|         } |         } | ||||||
|         generate(buffers[index].as_mut().as_mut_slice()); |         generate(buffers[index].as_mut()); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user