aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Perez Llamas <[email protected]>2022-12-08 20:22:50 +0100
committerChristian Perez Llamas <[email protected]>2022-12-08 20:22:50 +0100
commit5fdd521a767fd8825a2d55d6b833fd99627353d7 (patch)
tree906f042f5da59d68335c95c0e7a52045a120b7d6
parent199504be564b231154e07c58bcc52b11afdc9fe7 (diff)
Move the responsibility to manage buffers to the I2S stream
-rw-r--r--embassy-nrf/src/i2s.rs157
-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.rs26
4 files changed, 353 insertions, 62 deletions
diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs
index 08d4093f2..7e9507751 100644
--- a/embassy-nrf/src/i2s.rs
+++ b/embassy-nrf/src/i2s.rs
@@ -19,6 +19,8 @@ use crate::pac::i2s::RegisterBlock;
19use crate::util::{slice_in_ram_or, slice_ptr_parts}; 19use crate::util::{slice_in_ram_or, slice_ptr_parts};
20use crate::{Peripheral, EASY_DMA_SIZE}; 20use crate::{Peripheral, EASY_DMA_SIZE};
21 21
22pub type DoubleBuffering<S, const NS: usize> = MultiBuffering<S, 2, NS>;
23
22#[derive(Debug, Clone, Copy, PartialEq, Eq)] 24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23#[cfg_attr(feature = "defmt", derive(defmt::Format))] 25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
24#[non_exhaustive] 26#[non_exhaustive]
@@ -379,27 +381,47 @@ impl<'d, T: Instance> I2S<'d, T> {
379 } 381 }
380 382
381 /// I2S output only 383 /// I2S output only
382 pub fn output(mut self, sdout: impl Peripheral<P = impl GpioPin> + 'd) -> OutputStream<'d, T> { 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> {
383 self.sdout = Some(sdout.into_ref().map_into()); 389 self.sdout = Some(sdout.into_ref().map_into());
384 OutputStream { _p: self.build() } 390 OutputStream {
391 _p: self.build(),
392 buffers,
393 }
385 } 394 }
386 395
387 /// I2S input only 396 /// I2S input only
388 pub fn input(mut self, sdin: impl Peripheral<P = impl GpioPin> + 'd) -> InputStream<'d, T> { 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> {
389 self.sdin = Some(sdin.into_ref().map_into()); 402 self.sdin = Some(sdin.into_ref().map_into());
390 InputStream { _p: self.build() } 403 InputStream {
404 _p: self.build(),
405 buffers,
406 }
391 } 407 }
392 408
393 /// I2S full duplex (input and output) 409 /// I2S full duplex (input and output)
394 pub fn full_duplex( 410 pub fn full_duplex<S: Sample, const NB: usize, const NS: usize>(
395 mut self, 411 mut self,
396 sdin: impl Peripheral<P = impl GpioPin> + 'd, 412 sdin: impl Peripheral<P = impl GpioPin> + 'd,
397 sdout: impl Peripheral<P = impl GpioPin> + 'd, 413 sdout: impl Peripheral<P = impl GpioPin> + 'd,
398 ) -> FullDuplexStream<'d, T> { 414 buffers_out: MultiBuffering<S, NB, NS>,
415 buffers_in: MultiBuffering<S, NB, NS>,
416 ) -> FullDuplexStream<'d, T, S, NB, NS> {
399 self.sdout = Some(sdout.into_ref().map_into()); 417 self.sdout = Some(sdout.into_ref().map_into());
400 self.sdin = Some(sdin.into_ref().map_into()); 418 self.sdin = Some(sdin.into_ref().map_into());
401 419
402 FullDuplexStream { _p: self.build() } 420 FullDuplexStream {
421 _p: self.build(),
422 buffers_out,
423 buffers_in,
424 }
403 } 425 }
404 426
405 fn build(self) -> PeripheralRef<'d, T> { 427 fn build(self) -> PeripheralRef<'d, T> {
@@ -651,14 +673,19 @@ impl<'d, T: Instance> I2S<'d, T> {
651} 673}
652 674
653/// I2S output 675/// I2S output
654pub struct OutputStream<'d, T: Instance> { 676pub struct OutputStream<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> {
655 _p: PeripheralRef<'d, T>, 677 _p: PeripheralRef<'d, T>,
678 buffers: MultiBuffering<S, NB, NS>,
656} 679}
657 680
658impl<'d, T: Instance> OutputStream<'d, T> { 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
659 /// Prepare the initial buffer and start the I2S transfer. 687 /// Prepare the initial buffer and start the I2S transfer.
660 #[allow(unused_mut)] 688 pub async fn start(&mut self) -> Result<(), Error>
661 pub async fn start<S>(&mut self, buffer: &[S]) -> Result<(), Error>
662 where 689 where
663 S: Sample, 690 S: Sample,
664 { 691 {
@@ -672,7 +699,7 @@ impl<'d, T: Instance> OutputStream<'d, T> {
672 device.enable(); 699 device.enable();
673 device.enable_tx(); 700 device.enable_tx();
674 701
675 device.update_tx(buffer as *const [S])?; 702 device.update_tx(self.buffers.switch())?;
676 703
677 s.started.store(true, Ordering::Relaxed); 704 s.started.store(true, Ordering::Relaxed);
678 705
@@ -689,28 +716,30 @@ impl<'d, T: Instance> OutputStream<'d, T> {
689 I2S::<T>::stop().await 716 I2S::<T>::stop().await
690 } 717 }
691 718
692 /// Sets the given `buffer` for transmission in the DMA. 719 /// Sends the current buffer for transmission in the DMA.
693 /// Buffer address must be 4 byte aligned and located in RAM. 720 /// Switches to use the next available buffer.
694 /// The buffer must not be written while being used by the DMA, 721 pub async fn send(&mut self) -> Result<(), Error>
695 /// which takes two other `send`s being awaited.
696 #[allow(unused_mut)]
697 pub async fn send_from_ram<S>(&mut self, buffer: &[S]) -> Result<(), Error>
698 where 722 where
699 S: Sample, 723 S: Sample,
700 { 724 {
701 I2S::<T>::send_from_ram(buffer as *const [S]).await 725 I2S::<T>::send_from_ram(self.buffers.switch()).await
702 } 726 }
703} 727}
704 728
705/// I2S input 729/// I2S input
706pub struct InputStream<'d, T: Instance> { 730pub struct InputStream<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> {
707 _p: PeripheralRef<'d, T>, 731 _p: PeripheralRef<'d, T>,
732 buffers: MultiBuffering<S, NB, NS>,
708} 733}
709 734
710impl<'d, T: Instance> InputStream<'d, T> { 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
711 /// Prepare the initial buffer and start the I2S transfer. 741 /// Prepare the initial buffer and start the I2S transfer.
712 #[allow(unused_mut)] 742 pub async fn start(&mut self) -> Result<(), Error>
713 pub async fn start<S>(&mut self, buffer: &mut [S]) -> Result<(), Error>
714 where 743 where
715 S: Sample, 744 S: Sample,
716 { 745 {
@@ -724,7 +753,7 @@ impl<'d, T: Instance> InputStream<'d, T> {
724 device.enable(); 753 device.enable();
725 device.enable_rx(); 754 device.enable_rx();
726 755
727 device.update_rx(buffer as *mut [S])?; 756 device.update_rx(self.buffers.switch())?;
728 757
729 s.started.store(true, Ordering::Relaxed); 758 s.started.store(true, Ordering::Relaxed);
730 759
@@ -741,28 +770,32 @@ impl<'d, T: Instance> InputStream<'d, T> {
741 I2S::<T>::stop().await 770 I2S::<T>::stop().await
742 } 771 }
743 772
744 /// Sets the given `buffer` for reception from the DMA. 773 /// Sets the current buffer for reception from the DMA.
745 /// Buffer address must be 4 byte aligned and located in RAM. 774 /// Switches to use the next available buffer.
746 /// The buffer must not be read while being used by the DMA,
747 /// which takes two other `receive`s being awaited.
748 #[allow(unused_mut)] 775 #[allow(unused_mut)]
749 pub async fn receive_from_ram<S>(&mut self, buffer: &mut [S]) -> Result<(), Error> 776 pub async fn receive(&mut self) -> Result<(), Error>
750 where 777 where
751 S: Sample, 778 S: Sample,
752 { 779 {
753 I2S::<T>::receive_from_ram(buffer as *mut [S]).await 780 I2S::<T>::receive_from_ram(self.buffers.switch_mut()).await
754 } 781 }
755} 782}
756 783
757/// I2S full duplex stream (input & output) 784/// I2S full duplex stream (input & output)
758pub struct FullDuplexStream<'d, T: Instance> { 785pub struct FullDuplexStream<'d, T: Instance, S: Sample, const NB: usize, const NS: usize> {
759 _p: PeripheralRef<'d, T>, 786 _p: PeripheralRef<'d, T>,
787 buffers_out: MultiBuffering<S, NB, NS>,
788 buffers_in: MultiBuffering<S, NB, NS>,
760} 789}
761 790
762impl<'d, T: Instance> FullDuplexStream<'d, T> { 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
763 /// Prepare the initial buffers and start the I2S transfer. 797 /// Prepare the initial buffers and start the I2S transfer.
764 #[allow(unused_mut)] 798 pub async fn start(&mut self) -> Result<(), Error>
765 pub async fn start<S>(&mut self, buffer_in: &mut [S], buffer_out: &[S]) -> Result<(), Error>
766 where 799 where
767 S: Sample, 800 S: Sample,
768 { 801 {
@@ -777,8 +810,8 @@ impl<'d, T: Instance> FullDuplexStream<'d, T> {
777 device.enable_tx(); 810 device.enable_tx();
778 device.enable_rx(); 811 device.enable_rx();
779 812
780 device.update_tx(buffer_out as *const [S])?; 813 device.update_tx(self.buffers_out.switch())?;
781 device.update_rx(buffer_in as *mut [S])?; 814 device.update_rx(self.buffers_in.switch_mut())?;
782 815
783 s.started.store(true, Ordering::Relaxed); 816 s.started.store(true, Ordering::Relaxed);
784 817
@@ -796,17 +829,14 @@ impl<'d, T: Instance> FullDuplexStream<'d, T> {
796 I2S::<T>::stop().await 829 I2S::<T>::stop().await
797 } 830 }
798 831
799 /// Sets the given `buffer_out` and `buffer_in` for transmission/reception from the DMA. 832 /// Sets the current buffers for output and input for transmission/reception from the DMA.
800 /// Buffer address must be 4 byte aligned and located in RAM. 833 /// Switch to use the next available buffers for output/input.
801 /// The buffers must not be written/read while being used by the DMA, 834 pub async fn send_and_receive(&mut self) -> Result<(), Error>
802 /// which takes two other `send_and_receive` operations being awaited.
803 #[allow(unused_mut)]
804 pub async fn send_and_receive_from_ram<S>(&mut self, buffer_in: &mut [S], buffer_out: &[S]) -> Result<(), Error>
805 where 835 where
806 S: Sample, 836 S: Sample,
807 { 837 {
808 I2S::<T>::send_from_ram(buffer_out as *const [S]).await?; 838 I2S::<T>::send_from_ram(self.buffers_out.switch()).await?;
809 I2S::<T>::receive_from_ram(buffer_in as *mut [S]).await?; 839 I2S::<T>::receive_from_ram(self.buffers_in.switch_mut()).await?;
810 Ok(()) 840 Ok(())
811 } 841 }
812} 842}
@@ -992,7 +1022,7 @@ impl Sample for i32 {
992 const SCALE: Self = 1 << (Self::WIDTH - 1); 1022 const SCALE: Self = 1 << (Self::WIDTH - 1);
993} 1023}
994 1024
995/// A 4-bytes aligned [Buffer]. 1025/// A 4-bytes aligned buffer.
996#[derive(Clone, Copy)] 1026#[derive(Clone, Copy)]
997#[repr(align(4))] 1027#[repr(align(4))]
998pub struct AlignedBuffer<T: Sample, const N: usize>([T; N]); 1028pub struct AlignedBuffer<T: Sample, const N: usize>([T; N]);
@@ -1022,6 +1052,43 @@ impl<T: Sample, const N: usize> DerefMut for AlignedBuffer<T, N> {
1022 } 1052 }
1023} 1053}
1024 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
1025pub(crate) mod sealed { 1092pub(crate) mod sealed {
1026 use core::sync::atomic::AtomicBool; 1093 use core::sync::atomic::AtomicBool;
1027 1094
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
index 13b1300ea..1b0e8ebc8 100644
--- a/examples/nrf/src/bin/i2s_waveform.rs
+++ b/examples/nrf/src/bin/i2s_waveform.rs
@@ -6,13 +6,12 @@ use core::f32::consts::PI;
6 6
7use defmt::{error, info}; 7use defmt::{error, info};
8use embassy_executor::Spawner; 8use embassy_executor::Spawner;
9use embassy_nrf::i2s::{self, Channels, Config, MasterClock, Sample as _, SampleWidth, I2S}; 9use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S};
10use embassy_nrf::interrupt; 10use embassy_nrf::interrupt;
11use {defmt_rtt as _, panic_probe as _}; 11use {defmt_rtt as _, panic_probe as _};
12 12
13type Sample = i16; 13type Sample = i16;
14 14
15const NUM_BUFFERS: usize = 2;
16const NUM_SAMPLES: usize = 50; 15const NUM_SAMPLES: usize = 50;
17 16
18#[embassy_executor::main] 17#[embassy_executor::main]
@@ -29,29 +28,22 @@ async fn main(_spawner: Spawner) {
29 .channels(Channels::MonoLeft); 28 .channels(Channels::MonoLeft);
30 29
31 let irq = interrupt::take!(I2S); 30 let irq = interrupt::take!(I2S);
32 let mut output_stream = I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).output(p.P0_28); 31 let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
33 32 let mut output_stream =
34 let mut buffers: [i2s::AlignedBuffer<Sample, NUM_SAMPLES>; NUM_BUFFERS] = 33 I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).output(p.P0_28, buffers);
35 [i2s::AlignedBuffer::default(); NUM_BUFFERS];
36 34
37 let mut waveform = Waveform::new(1.0 / sample_rate as f32); 35 let mut waveform = Waveform::new(1.0 / sample_rate as f32);
38 36
39 waveform.process(&mut buffers[0]); 37 waveform.process(output_stream.buffer());
40 38
41 output_stream.start(&buffers[0]).await.expect("I2S Start"); 39 output_stream.start().await.expect("I2S Start");
42 40
43 let mut index = 1;
44 loop { 41 loop {
45 waveform.process(&mut buffers[index]); 42 waveform.process(output_stream.buffer());
46 43
47 if let Err(err) = output_stream.send_from_ram(&buffers[index]).await { 44 if let Err(err) = output_stream.send().await {
48 error!("{}", err); 45 error!("{}", err);
49 } 46 }
50
51 index += 1;
52 if index >= NUM_BUFFERS {
53 index = 0;
54 }
55 } 47 }
56} 48}
57 49
@@ -68,7 +60,7 @@ impl Waveform {
68 carrier.set_frequency(110.0, inv_sample_rate); 60 carrier.set_frequency(110.0, inv_sample_rate);
69 61
70 let mut freq_mod = SineOsc::new(); 62 let mut freq_mod = SineOsc::new();
71 freq_mod.set_frequency(8.0, inv_sample_rate); 63 freq_mod.set_frequency(1.0, inv_sample_rate);
72 freq_mod.set_amplitude(1.0); 64 freq_mod.set_amplitude(1.0);
73 65
74 let mut amp_mod = SineOsc::new(); 66 let mut amp_mod = SineOsc::new();