aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-nrf/src/chips/nrf52832.rs7
-rw-r--r--embassy-nrf/src/chips/nrf52833.rs7
-rw-r--r--embassy-nrf/src/chips/nrf52840.rs7
-rw-r--r--embassy-nrf/src/i2s.rs1141
-rw-r--r--embassy-nrf/src/lib.rs2
-rw-r--r--examples/nrf/src/bin/i2s_effect.rs117
-rw-r--r--examples/nrf/src/bin/i2s_monitor.rs115
-rw-r--r--examples/nrf/src/bin/i2s_waveform.rs151
8 files changed, 1544 insertions, 3 deletions
diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs
index 879600adb..152dad4e3 100644
--- a/embassy-nrf/src/chips/nrf52832.rs
+++ b/embassy-nrf/src/chips/nrf52832.rs
@@ -138,6 +138,9 @@ embassy_hal_common::peripherals! {
138 138
139 // QDEC 139 // QDEC
140 QDEC, 140 QDEC,
141
142 // I2S
143 I2S,
141} 144}
142 145
143impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); 146impl_uarte!(UARTE0, UARTE0, UARTE0_UART0);
@@ -241,6 +244,8 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5);
241impl_saadc_input!(P0_30, ANALOG_INPUT6); 244impl_saadc_input!(P0_30, ANALOG_INPUT6);
242impl_saadc_input!(P0_31, ANALOG_INPUT7); 245impl_saadc_input!(P0_31, ANALOG_INPUT7);
243 246
247impl_i2s!(I2S, I2S, I2S);
248
244pub mod irqs { 249pub mod irqs {
245 use embassy_cortex_m::interrupt::_export::declare; 250 use embassy_cortex_m::interrupt::_export::declare;
246 251
@@ -281,6 +286,6 @@ pub mod irqs {
281 declare!(PWM2); 286 declare!(PWM2);
282 declare!(SPIM2_SPIS2_SPI2); 287 declare!(SPIM2_SPIS2_SPI2);
283 declare!(RTC2); 288 declare!(RTC2);
284 declare!(I2S);
285 declare!(FPU); 289 declare!(FPU);
290 declare!(I2S);
286} 291}
diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs
index d406c32c2..a99ca6343 100644
--- a/embassy-nrf/src/chips/nrf52833.rs
+++ b/embassy-nrf/src/chips/nrf52833.rs
@@ -161,6 +161,9 @@ embassy_hal_common::peripherals! {
161 161
162 // PDM 162 // PDM
163 PDM, 163 PDM,
164
165 // I2S
166 I2S,
164} 167}
165 168
166#[cfg(feature = "nightly")] 169#[cfg(feature = "nightly")]
@@ -287,6 +290,8 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5);
287impl_saadc_input!(P0_30, ANALOG_INPUT6); 290impl_saadc_input!(P0_30, ANALOG_INPUT6);
288impl_saadc_input!(P0_31, ANALOG_INPUT7); 291impl_saadc_input!(P0_31, ANALOG_INPUT7);
289 292
293impl_i2s!(I2S, I2S, I2S);
294
290pub mod irqs { 295pub mod irqs {
291 use embassy_cortex_m::interrupt::_export::declare; 296 use embassy_cortex_m::interrupt::_export::declare;
292 297
@@ -327,10 +332,10 @@ pub mod irqs {
327 declare!(PWM2); 332 declare!(PWM2);
328 declare!(SPIM2_SPIS2_SPI2); 333 declare!(SPIM2_SPIS2_SPI2);
329 declare!(RTC2); 334 declare!(RTC2);
330 declare!(I2S);
331 declare!(FPU); 335 declare!(FPU);
332 declare!(USBD); 336 declare!(USBD);
333 declare!(UARTE1); 337 declare!(UARTE1);
334 declare!(PWM3); 338 declare!(PWM3);
335 declare!(SPIM3); 339 declare!(SPIM3);
340 declare!(I2S);
336} 341}
diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs
index f9e271c97..4f7463be2 100644
--- a/embassy-nrf/src/chips/nrf52840.rs
+++ b/embassy-nrf/src/chips/nrf52840.rs
@@ -164,6 +164,9 @@ embassy_hal_common::peripherals! {
164 164
165 // PDM 165 // PDM
166 PDM, 166 PDM,
167
168 // I2S
169 I2S,
167} 170}
168 171
169#[cfg(feature = "nightly")] 172#[cfg(feature = "nightly")]
@@ -292,6 +295,8 @@ impl_saadc_input!(P0_29, ANALOG_INPUT5);
292impl_saadc_input!(P0_30, ANALOG_INPUT6); 295impl_saadc_input!(P0_30, ANALOG_INPUT6);
293impl_saadc_input!(P0_31, ANALOG_INPUT7); 296impl_saadc_input!(P0_31, ANALOG_INPUT7);
294 297
298impl_i2s!(I2S, I2S, I2S);
299
295pub mod irqs { 300pub mod irqs {
296 use embassy_cortex_m::interrupt::_export::declare; 301 use embassy_cortex_m::interrupt::_export::declare;
297 302
@@ -332,7 +337,6 @@ pub mod irqs {
332 declare!(PWM2); 337 declare!(PWM2);
333 declare!(SPIM2_SPIS2_SPI2); 338 declare!(SPIM2_SPIS2_SPI2);
334 declare!(RTC2); 339 declare!(RTC2);
335 declare!(I2S);
336 declare!(FPU); 340 declare!(FPU);
337 declare!(USBD); 341 declare!(USBD);
338 declare!(UARTE1); 342 declare!(UARTE1);
@@ -340,4 +344,5 @@ pub mod irqs {
340 declare!(CRYPTOCELL); 344 declare!(CRYPTOCELL);
341 declare!(PWM3); 345 declare!(PWM3);
342 declare!(SPIM3); 346 declare!(SPIM3);
347 declare!(I2S);
343} 348}
diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs
new file mode 100644
index 000000000..7e9507751
--- /dev/null
+++ b/embassy-nrf/src/i2s.rs
@@ -0,0 +1,1141 @@
1#![macro_use]
2
3//! Support for I2S audio
4
5use core::future::poll_fn;
6use core::marker::PhantomData;
7use core::mem::size_of;
8use core::ops::{Deref, DerefMut};
9use core::sync::atomic::{compiler_fence, Ordering};
10use core::task::Poll;
11
12use embassy_cortex_m::interrupt::InterruptExt;
13use embassy_hal_common::drop::OnDrop;
14use embassy_hal_common::{into_ref, PeripheralRef};
15
16use crate::gpio::{AnyPin, Pin as GpioPin};
17use crate::interrupt::Interrupt;
18use crate::pac::i2s::RegisterBlock;
19use crate::util::{slice_in_ram_or, slice_ptr_parts};
20use crate::{Peripheral, EASY_DMA_SIZE};
21
22pub type DoubleBuffering<S, const NS: usize> = MultiBuffering<S, 2, NS>;
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26#[non_exhaustive]
27pub enum Error {
28 BufferTooLong,
29 BufferZeroLength,
30 BufferNotInDataMemory,
31 BufferMisaligned,
32 BufferLengthMisaligned,
33}
34
35/// I2S configuration.
36#[derive(Clone)]
37#[non_exhaustive]
38pub struct Config {
39 pub sample_width: SampleWidth,
40 pub align: Align,
41 pub format: Format,
42 pub channels: Channels,
43}
44
45impl Config {
46 pub fn sample_width(mut self, sample_width: SampleWidth) -> Self {
47 self.sample_width = sample_width;
48 self
49 }
50
51 pub fn align(mut self, align: Align) -> Self {
52 self.align = align;
53 self
54 }
55
56 pub fn format(mut self, format: Format) -> Self {
57 self.format = format;
58 self
59 }
60
61 pub fn channels(mut self, channels: Channels) -> Self {
62 self.channels = channels;
63 self
64 }
65}
66
67impl Default for Config {
68 fn default() -> Self {
69 Self {
70 sample_width: SampleWidth::_16bit,
71 align: Align::Left,
72 format: Format::I2S,
73 channels: Channels::Stereo,
74 }
75 }
76}
77
78/// I2S Mode
79#[derive(Debug, Eq, PartialEq, Clone, Copy)]
80pub struct MasterClock {
81 freq: MckFreq,
82 ratio: Ratio,
83}
84
85impl MasterClock {
86 pub fn new(freq: MckFreq, ratio: Ratio) -> Self {
87 Self { freq, ratio }
88 }
89}
90
91impl MasterClock {
92 pub fn sample_rate(&self) -> u32 {
93 self.freq.to_frequency() / self.ratio.to_divisor()
94 }
95}
96
97/// Master clock generator frequency.
98#[derive(Debug, Eq, PartialEq, Clone, Copy)]
99pub enum MckFreq {
100 _32MDiv8,
101 _32MDiv10,
102 _32MDiv11,
103 _32MDiv15,
104 _32MDiv16,
105 _32MDiv21,
106 _32MDiv23,
107 _32MDiv30,
108 _32MDiv31,
109 _32MDiv32,
110 _32MDiv42,
111 _32MDiv63,
112 _32MDiv125,
113}
114
115impl MckFreq {
116 const REGISTER_VALUES: &'static [u32] = &[
117 0x20000000, 0x18000000, 0x16000000, 0x11000000, 0x10000000, 0x0C000000, 0x0B000000, 0x08800000, 0x08400000,
118 0x08000000, 0x06000000, 0x04100000, 0x020C0000,
119 ];
120
121 const FREQUENCIES: &'static [u32] = &[
122 4000000, 3200000, 2909090, 2133333, 2000000, 1523809, 1391304, 1066666, 1032258, 1000000, 761904, 507936,
123 256000,
124 ];
125
126 /// Return the value that needs to be written to the register.
127 pub fn to_register_value(&self) -> u32 {
128 Self::REGISTER_VALUES[usize::from(*self)]
129 }
130
131 /// Return the master clock frequency.
132 pub fn to_frequency(&self) -> u32 {
133 Self::FREQUENCIES[usize::from(*self)]
134 }
135}
136
137impl From<MckFreq> for usize {
138 fn from(variant: MckFreq) -> Self {
139 variant as _
140 }
141}
142
143/// Master clock frequency ratio
144///
145/// Sample Rate = LRCK = MCK / Ratio
146///
147#[derive(Debug, Eq, PartialEq, Clone, Copy)]
148pub enum Ratio {
149 _32x,
150 _48x,
151 _64x,
152 _96x,
153 _128x,
154 _192x,
155 _256x,
156 _384x,
157 _512x,
158}
159
160impl Ratio {
161 const RATIOS: &'static [u32] = &[32, 48, 64, 96, 128, 192, 256, 384, 512];
162
163 /// Return the value that needs to be written to the register.
164 pub fn to_register_value(&self) -> u8 {
165 usize::from(*self) as u8
166 }
167
168 pub fn to_divisor(&self) -> u32 {
169 Self::RATIOS[usize::from(*self)]
170 }
171}
172
173impl From<Ratio> for usize {
174 fn from(variant: Ratio) -> Self {
175 variant as _
176 }
177}
178
179/// Approximate sample rates.
180///
181/// Those are common sample rates that can not be configured without an small error.
182///
183/// For custom master clock configuration, please refer to [MasterClock].
184#[derive(Clone, Copy)]
185pub enum ApproxSampleRate {
186 _11025,
187 _16000,
188 _22050,
189 _32000,
190 _44100,
191 _48000,
192}
193
194impl From<ApproxSampleRate> for MasterClock {
195 fn from(value: ApproxSampleRate) -> Self {
196 match value {
197 // error = 86
198 ApproxSampleRate::_11025 => MasterClock::new(MckFreq::_32MDiv15, Ratio::_192x),
199 // error = 127
200 ApproxSampleRate::_16000 => MasterClock::new(MckFreq::_32MDiv21, Ratio::_96x),
201 // error = 172
202 ApproxSampleRate::_22050 => MasterClock::new(MckFreq::_32MDiv15, Ratio::_96x),
203 // error = 254
204 ApproxSampleRate::_32000 => MasterClock::new(MckFreq::_32MDiv21, Ratio::_48x),
205 // error = 344
206 ApproxSampleRate::_44100 => MasterClock::new(MckFreq::_32MDiv15, Ratio::_48x),
207 // error = 381
208 ApproxSampleRate::_48000 => MasterClock::new(MckFreq::_32MDiv21, Ratio::_32x),
209 }
210 }
211}
212
213impl ApproxSampleRate {
214 pub fn sample_rate(&self) -> u32 {
215 MasterClock::from(*self).sample_rate()
216 }
217}
218
219/// Exact sample rates.
220///
221/// Those are non standard sample rates that can be configured without error.
222///
223/// For custom master clock configuration, please refer to [Mode].
224#[derive(Clone, Copy)]
225pub enum ExactSampleRate {
226 _8000,
227 _10582,
228 _12500,
229 _15625,
230 _15873,
231 _25000,
232 _31250,
233 _50000,
234 _62500,
235 _100000,
236 _125000,
237}
238
239impl ExactSampleRate {
240 pub fn sample_rate(&self) -> u32 {
241 MasterClock::from(*self).sample_rate()
242 }
243}
244
245impl From<ExactSampleRate> for MasterClock {
246 fn from(value: ExactSampleRate) -> Self {
247 match value {
248 ExactSampleRate::_8000 => MasterClock::new(MckFreq::_32MDiv125, Ratio::_32x),
249 ExactSampleRate::_10582 => MasterClock::new(MckFreq::_32MDiv63, Ratio::_48x),
250 ExactSampleRate::_12500 => MasterClock::new(MckFreq::_32MDiv10, Ratio::_256x),
251 ExactSampleRate::_15625 => MasterClock::new(MckFreq::_32MDiv32, Ratio::_64x),
252 ExactSampleRate::_15873 => MasterClock::new(MckFreq::_32MDiv63, Ratio::_32x),
253 ExactSampleRate::_25000 => MasterClock::new(MckFreq::_32MDiv10, Ratio::_128x),
254 ExactSampleRate::_31250 => MasterClock::new(MckFreq::_32MDiv32, Ratio::_32x),
255 ExactSampleRate::_50000 => MasterClock::new(MckFreq::_32MDiv10, Ratio::_64x),
256 ExactSampleRate::_62500 => MasterClock::new(MckFreq::_32MDiv16, Ratio::_32x),
257 ExactSampleRate::_100000 => MasterClock::new(MckFreq::_32MDiv10, Ratio::_32x),
258 ExactSampleRate::_125000 => MasterClock::new(MckFreq::_32MDiv8, Ratio::_32x),
259 }
260 }
261}
262
263/// Sample width.
264#[derive(Debug, Eq, PartialEq, Clone, Copy)]
265pub enum SampleWidth {
266 _8bit,
267 _16bit,
268 _24bit,
269}
270
271impl From<SampleWidth> for u8 {
272 fn from(variant: SampleWidth) -> Self {
273 variant as _
274 }
275}
276
277/// Channel used for the most significant sample value in a frame.
278#[derive(Debug, Eq, PartialEq, Clone, Copy)]
279pub enum Align {
280 Left,
281 Right,
282}
283
284impl From<Align> for bool {
285 fn from(variant: Align) -> Self {
286 match variant {
287 Align::Left => false,
288 Align::Right => true,
289 }
290 }
291}
292
293/// Frame format.
294#[derive(Debug, Eq, PartialEq, Clone, Copy)]
295pub enum Format {
296 I2S,
297 Aligned,
298}
299
300impl From<Format> for bool {
301 fn from(variant: Format) -> Self {
302 match variant {
303 Format::I2S => false,
304 Format::Aligned => true,
305 }
306 }
307}
308
309/// Channels
310#[derive(Debug, Eq, PartialEq, Clone, Copy)]
311pub enum Channels {
312 Stereo,
313 MonoLeft,
314 MonoRight,
315}
316
317impl From<Channels> for u8 {
318 fn from(variant: Channels) -> Self {
319 variant as _
320 }
321}
322
323/// Interface to the I2S peripheral using EasyDMA to offload the transmission and reception workload.
324pub struct I2S<'d, T: Instance> {
325 i2s: PeripheralRef<'d, T>,
326 irq: PeripheralRef<'d, T::Interrupt>,
327 mck: Option<PeripheralRef<'d, AnyPin>>,
328 sck: PeripheralRef<'d, AnyPin>,
329 lrck: PeripheralRef<'d, AnyPin>,
330 sdin: Option<PeripheralRef<'d, AnyPin>>,
331 sdout: Option<PeripheralRef<'d, AnyPin>>,
332 master_clock: Option<MasterClock>,
333 config: Config,
334}
335
336impl<'d, T: Instance> I2S<'d, T> {
337 /// Create a new I2S in master mode
338 pub fn master(
339 i2s: impl Peripheral<P = T> + 'd,
340 irq: impl Peripheral<P = T::Interrupt> + 'd,
341 mck: impl Peripheral<P = impl GpioPin> + 'd,
342 sck: impl Peripheral<P = impl GpioPin> + 'd,
343 lrck: impl Peripheral<P = impl GpioPin> + 'd,
344 master_clock: MasterClock,
345 config: Config,
346 ) -> Self {
347 into_ref!(i2s, irq, mck, sck, lrck);
348 Self {
349 i2s,
350 irq,
351 mck: Some(mck.map_into()),
352 sck: sck.map_into(),
353 lrck: lrck.map_into(),
354 sdin: None,
355 sdout: None,
356 master_clock: Some(master_clock),
357 config,
358 }
359 }
360
361 /// Create a new I2S in slave mode
362 pub fn slave(
363 i2s: impl Peripheral<P = T> + 'd,
364 irq: impl Peripheral<P = T::Interrupt> + 'd,
365 sck: impl Peripheral<P = impl GpioPin> + 'd,
366 lrck: impl Peripheral<P = impl GpioPin> + 'd,
367 config: Config,
368 ) -> Self {
369 into_ref!(i2s, irq, sck, lrck);
370 Self {
371 i2s,
372 irq,
373 mck: None,
374 sck: sck.map_into(),
375 lrck: lrck.map_into(),
376 sdin: None,
377 sdout: None,
378 master_clock: None,
379 config,
380 }
381 }
382
383 /// I2S output only
384 pub fn output<S: Sample, const NB: usize, const NS: usize>(
385 mut self,
386 sdout: impl Peripheral<P = impl GpioPin> + 'd,
387 buffers: MultiBuffering<S, NB, NS>,
388 ) -> OutputStream<'d, T, S, NB, NS> {
389 self.sdout = Some(sdout.into_ref().map_into());
390 OutputStream {
391 _p: self.build(),
392 buffers,
393 }
394 }
395
396 /// I2S input only
397 pub fn input<S: Sample, const NB: usize, const NS: usize>(
398 mut self,
399 sdin: impl Peripheral<P = impl GpioPin> + 'd,
400 buffers: MultiBuffering<S, NB, NS>,
401 ) -> InputStream<'d, T, S, NB, NS> {
402 self.sdin = Some(sdin.into_ref().map_into());
403 InputStream {
404 _p: self.build(),
405 buffers,
406 }
407 }
408
409 /// I2S full duplex (input and output)
410 pub fn full_duplex<S: Sample, const NB: usize, const NS: usize>(
411 mut self,
412 sdin: impl Peripheral<P = impl GpioPin> + 'd,
413 sdout: impl Peripheral<P = impl GpioPin> + 'd,
414 buffers_out: MultiBuffering<S, NB, NS>,
415 buffers_in: MultiBuffering<S, NB, NS>,
416 ) -> FullDuplexStream<'d, T, S, NB, NS> {
417 self.sdout = Some(sdout.into_ref().map_into());
418 self.sdin = Some(sdin.into_ref().map_into());
419
420 FullDuplexStream {
421 _p: self.build(),
422 buffers_out,
423 buffers_in,
424 }
425 }
426
427 fn build(self) -> PeripheralRef<'d, T> {
428 self.apply_config();
429 self.select_pins();
430 self.setup_interrupt();
431
432 let device = Device::<T>::new();
433 device.enable();
434
435 self.i2s
436 }
437
438 fn apply_config(&self) {
439 let c = &T::regs().config;
440 match &self.master_clock {
441 Some(MasterClock { freq, ratio }) => {
442 c.mode.write(|w| w.mode().master());
443 c.mcken.write(|w| w.mcken().enabled());
444 c.mckfreq
445 .write(|w| unsafe { w.mckfreq().bits(freq.to_register_value()) });
446 c.ratio.write(|w| unsafe { w.ratio().bits(ratio.to_register_value()) });
447 }
448 None => {
449 c.mode.write(|w| w.mode().slave());
450 }
451 };
452
453 c.swidth
454 .write(|w| unsafe { w.swidth().bits(self.config.sample_width.into()) });
455 c.align.write(|w| w.align().bit(self.config.align.into()));
456 c.format.write(|w| w.format().bit(self.config.format.into()));
457 c.channels
458 .write(|w| unsafe { w.channels().bits(self.config.channels.into()) });
459 }
460
461 fn select_pins(&self) {
462 let psel = &T::regs().psel;
463
464 if let Some(mck) = &self.mck {
465 psel.mck.write(|w| {
466 unsafe { w.bits(mck.psel_bits()) };
467 w.connect().connected()
468 });
469 }
470
471 psel.sck.write(|w| {
472 unsafe { w.bits(self.sck.psel_bits()) };
473 w.connect().connected()
474 });
475
476 psel.lrck.write(|w| {
477 unsafe { w.bits(self.lrck.psel_bits()) };
478 w.connect().connected()
479 });
480
481 if let Some(sdin) = &self.sdin {
482 psel.sdin.write(|w| {
483 unsafe { w.bits(sdin.psel_bits()) };
484 w.connect().connected()
485 });
486 }
487
488 if let Some(sdout) = &self.sdout {
489 psel.sdout.write(|w| {
490 unsafe { w.bits(sdout.psel_bits()) };
491 w.connect().connected()
492 });
493 }
494 }
495
496 fn setup_interrupt(&self) {
497 self.irq.set_handler(Self::on_interrupt);
498 self.irq.unpend();
499 self.irq.enable();
500
501 let device = Device::<T>::new();
502 device.disable_tx_ptr_interrupt();
503 device.disable_rx_ptr_interrupt();
504 device.disable_stopped_interrupt();
505
506 device.reset_tx_ptr_event();
507 device.reset_rx_ptr_event();
508 device.reset_stopped_event();
509
510 device.enable_tx_ptr_interrupt();
511 device.enable_rx_ptr_interrupt();
512 device.enable_stopped_interrupt();
513 }
514
515 fn on_interrupt(_: *mut ()) {
516 let device = Device::<T>::new();
517 let s = T::state();
518
519 if device.is_tx_ptr_updated() {
520 trace!("TX INT");
521 s.tx_waker.wake();
522 device.disable_tx_ptr_interrupt();
523 }
524
525 if device.is_rx_ptr_updated() {
526 trace!("RX INT");
527 s.rx_waker.wake();
528 device.disable_rx_ptr_interrupt();
529 }
530
531 if device.is_stopped() {
532 trace!("STOPPED INT");
533 s.stop_waker.wake();
534 device.disable_stopped_interrupt();
535 }
536 }
537
538 async fn stop() {
539 compiler_fence(Ordering::SeqCst);
540
541 let device = Device::<T>::new();
542 device.stop();
543
544 T::state().started.store(false, Ordering::Relaxed);
545
546 poll_fn(|cx| {
547 T::state().stop_waker.register(cx.waker());
548
549 if device.is_stopped() {
550 trace!("STOP: Ready");
551 device.reset_stopped_event();
552 Poll::Ready(())
553 } else {
554 trace!("STOP: Pending");
555 Poll::Pending
556 }
557 })
558 .await;
559
560 device.disable();
561 }
562
563 async fn send_from_ram<S>(buffer_ptr: *const [S]) -> Result<(), Error>
564 where
565 S: Sample,
566 {
567 trace!("SEND: {}", buffer_ptr as *const S as u32);
568
569 slice_in_ram_or(buffer_ptr, Error::BufferNotInDataMemory)?;
570
571 compiler_fence(Ordering::SeqCst);
572
573 let device = Device::<T>::new();
574
575 device.update_tx(buffer_ptr)?;
576
577 Self::wait_tx_ptr_update().await;
578
579 compiler_fence(Ordering::SeqCst);
580
581 Ok(())
582 }
583
584 async fn wait_tx_ptr_update() {
585 let drop = OnDrop::new(move || {
586 trace!("TX DROP: Stopping");
587
588 let device = Device::<T>::new();
589 device.disable_tx_ptr_interrupt();
590 device.reset_tx_ptr_event();
591 device.disable_tx();
592
593 // TX is stopped almost instantly, spinning is fine.
594 while !device.is_tx_ptr_updated() {}
595
596 trace!("TX DROP: Stopped");
597 });
598
599 poll_fn(|cx| {
600 T::state().tx_waker.register(cx.waker());
601
602 let device = Device::<T>::new();
603 if device.is_tx_ptr_updated() {
604 trace!("TX POLL: Ready");
605 device.reset_tx_ptr_event();
606 device.enable_tx_ptr_interrupt();
607 Poll::Ready(())
608 } else {
609 trace!("TX POLL: Pending");
610 Poll::Pending
611 }
612 })
613 .await;
614
615 drop.defuse();
616 }
617
618 async fn receive_from_ram<S>(buffer_ptr: *mut [S]) -> Result<(), Error>
619 where
620 S: Sample,
621 {
622 trace!("RECEIVE: {}", buffer_ptr as *const S as u32);
623
624 // NOTE: RAM slice check for rx is not necessary, as a mutable
625 // slice can only be built from data located in RAM.
626
627 compiler_fence(Ordering::SeqCst);
628
629 let device = Device::<T>::new();
630
631 device.update_rx(buffer_ptr)?;
632
633 Self::wait_rx_ptr_update().await;
634
635 compiler_fence(Ordering::SeqCst);
636
637 Ok(())
638 }
639
640 async fn wait_rx_ptr_update() {
641 let drop = OnDrop::new(move || {
642 trace!("RX DROP: Stopping");
643
644 let device = Device::<T>::new();
645 device.disable_rx_ptr_interrupt();
646 device.reset_rx_ptr_event();
647 device.disable_rx();
648
649 // TX is stopped almost instantly, spinning is fine.
650 while !device.is_rx_ptr_updated() {}
651
652 trace!("RX DROP: Stopped");
653 });
654
655 poll_fn(|cx| {
656 T::state().rx_waker.register(cx.waker());
657
658 let device = Device::<T>::new();
659 if device.is_rx_ptr_updated() {
660 trace!("RX POLL: Ready");
661 device.reset_rx_ptr_event();
662 device.enable_rx_ptr_interrupt();
663 Poll::Ready(())
664 } else {
665 trace!("RX POLL: Pending");
666 Poll::Pending
667 }
668 })
669 .await;
670
671 drop.defuse();
672 }
673}
674
675/// I2S output
676pub struct OutputStream<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> {
677 _p: PeripheralRef<'d, T>,
678 buffers: MultiBuffering<S, NB, NS>,
679}
680
681impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> OutputStream<'d, T, S, NB, NS> {
682 /// Get a mutable reference to the current buffer.
683 pub fn buffer(&mut self) -> &mut [S] {
684 self.buffers.get_mut()
685 }
686
687 /// Prepare the initial buffer and start the I2S transfer.
688 pub async fn start(&mut self) -> Result<(), Error>
689 where
690 S: Sample,
691 {
692 let device = Device::<T>::new();
693
694 let s = T::state();
695 if s.started.load(Ordering::Relaxed) {
696 self.stop().await;
697 }
698
699 device.enable();
700 device.enable_tx();
701
702 device.update_tx(self.buffers.switch())?;
703
704 s.started.store(true, Ordering::Relaxed);
705
706 device.start();
707
708 I2S::<T>::wait_tx_ptr_update().await;
709
710 Ok(())
711 }
712
713 /// Stops the I2S transfer and waits until it has stopped.
714 #[inline(always)]
715 pub async fn stop(&self) {
716 I2S::<T>::stop().await
717 }
718
719 /// Sends the current buffer for transmission in the DMA.
720 /// Switches to use the next available buffer.
721 pub async fn send(&mut self) -> Result<(), Error>
722 where
723 S: Sample,
724 {
725 I2S::<T>::send_from_ram(self.buffers.switch()).await
726 }
727}
728
729/// I2S input
730pub struct InputStream<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> {
731 _p: PeripheralRef<'d, T>,
732 buffers: MultiBuffering<S, NB, NS>,
733}
734
735impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> InputStream<'d, T, S, NB, NS> {
736 /// Get a mutable reference to the current buffer.
737 pub fn buffer(&mut self) -> &mut [S] {
738 self.buffers.get_mut()
739 }
740
741 /// Prepare the initial buffer and start the I2S transfer.
742 pub async fn start(&mut self) -> Result<(), Error>
743 where
744 S: Sample,
745 {
746 let device = Device::<T>::new();
747
748 let s = T::state();
749 if s.started.load(Ordering::Relaxed) {
750 self.stop().await;
751 }
752
753 device.enable();
754 device.enable_rx();
755
756 device.update_rx(self.buffers.switch())?;
757
758 s.started.store(true, Ordering::Relaxed);
759
760 device.start();
761
762 I2S::<T>::wait_rx_ptr_update().await;
763
764 Ok(())
765 }
766
767 /// Stops the I2S transfer and waits until it has stopped.
768 #[inline(always)]
769 pub async fn stop(&self) {
770 I2S::<T>::stop().await
771 }
772
773 /// Sets the current buffer for reception from the DMA.
774 /// Switches to use the next available buffer.
775 #[allow(unused_mut)]
776 pub async fn receive(&mut self) -> Result<(), Error>
777 where
778 S: Sample,
779 {
780 I2S::<T>::receive_from_ram(self.buffers.switch_mut()).await
781 }
782}
783
784/// I2S full duplex stream (input & output)
785pub struct FullDuplexStream<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> {
786 _p: PeripheralRef<'d, T>,
787 buffers_out: MultiBuffering<S, NB, NS>,
788 buffers_in: MultiBuffering<S, NB, NS>,
789}
790
791impl<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> FullDuplexStream<'d, T, S, NB, NS> {
792 /// Get the current output and input buffers.
793 pub fn buffers(&mut self) -> (&mut [S], &[S]) {
794 (self.buffers_out.get_mut(), self.buffers_in.get())
795 }
796
797 /// Prepare the initial buffers and start the I2S transfer.
798 pub async fn start(&mut self) -> Result<(), Error>
799 where
800 S: Sample,
801 {
802 let device = Device::<T>::new();
803
804 let s = T::state();
805 if s.started.load(Ordering::Relaxed) {
806 self.stop().await;
807 }
808
809 device.enable();
810 device.enable_tx();
811 device.enable_rx();
812
813 device.update_tx(self.buffers_out.switch())?;
814 device.update_rx(self.buffers_in.switch_mut())?;
815
816 s.started.store(true, Ordering::Relaxed);
817
818 device.start();
819
820 I2S::<T>::wait_tx_ptr_update().await;
821 I2S::<T>::wait_rx_ptr_update().await;
822
823 Ok(())
824 }
825
826 /// Stops the I2S transfer and waits until it has stopped.
827 #[inline(always)]
828 pub async fn stop(&self) {
829 I2S::<T>::stop().await
830 }
831
832 /// Sets the current buffers for output and input for transmission/reception from the DMA.
833 /// Switch to use the next available buffers for output/input.
834 pub async fn send_and_receive(&mut self) -> Result<(), Error>
835 where
836 S: Sample,
837 {
838 I2S::<T>::send_from_ram(self.buffers_out.switch()).await?;
839 I2S::<T>::receive_from_ram(self.buffers_in.switch_mut()).await?;
840 Ok(())
841 }
842}
843
844/// Helper encapsulating common I2S device operations.
845struct Device<T>(&'static RegisterBlock, PhantomData<T>);
846
847impl<T: Instance> Device<T> {
848 fn new() -> Self {
849 Self(T::regs(), PhantomData)
850 }
851
852 #[inline(always)]
853 pub fn enable(&self) {
854 trace!("ENABLED");
855 self.0.enable.write(|w| w.enable().enabled());
856 }
857
858 #[inline(always)]
859 pub fn disable(&self) {
860 trace!("DISABLED");
861 self.0.enable.write(|w| w.enable().disabled());
862 }
863
864 #[inline(always)]
865 fn enable_tx(&self) {
866 trace!("TX ENABLED");
867 self.0.config.txen.write(|w| w.txen().enabled());
868 }
869
870 #[inline(always)]
871 fn disable_tx(&self) {
872 trace!("TX DISABLED");
873 self.0.config.txen.write(|w| w.txen().disabled());
874 }
875
876 #[inline(always)]
877 fn enable_rx(&self) {
878 trace!("RX ENABLED");
879 self.0.config.rxen.write(|w| w.rxen().enabled());
880 }
881
882 #[inline(always)]
883 fn disable_rx(&self) {
884 trace!("RX DISABLED");
885 self.0.config.rxen.write(|w| w.rxen().disabled());
886 }
887
888 #[inline(always)]
889 fn start(&self) {
890 trace!("START");
891 self.0.tasks_start.write(|w| unsafe { w.bits(1) });
892 }
893
894 #[inline(always)]
895 fn stop(&self) {
896 self.0.tasks_stop.write(|w| unsafe { w.bits(1) });
897 }
898
899 #[inline(always)]
900 fn is_stopped(&self) -> bool {
901 self.0.events_stopped.read().bits() != 0
902 }
903
904 #[inline(always)]
905 fn reset_stopped_event(&self) {
906 trace!("STOPPED EVENT: Reset");
907 self.0.events_stopped.reset();
908 }
909
910 #[inline(always)]
911 fn disable_stopped_interrupt(&self) {
912 trace!("STOPPED INTERRUPT: Disabled");
913 self.0.intenclr.write(|w| w.stopped().clear());
914 }
915
916 #[inline(always)]
917 fn enable_stopped_interrupt(&self) {
918 trace!("STOPPED INTERRUPT: Enabled");
919 self.0.intenset.write(|w| w.stopped().set());
920 }
921
922 #[inline(always)]
923 fn reset_tx_ptr_event(&self) {
924 trace!("TX PTR EVENT: Reset");
925 self.0.events_txptrupd.reset();
926 }
927
928 #[inline(always)]
929 fn reset_rx_ptr_event(&self) {
930 trace!("RX PTR EVENT: Reset");
931 self.0.events_rxptrupd.reset();
932 }
933
934 #[inline(always)]
935 fn disable_tx_ptr_interrupt(&self) {
936 trace!("TX PTR INTERRUPT: Disabled");
937 self.0.intenclr.write(|w| w.txptrupd().clear());
938 }
939
940 #[inline(always)]
941 fn disable_rx_ptr_interrupt(&self) {
942 trace!("RX PTR INTERRUPT: Disabled");
943 self.0.intenclr.write(|w| w.rxptrupd().clear());
944 }
945
946 #[inline(always)]
947 fn enable_tx_ptr_interrupt(&self) {
948 trace!("TX PTR INTERRUPT: Enabled");
949 self.0.intenset.write(|w| w.txptrupd().set());
950 }
951
952 #[inline(always)]
953 fn enable_rx_ptr_interrupt(&self) {
954 trace!("RX PTR INTERRUPT: Enabled");
955 self.0.intenset.write(|w| w.rxptrupd().set());
956 }
957
958 #[inline(always)]
959 fn is_tx_ptr_updated(&self) -> bool {
960 self.0.events_txptrupd.read().bits() != 0
961 }
962
963 #[inline(always)]
964 fn is_rx_ptr_updated(&self) -> bool {
965 self.0.events_rxptrupd.read().bits() != 0
966 }
967
968 #[inline]
969 fn update_tx<S>(&self, buffer_ptr: *const [S]) -> Result<(), Error> {
970 let (ptr, maxcnt) = Self::validated_dma_parts(buffer_ptr)?;
971 self.0.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) });
972 self.0.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr) });
973 Ok(())
974 }
975
976 #[inline]
977 fn update_rx<S>(&self, buffer_ptr: *const [S]) -> Result<(), Error> {
978 let (ptr, maxcnt) = Self::validated_dma_parts(buffer_ptr)?;
979 self.0.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) });
980 self.0.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr) });
981 Ok(())
982 }
983
984 fn validated_dma_parts<S>(buffer_ptr: *const [S]) -> Result<(u32, u32), Error> {
985 let (ptr, len) = slice_ptr_parts(buffer_ptr);
986 let ptr = ptr as u32;
987 let bytes_len = len * size_of::<S>();
988 let maxcnt = (bytes_len / size_of::<u32>()) as u32;
989
990 trace!("PTR={}, MAXCNT={}", ptr, maxcnt);
991
992 if ptr % 4 != 0 {
993 Err(Error::BufferMisaligned)
994 } else if bytes_len % 4 != 0 {
995 Err(Error::BufferLengthMisaligned)
996 } else if maxcnt as usize > EASY_DMA_SIZE {
997 Err(Error::BufferTooLong)
998 } else {
999 Ok((ptr, maxcnt))
1000 }
1001 }
1002}
1003
1004/// Sample details
1005pub trait Sample: Sized + Copy + Default {
1006 const WIDTH: usize;
1007 const SCALE: Self;
1008}
1009
1010impl Sample for i8 {
1011 const WIDTH: usize = 8;
1012 const SCALE: Self = 1 << (Self::WIDTH - 1);
1013}
1014
1015impl Sample for i16 {
1016 const WIDTH: usize = 16;
1017 const SCALE: Self = 1 << (Self::WIDTH - 1);
1018}
1019
1020impl Sample for i32 {
1021 const WIDTH: usize = 24;
1022 const SCALE: Self = 1 << (Self::WIDTH - 1);
1023}
1024
1025/// A 4-bytes aligned buffer.
1026#[derive(Clone, Copy)]
1027#[repr(align(4))]
1028pub struct AlignedBuffer<T: Sample, const N: usize>([T; N]);
1029
1030impl<T: Sample, const N: usize> AlignedBuffer<T, N> {
1031 pub fn new(array: [T; N]) -> Self {
1032 Self(array)
1033 }
1034}
1035
1036impl<T: Sample, const N: usize> Default for AlignedBuffer<T, N> {
1037 fn default() -> Self {
1038 Self([T::default(); N])
1039 }
1040}
1041
1042impl<T: Sample, const N: usize> Deref for AlignedBuffer<T, N> {
1043 type Target = [T];
1044 fn deref(&self) -> &Self::Target {
1045 self.0.as_slice()
1046 }
1047}
1048
1049impl<T: Sample, const N: usize> DerefMut for AlignedBuffer<T, N> {
1050 fn deref_mut(&mut self) -> &mut Self::Target {
1051 self.0.as_mut_slice()
1052 }
1053}
1054
1055pub struct MultiBuffering<S: Sample, const NB: usize, const NS: usize> {
1056 buffers: [AlignedBuffer<S, NS>; NB],
1057 index: usize,
1058}
1059
1060impl<S: Sample, const NB: usize, const NS: usize> MultiBuffering<S, NB, NS> {
1061 pub fn new() -> Self {
1062 assert!(NB > 1);
1063 Self {
1064 buffers: [AlignedBuffer::<S, NS>::default(); NB],
1065 index: 0,
1066 }
1067 }
1068
1069 fn get(&self) -> &[S] {
1070 &self.buffers[self.index]
1071 }
1072
1073 fn get_mut(&mut self) -> &mut [S] {
1074 &mut self.buffers[self.index]
1075 }
1076
1077 /// Advance to use the next buffer and return a non mutable pointer to the previous one.
1078 fn switch(&mut self) -> *const [S] {
1079 let prev_index = self.index;
1080 self.index = (self.index + 1) % NB;
1081 self.buffers[prev_index].deref() as *const [S]
1082 }
1083
1084 /// Advance to use the next buffer and return a mutable pointer to the previous one.
1085 fn switch_mut(&mut self) -> *mut [S] {
1086 let prev_index = self.index;
1087 self.index = (self.index + 1) % NB;
1088 self.buffers[prev_index].deref_mut() as *mut [S]
1089 }
1090}
1091
1092pub(crate) mod sealed {
1093 use core::sync::atomic::AtomicBool;
1094
1095 use embassy_sync::waitqueue::AtomicWaker;
1096
1097 /// Peripheral static state
1098 pub struct State {
1099 pub started: AtomicBool,
1100 pub rx_waker: AtomicWaker,
1101 pub tx_waker: AtomicWaker,
1102 pub stop_waker: AtomicWaker,
1103 }
1104
1105 impl State {
1106 pub const fn new() -> Self {
1107 Self {
1108 started: AtomicBool::new(false),
1109 rx_waker: AtomicWaker::new(),
1110 tx_waker: AtomicWaker::new(),
1111 stop_waker: AtomicWaker::new(),
1112 }
1113 }
1114 }
1115
1116 pub trait Instance {
1117 fn regs() -> &'static crate::pac::i2s::RegisterBlock;
1118 fn state() -> &'static State;
1119 }
1120}
1121
1122pub trait Instance: Peripheral<P = Self> + sealed::Instance + 'static + Send {
1123 type Interrupt: Interrupt;
1124}
1125
1126macro_rules! impl_i2s {
1127 ($type:ident, $pac_type:ident, $irq:ident) => {
1128 impl crate::i2s::sealed::Instance for peripherals::$type {
1129 fn regs() -> &'static crate::pac::i2s::RegisterBlock {
1130 unsafe { &*pac::$pac_type::ptr() }
1131 }
1132 fn state() -> &'static crate::i2s::sealed::State {
1133 static STATE: crate::i2s::sealed::State = crate::i2s::sealed::State::new();
1134 &STATE
1135 }
1136 }
1137 impl crate::i2s::Instance for peripherals::$type {
1138 type Interrupt = crate::interrupt::$irq;
1139 }
1140 };
1141}
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs
index 9054bc300..4832e143f 100644
--- a/embassy-nrf/src/lib.rs
+++ b/embassy-nrf/src/lib.rs
@@ -78,6 +78,8 @@ pub mod buffered_uarte;
78pub mod gpio; 78pub mod gpio;
79#[cfg(feature = "gpiote")] 79#[cfg(feature = "gpiote")]
80pub mod gpiote; 80pub mod gpiote;
81#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
82pub mod i2s;
81#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))] 83#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
82pub mod nvmc; 84pub mod nvmc;
83#[cfg(any( 85#[cfg(any(
diff --git a/examples/nrf/src/bin/i2s_effect.rs b/examples/nrf/src/bin/i2s_effect.rs
new file mode 100644
index 000000000..3cca005b1
--- /dev/null
+++ b/examples/nrf/src/bin/i2s_effect.rs
@@ -0,0 +1,117 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::f32::consts::PI;
6
7use defmt::{error, info};
8use embassy_executor::Spawner;
9use embassy_nrf::i2s::{self, Channels, Config, MasterClock, MultiBuffering, Sample as _, SampleWidth, I2S};
10use embassy_nrf::interrupt;
11use {defmt_rtt as _, panic_probe as _};
12
13type Sample = i16;
14
15const NUM_BUFFERS: usize = 2;
16const NUM_SAMPLES: usize = 4;
17
18#[embassy_executor::main]
19async fn main(_spawner: Spawner) {
20 let p = embassy_nrf::init(Default::default());
21
22 let master_clock: MasterClock = i2s::ExactSampleRate::_50000.into();
23
24 let sample_rate = master_clock.sample_rate();
25 info!("Sample rate: {}", sample_rate);
26
27 let config = Config::default()
28 .sample_width(SampleWidth::_16bit)
29 .channels(Channels::MonoLeft);
30
31 let irq = interrupt::take!(I2S);
32 let buffers_out = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new();
33 let buffers_in = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new();
34 let mut full_duplex_stream = I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).full_duplex(
35 p.P0_29,
36 p.P0_28,
37 buffers_out,
38 buffers_in,
39 );
40
41 let mut modulator = SineOsc::new();
42 modulator.set_frequency(8.0, 1.0 / sample_rate as f32);
43 modulator.set_amplitude(1.0);
44
45 full_duplex_stream.start().await.expect("I2S Start");
46
47 loop {
48 let (buff_out, buff_in) = full_duplex_stream.buffers();
49 for i in 0..NUM_SAMPLES {
50 let modulation = (Sample::SCALE as f32 * bipolar_to_unipolar(modulator.generate())) as Sample;
51 buff_out[i] = buff_in[i] * modulation;
52 }
53
54 if let Err(err) = full_duplex_stream.send_and_receive().await {
55 error!("{}", err);
56 }
57 }
58}
59
60struct SineOsc {
61 amplitude: f32,
62 modulo: f32,
63 phase_inc: f32,
64}
65
66impl SineOsc {
67 const B: f32 = 4.0 / PI;
68 const C: f32 = -4.0 / (PI * PI);
69 const P: f32 = 0.225;
70
71 pub fn new() -> Self {
72 Self {
73 amplitude: 1.0,
74 modulo: 0.0,
75 phase_inc: 0.0,
76 }
77 }
78
79 pub fn set_frequency(&mut self, freq: f32, inv_sample_rate: f32) {
80 self.phase_inc = freq * inv_sample_rate;
81 }
82
83 pub fn set_amplitude(&mut self, amplitude: f32) {
84 self.amplitude = amplitude;
85 }
86
87 pub fn generate(&mut self) -> f32 {
88 let signal = self.parabolic_sin(self.modulo);
89 self.modulo += self.phase_inc;
90 if self.modulo < 0.0 {
91 self.modulo += 1.0;
92 } else if self.modulo > 1.0 {
93 self.modulo -= 1.0;
94 }
95 signal * self.amplitude
96 }
97
98 fn parabolic_sin(&mut self, modulo: f32) -> f32 {
99 let angle = PI - modulo * 2.0 * PI;
100 let y = Self::B * angle + Self::C * angle * abs(angle);
101 Self::P * (y * abs(y) - y) + y
102 }
103}
104
105#[inline]
106fn abs(value: f32) -> f32 {
107 if value < 0.0 {
108 -value
109 } else {
110 value
111 }
112}
113
114#[inline]
115fn bipolar_to_unipolar(value: f32) -> f32 {
116 (value + 1.0) / 2.0
117}
diff --git a/examples/nrf/src/bin/i2s_monitor.rs b/examples/nrf/src/bin/i2s_monitor.rs
new file mode 100644
index 000000000..48eb7d581
--- /dev/null
+++ b/examples/nrf/src/bin/i2s_monitor.rs
@@ -0,0 +1,115 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{debug, error, info};
6use embassy_executor::Spawner;
7use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S};
8use embassy_nrf::interrupt;
9use embassy_nrf::pwm::{Prescaler, SimplePwm};
10use {defmt_rtt as _, panic_probe as _};
11
12type Sample = i16;
13
14const NUM_SAMPLES: usize = 500;
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let p = embassy_nrf::init(Default::default());
19
20 let master_clock: MasterClock = i2s::ExactSampleRate::_50000.into();
21
22 let sample_rate = master_clock.sample_rate();
23 info!("Sample rate: {}", sample_rate);
24
25 let config = Config::default()
26 .sample_width(SampleWidth::_16bit)
27 .channels(Channels::MonoLeft);
28
29 let irq = interrupt::take!(I2S);
30 let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
31 let mut input_stream =
32 I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).input(p.P0_29, buffers);
33
34 // Configure the PWM to use the pins corresponding to the RGB leds
35 let mut pwm = SimplePwm::new_3ch(p.PWM0, p.P0_23, p.P0_22, p.P0_24);
36 pwm.set_prescaler(Prescaler::Div1);
37 pwm.set_max_duty(255);
38
39 let mut rms_online = RmsOnline::<NUM_SAMPLES>::default();
40
41 input_stream.start().await.expect("I2S Start");
42
43 loop {
44 let rms = rms_online.process(input_stream.buffer());
45 let rgb = rgb_from_rms(rms);
46
47 debug!("RMS: {}, RGB: {:?}", rms, rgb);
48 for i in 0..3 {
49 pwm.set_duty(i, rgb[i].into());
50 }
51
52 if let Err(err) = input_stream.receive().await {
53 error!("{}", err);
54 }
55 }
56}
57
58/// RMS from 0.0 until 0.75 will give green with a proportional intensity
59/// RMS from 0.75 until 0.9 will give a blend between orange and red proportionally to the intensity
60/// RMS above 0.9 will give a red with a proportional intensity
61fn rgb_from_rms(rms: f32) -> [u8; 3] {
62 if rms < 0.75 {
63 let intensity = rms / 0.75;
64 [0, (intensity * 165.0) as u8, 0]
65 } else if rms < 0.9 {
66 let intensity = (rms - 0.75) / 0.15;
67 [200, 165 - (165.0 * intensity) as u8, 0]
68 } else {
69 let intensity = (rms - 0.9) / 0.1;
70 [200 + (55.0 * intensity) as u8, 0, 0]
71 }
72}
73
74pub struct RmsOnline<const N: usize> {
75 pub squares: [f32; N],
76 pub head: usize,
77}
78
79impl<const N: usize> Default for RmsOnline<N> {
80 fn default() -> Self {
81 RmsOnline {
82 squares: [0.0; N],
83 head: 0,
84 }
85 }
86}
87
88impl<const N: usize> RmsOnline<N> {
89 pub fn reset(&mut self) {
90 self.squares = [0.0; N];
91 self.head = 0;
92 }
93
94 pub fn process(&mut self, buf: &[Sample]) -> f32 {
95 buf.iter()
96 .for_each(|sample| self.push(*sample as f32 / Sample::SCALE as f32));
97
98 let sum_of_squares = self.squares.iter().fold(0.0, |acc, v| acc + *v);
99 Self::approx_sqrt(sum_of_squares / N as f32)
100 }
101
102 pub fn push(&mut self, signal: f32) {
103 let square = signal * signal;
104 self.squares[self.head] = square;
105 self.head = (self.head + 1) % N;
106 }
107
108 /// Approximated sqrt taken from [micromath]
109 ///
110 /// [micromath]: https://docs.rs/micromath/latest/src/micromath/float/sqrt.rs.html#11-17
111 ///
112 fn approx_sqrt(value: f32) -> f32 {
113 f32::from_bits((value.to_bits() + 0x3f80_0000) >> 1)
114 }
115}
diff --git a/examples/nrf/src/bin/i2s_waveform.rs b/examples/nrf/src/bin/i2s_waveform.rs
new file mode 100644
index 000000000..1b0e8ebc8
--- /dev/null
+++ b/examples/nrf/src/bin/i2s_waveform.rs
@@ -0,0 +1,151 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::f32::consts::PI;
6
7use defmt::{error, info};
8use embassy_executor::Spawner;
9use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S};
10use embassy_nrf::interrupt;
11use {defmt_rtt as _, panic_probe as _};
12
13type Sample = i16;
14
15const NUM_SAMPLES: usize = 50;
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let p = embassy_nrf::init(Default::default());
20
21 let master_clock: MasterClock = i2s::ExactSampleRate::_50000.into();
22
23 let sample_rate = master_clock.sample_rate();
24 info!("Sample rate: {}", sample_rate);
25
26 let config = Config::default()
27 .sample_width(SampleWidth::_16bit)
28 .channels(Channels::MonoLeft);
29
30 let irq = interrupt::take!(I2S);
31 let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
32 let mut output_stream =
33 I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).output(p.P0_28, buffers);
34
35 let mut waveform = Waveform::new(1.0 / sample_rate as f32);
36
37 waveform.process(output_stream.buffer());
38
39 output_stream.start().await.expect("I2S Start");
40
41 loop {
42 waveform.process(output_stream.buffer());
43
44 if let Err(err) = output_stream.send().await {
45 error!("{}", err);
46 }
47 }
48}
49
50struct Waveform {
51 inv_sample_rate: f32,
52 carrier: SineOsc,
53 freq_mod: SineOsc,
54 amp_mod: SineOsc,
55}
56
57impl Waveform {
58 fn new(inv_sample_rate: f32) -> Self {
59 let mut carrier = SineOsc::new();
60 carrier.set_frequency(110.0, inv_sample_rate);
61
62 let mut freq_mod = SineOsc::new();
63 freq_mod.set_frequency(1.0, inv_sample_rate);
64 freq_mod.set_amplitude(1.0);
65
66 let mut amp_mod = SineOsc::new();
67 amp_mod.set_frequency(16.0, inv_sample_rate);
68 amp_mod.set_amplitude(0.5);
69
70 Self {
71 inv_sample_rate,
72 carrier,
73 freq_mod,
74 amp_mod,
75 }
76 }
77
78 fn process(&mut self, buf: &mut [Sample]) {
79 for sample in buf.chunks_mut(1) {
80 let freq_modulation = bipolar_to_unipolar(self.freq_mod.generate());
81 self.carrier
82 .set_frequency(110.0 + 440.0 * freq_modulation, self.inv_sample_rate);
83
84 let amp_modulation = bipolar_to_unipolar(self.amp_mod.generate());
85 self.carrier.set_amplitude(amp_modulation);
86
87 let signal = self.carrier.generate();
88
89 sample[0] = (Sample::SCALE as f32 * signal) as Sample;
90 }
91 }
92}
93
94struct SineOsc {
95 amplitude: f32,
96 modulo: f32,
97 phase_inc: f32,
98}
99
100impl SineOsc {
101 const B: f32 = 4.0 / PI;
102 const C: f32 = -4.0 / (PI * PI);
103 const P: f32 = 0.225;
104
105 pub fn new() -> Self {
106 Self {
107 amplitude: 1.0,
108 modulo: 0.0,
109 phase_inc: 0.0,
110 }
111 }
112
113 pub fn set_frequency(&mut self, freq: f32, inv_sample_rate: f32) {
114 self.phase_inc = freq * inv_sample_rate;
115 }
116
117 pub fn set_amplitude(&mut self, amplitude: f32) {
118 self.amplitude = amplitude;
119 }
120
121 pub fn generate(&mut self) -> f32 {
122 let signal = self.parabolic_sin(self.modulo);
123 self.modulo += self.phase_inc;
124 if self.modulo < 0.0 {
125 self.modulo += 1.0;
126 } else if self.modulo > 1.0 {
127 self.modulo -= 1.0;
128 }
129 signal * self.amplitude
130 }
131
132 fn parabolic_sin(&mut self, modulo: f32) -> f32 {
133 let angle = PI - modulo * 2.0 * PI;
134 let y = Self::B * angle + Self::C * angle * abs(angle);
135 Self::P * (y * abs(y) - y) + y
136 }
137}
138
139#[inline]
140fn abs(value: f32) -> f32 {
141 if value < 0.0 {
142 -value
143 } else {
144 value
145 }
146}
147
148#[inline]
149fn bipolar_to_unipolar(value: f32) -> f32 {
150 (value + 1.0) / 2.0
151}