From 15a93246d6bb3e0bea268ff919bca073a9890247 Mon Sep 17 00:00:00 2001 From: Christian Perez Llamas <932644+chris-zen@users.noreply.github.com> Date: Sat, 19 Nov 2022 19:18:20 +0100 Subject: Buffer management in line with other peripherals. Constructor and config redesign --- examples/nrf/src/bin/i2s-generate.rs | 142 ------------------------------ examples/nrf/src/bin/i2s_waveform.rs | 161 +++++++++++++++++++++++++++++++++++ 2 files changed, 161 insertions(+), 142 deletions(-) delete mode 100644 examples/nrf/src/bin/i2s-generate.rs create mode 100644 examples/nrf/src/bin/i2s_waveform.rs (limited to 'examples') diff --git a/examples/nrf/src/bin/i2s-generate.rs b/examples/nrf/src/bin/i2s-generate.rs deleted file mode 100644 index c2b5578f3..000000000 --- a/examples/nrf/src/bin/i2s-generate.rs +++ /dev/null @@ -1,142 +0,0 @@ -#![no_std] -#![no_main] -#![feature(type_alias_impl_trait)] - -use core::f32::consts::PI; - -use defmt::{error, info}; -use embassy_executor::Spawner; -use embassy_nrf::i2s::{self, Sample as _}; -use embassy_nrf::interrupt; -use {defmt_rtt as _, panic_probe as _}; - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = embassy_nrf::init(Default::default()); - - let mut config = i2s::Config::default(); - config.mode = i2s::ExactSampleRate::_50000.into(); - config.channels = i2s::Channels::Left; - config.swidth = i2s::SampleWidth::_16bit; - let sample_rate = config.mode.sample_rate().expect("I2S Master"); - let inv_sample_rate = 1.0 / sample_rate as f32; - - info!("Sample rate: {}", sample_rate); - - // Wait for a button press - // use embassy_nrf::gpio::{Input, Pin, Pull}; - // let mut btn1 = Input::new(p.P1_00.degrade(), Pull::Up); - // btn1.wait_for_low().await; - - let irq = interrupt::take!(I2S); - let mut i2s = i2s::I2S::new(p.I2S, irq, p.P0_28, p.P0_29, p.P0_31, p.P0_27, p.P0_30, config).output(); - - type Sample = i16; - const NUM_SAMPLES: usize = 6000; - - let mut buffers: [i2s::AlignedBuffer; 3] = [ - i2s::AlignedBuffer::default(), - i2s::AlignedBuffer::default(), - i2s::AlignedBuffer::default(), - ]; - - let mut carrier = SineOsc::new(); - - let mut freq_mod = SineOsc::new(); - freq_mod.set_frequency(8.0, inv_sample_rate); - freq_mod.set_amplitude(1.0); - - let mut amp_mod = SineOsc::new(); - amp_mod.set_frequency(16.0, inv_sample_rate); - amp_mod.set_amplitude(0.5); - - let mut generate = |buf: &mut [Sample]| { - for sample in &mut buf.chunks_mut(1) { - let freq_modulation = bipolar_to_unipolar(freq_mod.generate()); - carrier.set_frequency(220.0 + 440.0 * freq_modulation, inv_sample_rate); - let amp_modulation = bipolar_to_unipolar(amp_mod.generate()); - carrier.set_amplitude(amp_modulation); - let signal = carrier.generate(); - let value = (Sample::SCALE as f32 * signal) as Sample; - sample[0] = value; - } - }; - - generate(buffers[0].as_mut()); - generate(buffers[1].as_mut()); - - i2s.start(buffers[0].as_ref()).await.expect("I2S Start"); - - let mut index = 1; - loop { - if let Err(err) = i2s.send(buffers[index].as_ref()).await { - error!("{}", err); - } - - index += 1; - if index >= 3 { - index = 0; - } - generate(buffers[index].as_mut()); - } -} - -#[derive(Clone)] -struct SineOsc { - amplitude: f32, - modulo: f32, - phase_inc: f32, -} - -impl SineOsc { - const B: f32 = 4.0 / PI; - const C: f32 = -4.0 / (PI * PI); - const P: f32 = 0.225; - - pub fn new() -> Self { - Self { - amplitude: 1.0, - modulo: 0.0, - phase_inc: 0.0, - } - } - - pub fn set_frequency(&mut self, freq: f32, inv_sample_rate: f32) { - self.phase_inc = freq * inv_sample_rate; - } - - pub fn set_amplitude(&mut self, amplitude: f32) { - self.amplitude = amplitude; - } - - pub fn generate(&mut self) -> f32 { - let signal = self.parabolic_sin(self.modulo); - self.modulo += self.phase_inc; - if self.modulo < 0.0 { - self.modulo += 1.0; - } else if self.modulo > 1.0 { - self.modulo -= 1.0; - } - signal * self.amplitude - } - - fn parabolic_sin(&mut self, modulo: f32) -> f32 { - let angle = PI - modulo * 2.0 * PI; - let y = Self::B * angle + Self::C * angle * abs(angle); - Self::P * (y * abs(y) - y) + y - } -} - -#[inline] -fn abs(value: f32) -> f32 { - if value < 0.0 { - -value - } else { - value - } -} - -#[inline] -fn bipolar_to_unipolar(value: f32) -> f32 { - (value + 1.0) / 2.0 -} diff --git a/examples/nrf/src/bin/i2s_waveform.rs b/examples/nrf/src/bin/i2s_waveform.rs new file mode 100644 index 000000000..81858ff59 --- /dev/null +++ b/examples/nrf/src/bin/i2s_waveform.rs @@ -0,0 +1,161 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use core::f32::consts::PI; + +use defmt::{error, info}; +use embassy_executor::Spawner; +use embassy_nrf::i2s::{self, Channels, Config, MasterClock, Sample as _, SampleWidth, I2S}; +use embassy_nrf::interrupt; +use {defmt_rtt as _, panic_probe as _}; + +type Sample = i16; + +const NUM_SAMPLES: usize = 6000; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + + let master_clock: MasterClock = i2s::ExactSampleRate::_50000.into(); + + let sample_rate = master_clock.sample_rate(); + info!("Sample rate: {}", sample_rate); + + let config = Config::default() + .sample_width(SampleWidth::_16bit) + .channels(Channels::MonoLeft); + + let irq = interrupt::take!(I2S); + 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); + + let mut buffers: [i2s::AlignedBuffer; 3] = [ + i2s::AlignedBuffer::default(), + i2s::AlignedBuffer::default(), + i2s::AlignedBuffer::default(), + ]; + + let mut waveform = Waveform::new(1.0 / sample_rate as f32); + + waveform.process(&mut buffers[0]); + waveform.process(&mut buffers[1]); + + output_stream.start(&buffers[0]).await.expect("I2S Start"); + + let mut index = 1; + loop { + if let Err(err) = output_stream.send_from_ram(&buffers[index]).await { + error!("{}", err); + } + + index += 1; + if index >= 3 { + index = 0; + } + + waveform.process(&mut buffers[index]); + } +} + +struct Waveform { + inv_sample_rate: f32, + carrier: SineOsc, + freq_mod: SineOsc, + amp_mod: SineOsc, +} + +impl Waveform { + fn new(inv_sample_rate: f32) -> Self { + let carrier = SineOsc::new(); + + let mut freq_mod = SineOsc::new(); + freq_mod.set_frequency(8.0, inv_sample_rate); + freq_mod.set_amplitude(1.0); + + let mut amp_mod = SineOsc::new(); + amp_mod.set_frequency(16.0, inv_sample_rate); + amp_mod.set_amplitude(0.5); + + Self { + inv_sample_rate, + carrier, + freq_mod, + amp_mod, + } + } + + fn process(&mut self, buf: &mut [Sample]) { + for sample in buf.chunks_mut(1) { + let freq_modulation = bipolar_to_unipolar(self.freq_mod.generate()); + self.carrier + .set_frequency(110.0 + 440.0 * freq_modulation, self.inv_sample_rate); + + let amp_modulation = bipolar_to_unipolar(self.amp_mod.generate()); + self.carrier.set_amplitude(amp_modulation); + + let signal = self.carrier.generate(); + + sample[0] = (Sample::SCALE as f32 * signal) as Sample; + } + } +} + +struct SineOsc { + amplitude: f32, + modulo: f32, + phase_inc: f32, +} + +impl SineOsc { + const B: f32 = 4.0 / PI; + const C: f32 = -4.0 / (PI * PI); + const P: f32 = 0.225; + + pub fn new() -> Self { + Self { + amplitude: 1.0, + modulo: 0.0, + phase_inc: 0.0, + } + } + + pub fn set_frequency(&mut self, freq: f32, inv_sample_rate: f32) { + self.phase_inc = freq * inv_sample_rate; + } + + pub fn set_amplitude(&mut self, amplitude: f32) { + self.amplitude = amplitude; + } + + pub fn generate(&mut self) -> f32 { + let signal = self.parabolic_sin(self.modulo); + self.modulo += self.phase_inc; + if self.modulo < 0.0 { + self.modulo += 1.0; + } else if self.modulo > 1.0 { + self.modulo -= 1.0; + } + signal * self.amplitude + } + + fn parabolic_sin(&mut self, modulo: f32) -> f32 { + let angle = PI - modulo * 2.0 * PI; + let y = Self::B * angle + Self::C * angle * abs(angle); + Self::P * (y * abs(y) - y) + y + } +} + +#[inline] +fn abs(value: f32) -> f32 { + if value < 0.0 { + -value + } else { + value + } +} + +#[inline] +fn bipolar_to_unipolar(value: f32) -> f32 { + (value + 1.0) / 2.0 +} -- cgit