diff options
| author | Christian Perez Llamas <[email protected]> | 2022-11-19 00:29:05 +0100 |
|---|---|---|
| committer | Christian Perez Llamas <[email protected]> | 2022-11-19 00:29:05 +0100 |
| commit | 6b88057aef79e32a66c9c99cf048f905d10c2d3a (patch) | |
| tree | 6c7889cc365efa5aa7d15b21ef6e797ae9e0841c | |
| parent | 1ed260b1055fad6ddd89053ae3e1997ec34c6332 (diff) | |
Add missing parts and Cleanup
| -rw-r--r-- | embassy-nrf/src/i2s.rs | 549 | ||||
| -rw-r--r-- | examples/nrf/src/bin/i2s-generate.rs (renamed from examples/nrf/src/bin/i2s.rs) | 73 |
2 files changed, 492 insertions, 130 deletions
diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs index e6dfb690c..53d9f9a1b 100644 --- a/embassy-nrf/src/i2s.rs +++ b/embassy-nrf/src/i2s.rs | |||
| @@ -1,27 +1,27 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | 2 | ||
| 3 | //! I2S | 3 | //! Support for I2S audio |
| 4 | 4 | ||
| 5 | use core::future::poll_fn; | 5 | use core::future::poll_fn; |
| 6 | use core::marker::PhantomData; | 6 | use core::marker::PhantomData; |
| 7 | use core::sync::atomic::{compiler_fence, Ordering}; | 7 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 8 | use core::task::Poll; | 8 | use core::task::Poll; |
| 9 | 9 | ||
| 10 | use embassy_cortex_m::interrupt::{InterruptExt, Priority}; | 10 | use embassy_cortex_m::interrupt::InterruptExt; |
| 11 | use embassy_hal_common::drop::OnDrop; | 11 | use embassy_hal_common::drop::OnDrop; |
| 12 | use embassy_hal_common::{into_ref, PeripheralRef}; | 12 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 13 | 13 | ||
| 14 | use crate::gpio::{AnyPin, Pin as GpioPin}; | 14 | use crate::gpio::{AnyPin, Pin as GpioPin}; |
| 15 | use crate::interrupt::Interrupt; | 15 | use crate::interrupt::Interrupt; |
| 16 | use crate::pac::i2s::{RegisterBlock, CONFIG, PSEL}; | 16 | use crate::pac::i2s::RegisterBlock; |
| 17 | use crate::Peripheral; | 17 | use crate::Peripheral; |
| 18 | 18 | ||
| 19 | // TODO: Define those in lib.rs somewhere else | 19 | // TODO: Define those in lib.rs somewhere else |
| 20 | // | 20 | |
| 21 | // I2S EasyDMA MAXCNT bit length = 14 | 21 | /// I2S EasyDMA MAXCNT bit length = 14 |
| 22 | const MAX_DMA_MAXCNT: u32 = 1 << 14; | 22 | const MAX_DMA_MAXCNT: u32 = 1 << 14; |
| 23 | 23 | ||
| 24 | // Limits for Easy DMA - it can only read from data ram | 24 | /// Limits for Easy DMA - it can only read from data ram |
| 25 | pub const SRAM_LOWER: usize = 0x2000_0000; | 25 | pub const SRAM_LOWER: usize = 0x2000_0000; |
| 26 | pub const SRAM_UPPER: usize = 0x3000_0000; | 26 | pub const SRAM_UPPER: usize = 0x3000_0000; |
| 27 | 27 | ||
| @@ -36,35 +36,144 @@ pub enum Error { | |||
| 36 | BufferLengthMisaligned, | 36 | BufferLengthMisaligned, |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | pub const MODE_MASTER_8000: Mode = Mode::Master { | 39 | /// Approximate sample rates. |
| 40 | freq: MckFreq::_32MDiv125, | 40 | /// |
| 41 | ratio: Ratio::_32x, | 41 | /// Those are common sample rates that can not be configured without an small error. |
| 42 | }; // error = 0 | 42 | /// |
| 43 | pub const MODE_MASTER_11025: Mode = Mode::Master { | 43 | /// For custom master clock configuration, please refer to [Mode]. |
| 44 | freq: MckFreq::_32MDiv15, | 44 | #[derive(Clone, Copy)] |
| 45 | ratio: Ratio::_192x, | 45 | pub enum ApproxSampleRate { |
| 46 | }; // error = 86 | 46 | _11025, |
| 47 | pub const MODE_MASTER_16000: Mode = Mode::Master { | 47 | _16000, |
| 48 | freq: MckFreq::_32MDiv21, | 48 | _22050, |
| 49 | ratio: Ratio::_96x, | 49 | _32000, |
| 50 | }; // error = 127 | 50 | _44100, |
| 51 | pub const MODE_MASTER_22050: Mode = Mode::Master { | 51 | _48000, |
| 52 | freq: MckFreq::_32MDiv15, | 52 | } |
| 53 | ratio: Ratio::_96x, | 53 | |
| 54 | }; // error = 172 | 54 | impl From<ApproxSampleRate> for Mode { |
| 55 | pub const MODE_MASTER_32000: Mode = Mode::Master { | 55 | fn from(value: ApproxSampleRate) -> Self { |
| 56 | freq: MckFreq::_32MDiv21, | 56 | match value { |
| 57 | ratio: Ratio::_48x, | 57 | // error = 86 |
| 58 | }; // error = 254 | 58 | ApproxSampleRate::_11025 => Mode::Master { |
| 59 | pub const MODE_MASTER_44100: Mode = Mode::Master { | 59 | freq: MckFreq::_32MDiv15, |
| 60 | freq: MckFreq::_32MDiv15, | 60 | ratio: Ratio::_192x, |
| 61 | ratio: Ratio::_48x, | 61 | }, |
| 62 | }; // error = 344 | 62 | // error = 127 |
| 63 | pub const MODE_MASTER_48000: Mode = Mode::Master { | 63 | ApproxSampleRate::_16000 => Mode::Master { |
| 64 | freq: MckFreq::_32MDiv21, | 64 | freq: MckFreq::_32MDiv21, |
| 65 | ratio: Ratio::_32x, | 65 | ratio: Ratio::_96x, |
| 66 | }; // error = 381 | 66 | }, |
| 67 | // error = 172 | ||
| 68 | ApproxSampleRate::_22050 => Mode::Master { | ||
| 69 | freq: MckFreq::_32MDiv15, | ||
| 70 | ratio: Ratio::_96x, | ||
| 71 | }, | ||
| 72 | // error = 254 | ||
| 73 | ApproxSampleRate::_32000 => Mode::Master { | ||
| 74 | freq: MckFreq::_32MDiv21, | ||
| 75 | ratio: Ratio::_48x, | ||
| 76 | }, | ||
| 77 | // error = 344 | ||
| 78 | ApproxSampleRate::_44100 => Mode::Master { | ||
| 79 | freq: MckFreq::_32MDiv15, | ||
| 80 | ratio: Ratio::_48x, | ||
| 81 | }, | ||
| 82 | // error = 381 | ||
| 83 | ApproxSampleRate::_48000 => Mode::Master { | ||
| 84 | freq: MckFreq::_32MDiv21, | ||
| 85 | ratio: Ratio::_32x, | ||
| 86 | }, | ||
| 87 | } | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | impl ApproxSampleRate { | ||
| 92 | pub fn sample_rate(&self) -> u32 { | ||
| 93 | // This will always provide a Master mode, so it is safe to unwrap. | ||
| 94 | Mode::from(*self).sample_rate().unwrap() | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | /// Exact sample rates. | ||
| 99 | /// | ||
| 100 | /// Those are non standard sample rates that can be configured without error. | ||
| 101 | /// | ||
| 102 | /// For custom master clock configuration, please refer to [Mode]. | ||
| 103 | #[derive(Clone, Copy)] | ||
| 104 | pub enum ExactSampleRate { | ||
| 105 | _8000, | ||
| 106 | _10582, | ||
| 107 | _12500, | ||
| 108 | _15625, | ||
| 109 | _15873, | ||
| 110 | _25000, | ||
| 111 | _31250, | ||
| 112 | _50000, | ||
| 113 | _62500, | ||
| 114 | _100000, | ||
| 115 | _125000, | ||
| 116 | } | ||
| 67 | 117 | ||
| 118 | impl ExactSampleRate { | ||
| 119 | pub fn sample_rate(&self) -> u32 { | ||
| 120 | // This will always provide a Master mode, so it is safe to unwrap. | ||
| 121 | Mode::from(*self).sample_rate().unwrap() | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | impl From<ExactSampleRate> for Mode { | ||
| 126 | fn from(value: ExactSampleRate) -> Self { | ||
| 127 | match value { | ||
| 128 | ExactSampleRate::_8000 => Mode::Master { | ||
| 129 | freq: MckFreq::_32MDiv125, | ||
| 130 | ratio: Ratio::_32x, | ||
| 131 | }, | ||
| 132 | ExactSampleRate::_10582 => Mode::Master { | ||
| 133 | freq: MckFreq::_32MDiv63, | ||
| 134 | ratio: Ratio::_48x, | ||
| 135 | }, | ||
| 136 | ExactSampleRate::_12500 => Mode::Master { | ||
| 137 | freq: MckFreq::_32MDiv10, | ||
| 138 | ratio: Ratio::_256x, | ||
| 139 | }, | ||
| 140 | ExactSampleRate::_15625 => Mode::Master { | ||
| 141 | freq: MckFreq::_32MDiv32, | ||
| 142 | ratio: Ratio::_64x, | ||
| 143 | }, | ||
| 144 | ExactSampleRate::_15873 => Mode::Master { | ||
| 145 | freq: MckFreq::_32MDiv63, | ||
| 146 | ratio: Ratio::_32x, | ||
| 147 | }, | ||
| 148 | ExactSampleRate::_25000 => Mode::Master { | ||
| 149 | freq: MckFreq::_32MDiv10, | ||
| 150 | ratio: Ratio::_128x, | ||
| 151 | }, | ||
| 152 | ExactSampleRate::_31250 => Mode::Master { | ||
| 153 | freq: MckFreq::_32MDiv32, | ||
| 154 | ratio: Ratio::_32x, | ||
| 155 | }, | ||
| 156 | ExactSampleRate::_50000 => Mode::Master { | ||
| 157 | freq: MckFreq::_32MDiv10, | ||
| 158 | ratio: Ratio::_64x, | ||
| 159 | }, | ||
| 160 | ExactSampleRate::_62500 => Mode::Master { | ||
| 161 | freq: MckFreq::_32MDiv16, | ||
| 162 | ratio: Ratio::_32x, | ||
| 163 | }, | ||
| 164 | ExactSampleRate::_100000 => Mode::Master { | ||
| 165 | freq: MckFreq::_32MDiv10, | ||
| 166 | ratio: Ratio::_32x, | ||
| 167 | }, | ||
| 168 | ExactSampleRate::_125000 => Mode::Master { | ||
| 169 | freq: MckFreq::_32MDiv8, | ||
| 170 | ratio: Ratio::_32x, | ||
| 171 | }, | ||
| 172 | } | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | /// I2S configuration. | ||
| 68 | #[derive(Clone)] | 177 | #[derive(Clone)] |
| 69 | #[non_exhaustive] | 178 | #[non_exhaustive] |
| 70 | pub struct Config { | 179 | pub struct Config { |
| @@ -78,7 +187,7 @@ pub struct Config { | |||
| 78 | impl Default for Config { | 187 | impl Default for Config { |
| 79 | fn default() -> Self { | 188 | fn default() -> Self { |
| 80 | Self { | 189 | Self { |
| 81 | mode: MODE_MASTER_32000, | 190 | mode: ExactSampleRate::_31250.into(), |
| 82 | swidth: SampleWidth::_16bit, | 191 | swidth: SampleWidth::_16bit, |
| 83 | align: Align::Left, | 192 | align: Align::Left, |
| 84 | format: Format::I2S, | 193 | format: Format::I2S, |
| @@ -132,10 +241,12 @@ impl MckFreq { | |||
| 132 | 256000, | 241 | 256000, |
| 133 | ]; | 242 | ]; |
| 134 | 243 | ||
| 244 | /// Return the value that needs to be written to the register. | ||
| 135 | pub fn to_register_value(&self) -> u32 { | 245 | pub fn to_register_value(&self) -> u32 { |
| 136 | Self::REGISTER_VALUES[usize::from(*self)] | 246 | Self::REGISTER_VALUES[usize::from(*self)] |
| 137 | } | 247 | } |
| 138 | 248 | ||
| 249 | /// Return the master clock frequency. | ||
| 139 | pub fn to_frequency(&self) -> u32 { | 250 | pub fn to_frequency(&self) -> u32 { |
| 140 | Self::FREQUENCIES[usize::from(*self)] | 251 | Self::FREQUENCIES[usize::from(*self)] |
| 141 | } | 252 | } |
| @@ -147,7 +258,10 @@ impl From<MckFreq> for usize { | |||
| 147 | } | 258 | } |
| 148 | } | 259 | } |
| 149 | 260 | ||
| 150 | /// MCK / LRCK ratio. | 261 | /// Master clock frequency ratio |
| 262 | /// | ||
| 263 | /// Sample Rate = LRCK = MCK / Ratio | ||
| 264 | /// | ||
| 151 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | 265 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] |
| 152 | pub enum Ratio { | 266 | pub enum Ratio { |
| 153 | _32x, | 267 | _32x, |
| @@ -175,6 +289,7 @@ impl From<Ratio> for u8 { | |||
| 175 | } | 289 | } |
| 176 | } | 290 | } |
| 177 | 291 | ||
| 292 | /// Sample width. | ||
| 178 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | 293 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] |
| 179 | pub enum SampleWidth { | 294 | pub enum SampleWidth { |
| 180 | _8bit, | 295 | _8bit, |
| @@ -188,7 +303,7 @@ impl From<SampleWidth> for u8 { | |||
| 188 | } | 303 | } |
| 189 | } | 304 | } |
| 190 | 305 | ||
| 191 | /// Alignment of sample within a frame. | 306 | /// Channel used for the most significant sample value in a frame. |
| 192 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | 307 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] |
| 193 | pub enum Align { | 308 | pub enum Align { |
| 194 | Left, | 309 | Left, |
| @@ -220,11 +335,13 @@ impl From<Format> for bool { | |||
| 220 | } | 335 | } |
| 221 | } | 336 | } |
| 222 | 337 | ||
| 223 | /// Enable channels. | 338 | /// Channels |
| 224 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | 339 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] |
| 225 | pub enum Channels { | 340 | pub enum Channels { |
| 226 | Stereo, | 341 | Stereo, |
| 342 | /// Mono left | ||
| 227 | Left, | 343 | Left, |
| 344 | /// Mono right | ||
| 228 | Right, | 345 | Right, |
| 229 | } | 346 | } |
| 230 | 347 | ||
| @@ -235,8 +352,6 @@ impl From<Channels> for u8 { | |||
| 235 | } | 352 | } |
| 236 | 353 | ||
| 237 | /// Interface to the I2S peripheral using EasyDMA to offload the transmission and reception workload. | 354 | /// Interface to the I2S peripheral using EasyDMA to offload the transmission and reception workload. |
| 238 | /// | ||
| 239 | /// For more details about EasyDMA, consult the module documentation. | ||
| 240 | pub struct I2S<'d, T: Instance> { | 355 | pub struct I2S<'d, T: Instance> { |
| 241 | _p: PeripheralRef<'d, T>, | 356 | _p: PeripheralRef<'d, T>, |
| 242 | } | 357 | } |
| @@ -278,29 +393,32 @@ impl<'d, T: Instance> I2S<'d, T> { | |||
| 278 | ) -> Self { | 393 | ) -> Self { |
| 279 | into_ref!(i2s, irq, mck, sck, lrck, sdin, sdout); | 394 | into_ref!(i2s, irq, mck, sck, lrck, sdin, sdout); |
| 280 | 395 | ||
| 281 | let r = T::regs(); | 396 | Self::apply_config(&config); |
| 282 | Self::apply_config(&r.config, &config); | 397 | Self::select_pins(mck, sck, lrck, sdin, sdout); |
| 283 | Self::select_pins(&r.psel, mck, sck, lrck, sdin, sdout); | 398 | Self::setup_interrupt(irq); |
| 284 | Self::setup_interrupt(irq, r); | ||
| 285 | 399 | ||
| 286 | r.enable.write(|w| w.enable().enabled()); | 400 | T::regs().enable.write(|w| w.enable().enabled()); |
| 287 | 401 | ||
| 288 | Self { _p: i2s } | 402 | Self { _p: i2s } |
| 289 | } | 403 | } |
| 290 | 404 | ||
| 405 | /// I2S output only | ||
| 291 | pub fn output(self) -> Output<'d, T> { | 406 | pub fn output(self) -> Output<'d, T> { |
| 292 | Output { _p: self._p } | 407 | Output { _p: self._p } |
| 293 | } | 408 | } |
| 294 | 409 | ||
| 410 | /// I2S input only | ||
| 295 | pub fn input(self) -> Input<'d, T> { | 411 | pub fn input(self) -> Input<'d, T> { |
| 296 | Input { _p: self._p } | 412 | Input { _p: self._p } |
| 297 | } | 413 | } |
| 298 | 414 | ||
| 415 | /// I2S full duplex (input and output) | ||
| 299 | pub fn full_duplex(self) -> FullDuplex<'d, T> { | 416 | pub fn full_duplex(self) -> FullDuplex<'d, T> { |
| 300 | FullDuplex { _p: self._p } | 417 | FullDuplex { _p: self._p } |
| 301 | } | 418 | } |
| 302 | 419 | ||
| 303 | fn apply_config(c: &CONFIG, config: &Config) { | 420 | fn apply_config(config: &Config) { |
| 421 | let c = &T::regs().config; | ||
| 304 | match config.mode { | 422 | match config.mode { |
| 305 | Mode::Master { freq, ratio } => { | 423 | Mode::Master { freq, ratio } => { |
| 306 | c.mode.write(|w| w.mode().master()); | 424 | c.mode.write(|w| w.mode().master()); |
| @@ -322,13 +440,14 @@ impl<'d, T: Instance> I2S<'d, T> { | |||
| 322 | } | 440 | } |
| 323 | 441 | ||
| 324 | fn select_pins( | 442 | fn select_pins( |
| 325 | psel: &PSEL, | ||
| 326 | mck: PeripheralRef<'d, AnyPin>, | 443 | mck: PeripheralRef<'d, AnyPin>, |
| 327 | sck: PeripheralRef<'d, AnyPin>, | 444 | sck: PeripheralRef<'d, AnyPin>, |
| 328 | lrck: PeripheralRef<'d, AnyPin>, | 445 | lrck: PeripheralRef<'d, AnyPin>, |
| 329 | sdin: PeripheralRef<'d, AnyPin>, | 446 | sdin: PeripheralRef<'d, AnyPin>, |
| 330 | sdout: PeripheralRef<'d, AnyPin>, | 447 | sdout: PeripheralRef<'d, AnyPin>, |
| 331 | ) { | 448 | ) { |
| 449 | let psel = &T::regs().psel; | ||
| 450 | |||
| 332 | psel.mck.write(|w| { | 451 | psel.mck.write(|w| { |
| 333 | unsafe { w.bits(mck.psel_bits()) }; | 452 | unsafe { w.bits(mck.psel_bits()) }; |
| 334 | w.connect().connected() | 453 | w.connect().connected() |
| @@ -355,21 +474,23 @@ impl<'d, T: Instance> I2S<'d, T> { | |||
| 355 | }); | 474 | }); |
| 356 | } | 475 | } |
| 357 | 476 | ||
| 358 | fn setup_interrupt(irq: PeripheralRef<'d, T::Interrupt>, r: &RegisterBlock) { | 477 | fn setup_interrupt(irq: PeripheralRef<'d, T::Interrupt>) { |
| 359 | irq.set_handler(Self::on_interrupt); | 478 | irq.set_handler(Self::on_interrupt); |
| 360 | // irq.set_priority(Priority::P1); // TODO review priorities | ||
| 361 | irq.unpend(); | 479 | irq.unpend(); |
| 362 | irq.enable(); | 480 | irq.enable(); |
| 363 | 481 | ||
| 364 | let device = Device::<T>::new(); | 482 | let device = Device::<T>::new(); |
| 365 | device.disable_tx_ptr_interrupt(); | 483 | device.disable_tx_ptr_interrupt(); |
| 366 | device.disable_rx_ptr_interrupt(); | 484 | device.disable_rx_ptr_interrupt(); |
| 485 | device.disable_stopped_interrupt(); | ||
| 367 | 486 | ||
| 368 | device.reset_tx_ptr_event(); | 487 | device.reset_tx_ptr_event(); |
| 369 | device.reset_rx_ptr_event(); | 488 | device.reset_rx_ptr_event(); |
| 489 | device.reset_stopped_event(); | ||
| 370 | 490 | ||
| 371 | device.enable_tx_ptr_interrupt(); | 491 | device.enable_tx_ptr_interrupt(); |
| 372 | device.enable_rx_ptr_interrupt(); | 492 | device.enable_rx_ptr_interrupt(); |
| 493 | device.enable_stopped_interrupt(); | ||
| 373 | } | 494 | } |
| 374 | 495 | ||
| 375 | fn on_interrupt(_: *mut ()) { | 496 | fn on_interrupt(_: *mut ()) { |
| @@ -387,41 +508,40 @@ impl<'d, T: Instance> I2S<'d, T> { | |||
| 387 | s.rx_waker.wake(); | 508 | s.rx_waker.wake(); |
| 388 | device.disable_rx_ptr_interrupt(); | 509 | device.disable_rx_ptr_interrupt(); |
| 389 | } | 510 | } |
| 390 | } | ||
| 391 | } | ||
| 392 | 511 | ||
| 393 | pub struct Output<'d, T: Instance> { | 512 | if device.is_stopped() { |
| 394 | _p: PeripheralRef<'d, T>, | 513 | trace!("STOPPED INT"); |
| 395 | } | 514 | s.stop_waker.wake(); |
| 515 | device.disable_stopped_interrupt(); | ||
| 516 | } | ||
| 517 | } | ||
| 396 | 518 | ||
| 397 | impl<'d, T: Instance> Output<'d, T> { | 519 | async fn stop() { |
| 398 | /// Starts I2S transfer. | 520 | compiler_fence(Ordering::SeqCst); |
| 399 | #[inline(always)] | ||
| 400 | pub fn start<B>(&self, buffer: B) -> Result<(), Error> | ||
| 401 | where | ||
| 402 | B: Buffer, | ||
| 403 | { | ||
| 404 | // TODO what to do if it is started already? | ||
| 405 | 521 | ||
| 406 | let device = Device::<T>::new(); | 522 | let device = Device::<T>::new(); |
| 407 | device.enable(); | 523 | device.stop(); |
| 408 | device.set_tx_buffer(buffer)?; | ||
| 409 | device.enable_tx(); | ||
| 410 | device.start(); | ||
| 411 | 524 | ||
| 412 | Ok(()) | 525 | T::state().started.store(false, Ordering::Relaxed); |
| 413 | } | ||
| 414 | 526 | ||
| 415 | /// Stops the I2S transfer and waits until it has stopped. | 527 | poll_fn(|cx| { |
| 416 | #[inline(always)] | 528 | T::state().stop_waker.register(cx.waker()); |
| 417 | pub async fn stop(&self) { | 529 | |
| 418 | todo!() | 530 | if device.is_stopped() { |
| 531 | trace!("STOP: Ready"); | ||
| 532 | device.reset_stopped_event(); | ||
| 533 | Poll::Ready(()) | ||
| 534 | } else { | ||
| 535 | trace!("STOP: Pending"); | ||
| 536 | Poll::Pending | ||
| 537 | } | ||
| 538 | }) | ||
| 539 | .await; | ||
| 540 | |||
| 541 | device.disable(); | ||
| 419 | } | 542 | } |
| 420 | 543 | ||
| 421 | /// Transmits the given `buffer`. | 544 | async fn send<B>(buffer: B) -> Result<(), Error> |
| 422 | /// Buffer address must be 4 byte aligned and located in RAM. | ||
| 423 | #[allow(unused_mut)] | ||
| 424 | pub async fn send<B>(&mut self, buffer: B) -> Result<(), Error> | ||
| 425 | where | 545 | where |
| 426 | B: Buffer, | 546 | B: Buffer, |
| 427 | { | 547 | { |
| @@ -454,24 +574,191 @@ impl<'d, T: Instance> Output<'d, T> { | |||
| 454 | 574 | ||
| 455 | Ok(()) | 575 | Ok(()) |
| 456 | } | 576 | } |
| 577 | |||
| 578 | async fn receive<B>(buffer: B) -> Result<(), Error> | ||
| 579 | where | ||
| 580 | B: Buffer, | ||
| 581 | { | ||
| 582 | trace!("RECEIVE: {}", buffer.bytes_ptr() as u32); | ||
| 583 | |||
| 584 | let device = Device::<T>::new(); | ||
| 585 | let drop = device.on_rx_drop(); | ||
| 586 | |||
| 587 | compiler_fence(Ordering::SeqCst); | ||
| 588 | |||
| 589 | poll_fn(|cx| { | ||
| 590 | T::state().rx_waker.register(cx.waker()); | ||
| 591 | |||
| 592 | if device.is_rx_ptr_updated() { | ||
| 593 | trace!("RX POLL: Ready"); | ||
| 594 | device.reset_rx_ptr_event(); | ||
| 595 | device.enable_rx_ptr_interrupt(); | ||
| 596 | Poll::Ready(()) | ||
| 597 | } else { | ||
| 598 | trace!("RX POLL: Pending"); | ||
| 599 | Poll::Pending | ||
| 600 | } | ||
| 601 | }) | ||
| 602 | .await; | ||
| 603 | |||
| 604 | device.set_rx_buffer(buffer)?; | ||
| 605 | |||
| 606 | compiler_fence(Ordering::SeqCst); | ||
| 607 | drop.defuse(); | ||
| 608 | |||
| 609 | Ok(()) | ||
| 610 | } | ||
| 611 | } | ||
| 612 | |||
| 613 | /// I2S output | ||
| 614 | pub struct Output<'d, T: Instance> { | ||
| 615 | _p: PeripheralRef<'d, T>, | ||
| 616 | } | ||
| 617 | |||
| 618 | impl<'d, T: Instance> Output<'d, T> { | ||
| 619 | /// Prepare the initial buffer and start the I2S transfer. | ||
| 620 | pub async fn start<B>(&self, buffer: B) -> Result<(), Error> | ||
| 621 | where | ||
| 622 | B: Buffer, | ||
| 623 | { | ||
| 624 | let device = Device::<T>::new(); | ||
| 625 | |||
| 626 | let s = T::state(); | ||
| 627 | if s.started.load(Ordering::Relaxed) { | ||
| 628 | self.stop().await; | ||
| 629 | } | ||
| 630 | |||
| 631 | device.enable(); | ||
| 632 | device.enable_tx(); | ||
| 633 | device.set_tx_buffer(buffer)?; | ||
| 634 | |||
| 635 | s.started.store(true, Ordering::Relaxed); | ||
| 636 | |||
| 637 | device.start(); | ||
| 638 | |||
| 639 | Ok(()) | ||
| 640 | } | ||
| 641 | |||
| 642 | /// Stops the I2S transfer and waits until it has stopped. | ||
| 643 | #[inline(always)] | ||
| 644 | pub async fn stop(&self) { | ||
| 645 | I2S::<T>::stop().await | ||
| 646 | } | ||
| 647 | |||
| 648 | /// Sets the given `buffer` for transmission in the DMA. | ||
| 649 | /// Buffer address must be 4 byte aligned and located in RAM. | ||
| 650 | /// The buffer must not be written while being used by the DMA, | ||
| 651 | /// which takes two other `send`s being awaited. | ||
| 652 | #[allow(unused_mut)] | ||
| 653 | pub async fn send<B>(&mut self, buffer: B) -> Result<(), Error> | ||
| 654 | where | ||
| 655 | B: Buffer, | ||
| 656 | { | ||
| 657 | I2S::<T>::send(buffer).await | ||
| 658 | } | ||
| 457 | } | 659 | } |
| 458 | 660 | ||
| 661 | /// I2S input | ||
| 459 | pub struct Input<'d, T: Instance> { | 662 | pub struct Input<'d, T: Instance> { |
| 460 | _p: PeripheralRef<'d, T>, | 663 | _p: PeripheralRef<'d, T>, |
| 461 | } | 664 | } |
| 462 | 665 | ||
| 463 | impl<'d, T: Instance> Input<'d, T> { | 666 | impl<'d, T: Instance> Input<'d, T> { |
| 464 | // TODO | 667 | /// Prepare the initial buffer and start the I2S transfer. |
| 668 | pub async fn start<B>(&self, buffer: B) -> Result<(), Error> | ||
| 669 | where | ||
| 670 | B: Buffer, | ||
| 671 | { | ||
| 672 | let device = Device::<T>::new(); | ||
| 673 | |||
| 674 | let s = T::state(); | ||
| 675 | if s.started.load(Ordering::Relaxed) { | ||
| 676 | self.stop().await; | ||
| 677 | } | ||
| 678 | |||
| 679 | device.enable(); | ||
| 680 | device.enable_rx(); | ||
| 681 | device.set_rx_buffer(buffer)?; | ||
| 682 | |||
| 683 | s.started.store(true, Ordering::Relaxed); | ||
| 684 | |||
| 685 | device.start(); | ||
| 686 | |||
| 687 | Ok(()) | ||
| 688 | } | ||
| 689 | |||
| 690 | /// Stops the I2S transfer and waits until it has stopped. | ||
| 691 | #[inline(always)] | ||
| 692 | pub async fn stop(&self) { | ||
| 693 | I2S::<T>::stop().await | ||
| 694 | } | ||
| 695 | |||
| 696 | /// Sets the given `buffer` for reception from the DMA. | ||
| 697 | /// Buffer address must be 4 byte aligned and located in RAM. | ||
| 698 | /// The buffer must not be read while being used by the DMA, | ||
| 699 | /// which takes two other `receive`s being awaited. | ||
| 700 | #[allow(unused_mut)] | ||
| 701 | pub async fn receive<B>(&mut self, buffer: B) -> Result<(), Error> | ||
| 702 | where | ||
| 703 | B: Buffer, | ||
| 704 | { | ||
| 705 | I2S::<T>::receive(buffer).await | ||
| 706 | } | ||
| 465 | } | 707 | } |
| 466 | 708 | ||
| 709 | /// I2S ful duplex (input & output) | ||
| 467 | pub struct FullDuplex<'d, T: Instance> { | 710 | pub struct FullDuplex<'d, T: Instance> { |
| 468 | _p: PeripheralRef<'d, T>, | 711 | _p: PeripheralRef<'d, T>, |
| 469 | } | 712 | } |
| 470 | 713 | ||
| 471 | impl<'d, T: Instance> FullDuplex<'d, T> { | 714 | impl<'d, T: Instance> FullDuplex<'d, T> { |
| 472 | // TODO | 715 | /// Prepare the initial buffers and start the I2S transfer. |
| 716 | pub async fn start<B>(&self, buffer_out: B, buffer_in: B) -> Result<(), Error> | ||
| 717 | where | ||
| 718 | B: Buffer, | ||
| 719 | { | ||
| 720 | let device = Device::<T>::new(); | ||
| 721 | |||
| 722 | let s = T::state(); | ||
| 723 | if s.started.load(Ordering::Relaxed) { | ||
| 724 | self.stop().await; | ||
| 725 | } | ||
| 726 | |||
| 727 | device.enable(); | ||
| 728 | device.enable_tx(); | ||
| 729 | device.enable_rx(); | ||
| 730 | device.set_tx_buffer(buffer_out)?; | ||
| 731 | device.set_rx_buffer(buffer_in)?; | ||
| 732 | |||
| 733 | s.started.store(true, Ordering::Relaxed); | ||
| 734 | |||
| 735 | device.start(); | ||
| 736 | |||
| 737 | Ok(()) | ||
| 738 | } | ||
| 739 | |||
| 740 | /// Stops the I2S transfer and waits until it has stopped. | ||
| 741 | #[inline(always)] | ||
| 742 | pub async fn stop(&self) { | ||
| 743 | I2S::<T>::stop().await | ||
| 744 | } | ||
| 745 | |||
| 746 | /// Sets the given `buffer_out` and `buffer_in` for transmission/reception from the DMA. | ||
| 747 | /// Buffer address must be 4 byte aligned and located in RAM. | ||
| 748 | /// The buffers must not be written/read while being used by the DMA, | ||
| 749 | /// which takes two other `send_and_receive` operations being awaited. | ||
| 750 | #[allow(unused_mut)] | ||
| 751 | pub async fn send_and_receive<B>(&mut self, buffer_out: B, buffer_in: B) -> Result<(), Error> | ||
| 752 | where | ||
| 753 | B: Buffer, | ||
| 754 | { | ||
| 755 | I2S::<T>::send(buffer_out).await?; | ||
| 756 | I2S::<T>::receive(buffer_in).await?; | ||
| 757 | Ok(()) | ||
| 758 | } | ||
| 473 | } | 759 | } |
| 474 | 760 | ||
| 761 | /// Helper encapsulating common I2S device operations. | ||
| 475 | struct Device<T>(&'static RegisterBlock, PhantomData<T>); | 762 | struct Device<T>(&'static RegisterBlock, PhantomData<T>); |
| 476 | 763 | ||
| 477 | impl<T: Instance> Device<T> { | 764 | impl<T: Instance> Device<T> { |
| @@ -521,6 +808,34 @@ impl<T: Instance> Device<T> { | |||
| 521 | self.0.tasks_start.write(|w| unsafe { w.bits(1) }); | 808 | self.0.tasks_start.write(|w| unsafe { w.bits(1) }); |
| 522 | } | 809 | } |
| 523 | 810 | ||
| 811 | #[inline(always)] | ||
| 812 | fn stop(&self) { | ||
| 813 | self.0.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 814 | } | ||
| 815 | |||
| 816 | #[inline(always)] | ||
| 817 | fn is_stopped(&self) -> bool { | ||
| 818 | self.0.events_stopped.read().bits() != 0 | ||
| 819 | } | ||
| 820 | |||
| 821 | #[inline(always)] | ||
| 822 | fn reset_stopped_event(&self) { | ||
| 823 | trace!("STOPPED EVENT: Reset"); | ||
| 824 | self.0.events_stopped.reset(); | ||
| 825 | } | ||
| 826 | |||
| 827 | #[inline(always)] | ||
| 828 | fn disable_stopped_interrupt(&self) { | ||
| 829 | trace!("STOPPED INTERRUPT: Disabled"); | ||
| 830 | self.0.intenclr.write(|w| w.stopped().clear()); | ||
| 831 | } | ||
| 832 | |||
| 833 | #[inline(always)] | ||
| 834 | fn enable_stopped_interrupt(&self) { | ||
| 835 | trace!("STOPPED INTERRUPT: Enabled"); | ||
| 836 | self.0.intenset.write(|w| w.stopped().set()); | ||
| 837 | } | ||
| 838 | |||
| 524 | #[inline] | 839 | #[inline] |
| 525 | fn set_tx_buffer<B>(&self, buffer: B) -> Result<(), Error> | 840 | fn set_tx_buffer<B>(&self, buffer: B) -> Result<(), Error> |
| 526 | where | 841 | where |
| @@ -606,6 +921,23 @@ impl<T: Instance> Device<T> { | |||
| 606 | }) | 921 | }) |
| 607 | } | 922 | } |
| 608 | 923 | ||
| 924 | #[inline] | ||
| 925 | fn on_rx_drop(&self) -> OnDrop<fn()> { | ||
| 926 | OnDrop::new(move || { | ||
| 927 | trace!("RX DROP: Stopping"); | ||
| 928 | |||
| 929 | let device = Device::<T>::new(); | ||
| 930 | device.disable_rx_ptr_interrupt(); | ||
| 931 | device.reset_rx_ptr_event(); | ||
| 932 | device.disable_rx(); | ||
| 933 | |||
| 934 | // TX is stopped almost instantly, spinning is fine. | ||
| 935 | while !device.is_rx_ptr_updated() {} | ||
| 936 | |||
| 937 | trace!("RX DROP: Stopped"); | ||
| 938 | }) | ||
| 939 | } | ||
| 940 | |||
| 609 | fn validate_buffer<B>(buffer: B) -> Result<(u32, u32), Error> | 941 | fn validate_buffer<B>(buffer: B) -> Result<(u32, u32), Error> |
| 610 | where | 942 | where |
| 611 | B: Buffer, | 943 | B: Buffer, |
| @@ -632,6 +964,56 @@ impl<T: Instance> Device<T> { | |||
| 632 | } | 964 | } |
| 633 | } | 965 | } |
| 634 | 966 | ||
| 967 | /// Sample details | ||
| 968 | pub trait Sample: Sized + Copy + Default { | ||
| 969 | const WIDTH: usize; | ||
| 970 | const SCALE: Self; | ||
| 971 | } | ||
| 972 | |||
| 973 | impl Sample for i8 { | ||
| 974 | const WIDTH: usize = 8; | ||
| 975 | const SCALE: Self = 1 << (Self::WIDTH - 1); | ||
| 976 | } | ||
| 977 | |||
| 978 | impl Sample for i16 { | ||
| 979 | const WIDTH: usize = 16; | ||
| 980 | const SCALE: Self = 1 << (Self::WIDTH - 1); | ||
| 981 | } | ||
| 982 | |||
| 983 | impl Sample for i32 { | ||
| 984 | const WIDTH: usize = 24; | ||
| 985 | const SCALE: Self = 1 << (Self::WIDTH - 1); | ||
| 986 | } | ||
| 987 | |||
| 988 | /// A 4-bytes aligned [Buffer]. | ||
| 989 | #[repr(align(4))] | ||
| 990 | pub struct AlignedBuffer<T: Sample, const N: usize>([T; N]); | ||
| 991 | |||
| 992 | impl<T: Sample, const N: usize> AlignedBuffer<T, N> { | ||
| 993 | pub fn new(array: [T; N]) -> Self { | ||
| 994 | Self(array) | ||
| 995 | } | ||
| 996 | } | ||
| 997 | |||
| 998 | impl<T: Sample, const N: usize> Default for AlignedBuffer<T, N> { | ||
| 999 | fn default() -> Self { | ||
| 1000 | Self([T::default(); N]) | ||
| 1001 | } | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | impl<T: Sample, const N: usize> AsRef<[T]> for AlignedBuffer<T, N> { | ||
| 1005 | fn as_ref(&self) -> &[T] { | ||
| 1006 | self.0.as_slice() | ||
| 1007 | } | ||
| 1008 | } | ||
| 1009 | |||
| 1010 | impl<T: Sample, const N: usize> AsMut<[T]> for AlignedBuffer<T, N> { | ||
| 1011 | fn as_mut(&mut self) -> &mut [T] { | ||
| 1012 | self.0.as_mut_slice() | ||
| 1013 | } | ||
| 1014 | } | ||
| 1015 | |||
| 1016 | /// Common operations required for a buffer to be used by the DMA | ||
| 635 | pub trait Buffer: Sized { | 1017 | pub trait Buffer: Sized { |
| 636 | fn bytes_ptr(&self) -> *const u8; | 1018 | fn bytes_ptr(&self) -> *const u8; |
| 637 | fn bytes_len(&self) -> usize; | 1019 | fn bytes_len(&self) -> usize; |
| @@ -674,22 +1056,25 @@ impl Buffer for &[i32] { | |||
| 674 | } | 1056 | } |
| 675 | 1057 | ||
| 676 | pub(crate) mod sealed { | 1058 | pub(crate) mod sealed { |
| 677 | use core::sync::atomic::AtomicI32; | 1059 | use core::sync::atomic::AtomicBool; |
| 678 | 1060 | ||
| 679 | use embassy_sync::waitqueue::AtomicWaker; | 1061 | use embassy_sync::waitqueue::AtomicWaker; |
| 680 | 1062 | ||
| 681 | use super::*; | 1063 | /// Peripheral static state |
| 682 | |||
| 683 | pub struct State { | 1064 | pub struct State { |
| 1065 | pub started: AtomicBool, | ||
| 684 | pub rx_waker: AtomicWaker, | 1066 | pub rx_waker: AtomicWaker, |
| 685 | pub tx_waker: AtomicWaker, | 1067 | pub tx_waker: AtomicWaker, |
| 1068 | pub stop_waker: AtomicWaker, | ||
| 686 | } | 1069 | } |
| 687 | 1070 | ||
| 688 | impl State { | 1071 | impl State { |
| 689 | pub const fn new() -> Self { | 1072 | pub const fn new() -> Self { |
| 690 | Self { | 1073 | Self { |
| 1074 | started: AtomicBool::new(false), | ||
| 691 | rx_waker: AtomicWaker::new(), | 1075 | rx_waker: AtomicWaker::new(), |
| 692 | tx_waker: AtomicWaker::new(), | 1076 | tx_waker: AtomicWaker::new(), |
| 1077 | stop_waker: AtomicWaker::new(), | ||
| 693 | } | 1078 | } |
| 694 | } | 1079 | } |
| 695 | } | 1080 | } |
| @@ -704,8 +1089,6 @@ pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send { | |||
| 704 | type Interrupt: Interrupt; | 1089 | type Interrupt: Interrupt; |
| 705 | } | 1090 | } |
| 706 | 1091 | ||
| 707 | // TODO: Unsure why this macro is flagged as unused by CI when in fact it's used elsewhere? | ||
| 708 | #[allow(unused_macros)] | ||
| 709 | macro_rules! impl_i2s { | 1092 | macro_rules! impl_i2s { |
| 710 | ($type:ident, $pac_type:ident, $irq:ident) => { | 1093 | ($type:ident, $pac_type:ident, $irq:ident) => { |
| 711 | impl crate::i2s::sealed::Instance for peripherals::$type { | 1094 | impl crate::i2s::sealed::Instance for peripherals::$type { |
diff --git a/examples/nrf/src/bin/i2s.rs b/examples/nrf/src/bin/i2s-generate.rs index 9b3144f24..f59b63ce6 100644 --- a/examples/nrf/src/bin/i2s.rs +++ b/examples/nrf/src/bin/i2s-generate.rs | |||
| @@ -4,59 +4,41 @@ | |||
| 4 | 4 | ||
| 5 | use core::f32::consts::PI; | 5 | use core::f32::consts::PI; |
| 6 | 6 | ||
| 7 | use defmt::{error, info, trace}; | 7 | use defmt::{error, info}; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_nrf::gpio::{Input, Pin, Pull}; | 9 | use embassy_nrf::i2s::{self, Sample as _}; |
| 10 | use embassy_nrf::i2s::{Channels, MckFreq, Mode, Ratio, SampleWidth, MODE_MASTER_32000}; | 10 | use embassy_nrf::interrupt; |
| 11 | use embassy_nrf::pac::ficr::info; | ||
| 12 | use embassy_nrf::{i2s, interrupt}; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | 11 | use {defmt_rtt as _, panic_probe as _}; |
| 14 | 12 | ||
| 15 | #[repr(align(4))] | ||
| 16 | pub struct AlignedBuffer<T: ?Sized>(T); | ||
| 17 | |||
| 18 | impl<T> AsRef<T> for AlignedBuffer<T> { | ||
| 19 | fn as_ref(&self) -> &T { | ||
| 20 | &self.0 | ||
| 21 | } | ||
| 22 | } | ||
| 23 | |||
| 24 | impl<T> AsMut<T> for AlignedBuffer<T> { | ||
| 25 | fn as_mut(&mut self) -> &mut T { | ||
| 26 | &mut self.0 | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | #[embassy_executor::main] | 13 | #[embassy_executor::main] |
| 31 | async fn main(_spawner: Spawner) { | 14 | async fn main(_spawner: Spawner) { |
| 32 | let p = embassy_nrf::init(Default::default()); | 15 | let p = embassy_nrf::init(Default::default()); |
| 16 | |||
| 33 | let mut config = i2s::Config::default(); | 17 | let mut config = i2s::Config::default(); |
| 34 | config.mode = MODE_MASTER_32000; | 18 | config.mode = i2s::ExactSampleRate::_50000.into(); |
| 35 | // config.mode = Mode::Master { | 19 | config.channels = i2s::Channels::Left; |
| 36 | // freq: MckFreq::_32MDiv10, | 20 | config.swidth = i2s::SampleWidth::_16bit; |
| 37 | // ratio: Ratio::_256x, | ||
| 38 | // }; // 12500 Hz | ||
| 39 | config.channels = Channels::Left; | ||
| 40 | config.swidth = SampleWidth::_16bit; | ||
| 41 | let sample_rate = config.mode.sample_rate().expect("I2S Master"); | 21 | let sample_rate = config.mode.sample_rate().expect("I2S Master"); |
| 42 | let inv_sample_rate = 1.0 / sample_rate as f32; | 22 | let inv_sample_rate = 1.0 / sample_rate as f32; |
| 43 | 23 | ||
| 44 | info!("Sample rate: {}", sample_rate); | 24 | info!("Sample rate: {}", sample_rate); |
| 45 | 25 | ||
| 46 | // Wait for a button press | 26 | // Wait for a button press |
| 27 | // use embassy_nrf::gpio::{Input, Pin, Pull}; | ||
| 47 | // let mut btn1 = Input::new(p.P1_00.degrade(), Pull::Up); | 28 | // let mut btn1 = Input::new(p.P1_00.degrade(), Pull::Up); |
| 48 | // btn1.wait_for_low().await; | 29 | // btn1.wait_for_low().await; |
| 49 | 30 | ||
| 50 | let irq = interrupt::take!(I2S); | 31 | let irq = interrupt::take!(I2S); |
| 51 | 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(); | 32 | 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) |
| 33 | .output(); | ||
| 52 | 34 | ||
| 53 | type Sample = i16; | 35 | type Sample = i16; |
| 54 | const MAX_UNIPOLAR_VALUE: Sample = (1 << 15) as Sample; | 36 | const NUM_SAMPLES: usize = 6000; |
| 55 | const NUM_SAMPLES: usize = 2000; | 37 | |
| 56 | let mut buffers: [AlignedBuffer<[Sample; NUM_SAMPLES]>; 3] = [ | 38 | let mut buffers: [i2s::AlignedBuffer<Sample, NUM_SAMPLES>; 3] = [ |
| 57 | AlignedBuffer([0; NUM_SAMPLES]), | 39 | i2s::AlignedBuffer::default(), |
| 58 | AlignedBuffer([0; NUM_SAMPLES]), | 40 | i2s::AlignedBuffer::default(), |
| 59 | AlignedBuffer([0; NUM_SAMPLES]), | 41 | i2s::AlignedBuffer::default(), |
| 60 | ]; | 42 | ]; |
| 61 | 43 | ||
| 62 | let mut carrier = SineOsc::new(); | 44 | let mut carrier = SineOsc::new(); |
| @@ -66,32 +48,29 @@ async fn main(_spawner: Spawner) { | |||
| 66 | freq_mod.set_amplitude(1.0); | 48 | freq_mod.set_amplitude(1.0); |
| 67 | 49 | ||
| 68 | let mut amp_mod = SineOsc::new(); | 50 | let mut amp_mod = SineOsc::new(); |
| 69 | amp_mod.set_frequency(4.0, inv_sample_rate); | 51 | amp_mod.set_frequency(16.0, inv_sample_rate); |
| 70 | amp_mod.set_amplitude(0.5); | 52 | amp_mod.set_amplitude(0.5); |
| 71 | 53 | ||
| 72 | let mut generate = |buf: &mut [Sample]| { | 54 | let mut generate = |buf: &mut [Sample]| { |
| 73 | let ptr = buf as *const [Sample] as *const Sample as u32; | 55 | for sample in &mut buf.chunks_mut(1) { |
| 74 | trace!("GEN: {}", ptr); | ||
| 75 | |||
| 76 | for sample in &mut buf.as_mut().chunks_mut(1) { | ||
| 77 | let signal = carrier.generate(); | ||
| 78 | let freq_modulation = bipolar_to_unipolar(freq_mod.generate()); | 56 | let freq_modulation = bipolar_to_unipolar(freq_mod.generate()); |
| 79 | carrier.set_frequency(220.0 + 220.0 * freq_modulation, inv_sample_rate); | 57 | carrier.set_frequency(220.0 + 440.0 * freq_modulation, inv_sample_rate); |
| 80 | let amp_modulation = bipolar_to_unipolar(amp_mod.generate()); | 58 | let amp_modulation = bipolar_to_unipolar(amp_mod.generate()); |
| 81 | carrier.set_amplitude(amp_modulation); | 59 | carrier.set_amplitude(amp_modulation); |
| 82 | let value = (MAX_UNIPOLAR_VALUE as f32 * signal) as Sample; | 60 | let signal = carrier.generate(); |
| 61 | let value = (Sample::SCALE as f32 * signal) as Sample; | ||
| 83 | sample[0] = value; | 62 | sample[0] = value; |
| 84 | } | 63 | } |
| 85 | }; | 64 | }; |
| 86 | 65 | ||
| 87 | generate(buffers[0].as_mut().as_mut_slice()); | 66 | generate(buffers[0].as_mut()); |
| 88 | generate(buffers[1].as_mut().as_mut_slice()); | 67 | generate(buffers[1].as_mut()); |
| 89 | 68 | ||
| 90 | i2s.start(buffers[0].as_ref().as_slice()).expect("I2S Start"); | 69 | i2s.start(buffers[0].as_ref()).await.expect("I2S Start"); |
| 91 | 70 | ||
| 92 | let mut index = 1; | 71 | let mut index = 1; |
| 93 | loop { | 72 | loop { |
| 94 | if let Err(err) = i2s.send(buffers[index].as_ref().as_slice()).await { | 73 | if let Err(err) = i2s.send(buffers[index].as_ref()).await { |
| 95 | error!("{}", err); | 74 | error!("{}", err); |
| 96 | } | 75 | } |
| 97 | 76 | ||
| @@ -99,7 +78,7 @@ async fn main(_spawner: Spawner) { | |||
| 99 | if index >= 3 { | 78 | if index >= 3 { |
| 100 | index = 0; | 79 | index = 0; |
| 101 | } | 80 | } |
| 102 | generate(buffers[index].as_mut().as_mut_slice()); | 81 | generate(buffers[index].as_mut()); |
| 103 | } | 82 | } |
| 104 | } | 83 | } |
| 105 | 84 | ||
