diff options
| author | Christian Perez Llamas <[email protected]> | 2022-11-12 18:48:57 +0100 |
|---|---|---|
| committer | Christian Perez Llamas <[email protected]> | 2022-11-12 18:48:57 +0100 |
| commit | 122a31d20877005c7201d4e7c98da5544666dd1d (patch) | |
| tree | c97037ba880f63a4e03e642c6630efb1042a3cde /examples | |
| parent | 10e3c3f2ec358da6d81f2bb9c05936c2ab6da567 (diff) | |
Interrupts, async, sine oscillator
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/nrf/src/bin/i2s.rs | 132 |
1 files changed, 111 insertions, 21 deletions
diff --git a/examples/nrf/src/bin/i2s.rs b/examples/nrf/src/bin/i2s.rs index e8ddb4a40..53ccb3b85 100644 --- a/examples/nrf/src/bin/i2s.rs +++ b/examples/nrf/src/bin/i2s.rs | |||
| @@ -4,43 +4,133 @@ | |||
| 4 | #![no_main] | 4 | #![no_main] |
| 5 | #![feature(type_alias_impl_trait)] | 5 | #![feature(type_alias_impl_trait)] |
| 6 | 6 | ||
| 7 | //use defmt::*; | 7 | use core::f32::consts::PI; |
| 8 | |||
| 9 | use defmt::{error, info}; | ||
| 8 | use embassy_executor::Spawner; | 10 | use embassy_executor::Spawner; |
| 9 | use embassy_nrf::i2s; | 11 | use embassy_nrf::i2s::{MckFreq, Mode, Ratio, MODE_MASTER_16000, MODE_MASTER_8000}; |
| 12 | use embassy_nrf::{i2s, interrupt}; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 14 | ||
| 12 | #[repr(align(4))] | 15 | #[repr(align(4))] |
| 13 | pub struct Aligned<T: ?Sized>(T); | 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 | } | ||
| 14 | 29 | ||
| 15 | #[embassy_executor::main] | 30 | #[embassy_executor::main] |
| 16 | async fn main(_spawner: Spawner) { | 31 | async fn main(_spawner: Spawner) { |
| 17 | let p = embassy_nrf::init(Default::default()); | 32 | let p = embassy_nrf::init(Default::default()); |
| 18 | let config = i2s::Config::default(); | 33 | let mut config = i2s::Config::default(); |
| 34 | // config.mode = MODE_MASTER_16000; | ||
| 35 | config.mode = Mode::Master { | ||
| 36 | freq: MckFreq::_32MDiv10, | ||
| 37 | ratio: Ratio::_256x, | ||
| 38 | }; // 12500 Hz | ||
| 39 | let sample_rate = config.mode.sample_rate().expect("I2S Master"); | ||
| 40 | let inv_sample_rate = 1.0 / sample_rate as f32; | ||
| 19 | 41 | ||
| 20 | let mut i2s = i2s::I2S::new(p.I2S, p.P0_28, p.P0_29, p.P0_31, p.P0_11, p.P0_30, config); | 42 | info!("Sample rate: {}", sample_rate); |
| 21 | 43 | ||
| 22 | let mut signal_buf: Aligned<[i16; 32]> = Aligned([0i16; 32]); | 44 | let irq = interrupt::take!(I2S); |
| 23 | let len = signal_buf.0.len() / 2; | 45 | 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); |
| 24 | for x in 0..len { | 46 | |
| 25 | signal_buf.0[2 * x] = triangle_wave(x as i32, len, 2048, 0, 1) as i16; | 47 | const BUF_SAMPLES: usize = 250; |
| 26 | signal_buf.0[2 * x + 1] = triangle_wave(x as i32, len, 2048, 0, 1) as i16; | 48 | const BUF_SIZE: usize = BUF_SAMPLES * 2; |
| 27 | } | 49 | let mut buf = AlignedBuffer([0i16; BUF_SIZE]); |
| 50 | |||
| 51 | let mut carrier = SineOsc::new(); | ||
| 52 | carrier.set_frequency(300.0, inv_sample_rate); | ||
| 53 | |||
| 54 | let mut modulator = SineOsc::new(); | ||
| 55 | modulator.set_frequency(0.01, inv_sample_rate); | ||
| 56 | modulator.set_amplitude(0.2); | ||
| 28 | 57 | ||
| 29 | i2s.set_tx_enabled(true); | 58 | i2s.set_tx_enabled(true); |
| 30 | i2s.start(); | 59 | i2s.start(); |
| 31 | 60 | ||
| 32 | loop { | 61 | loop { |
| 33 | match i2s.tx(signal_buf.0.as_slice()).await { | 62 | for sample in buf.as_mut().chunks_mut(2) { |
| 34 | Ok(_) => todo!(), | 63 | let signal = carrier.generate(); |
| 35 | Err(_) => todo!(), | 64 | // let modulation = bipolar_to_unipolar(modulator.generate()); |
| 36 | }; | 65 | // carrier.set_frequency(200.0 + 100.0 * modulation, inv_sample_rate); |
| 66 | // carrier.set_amplitude((modulation); | ||
| 67 | let value = (i16::MAX as f32 * signal) as i16; | ||
| 68 | sample[0] = value; | ||
| 69 | sample[1] = value; | ||
| 70 | // info!("{}", signal); | ||
| 71 | } | ||
| 72 | |||
| 73 | if let Err(err) = i2s.tx(buf.as_ref().as_slice()).await { | ||
| 74 | error!("{}", err); | ||
| 75 | } | ||
| 76 | } | ||
| 77 | } | ||
| 78 | |||
| 79 | struct SineOsc { | ||
| 80 | amplitude: f32, | ||
| 81 | modulo: f32, | ||
| 82 | phase_inc: f32, | ||
| 83 | } | ||
| 84 | |||
| 85 | impl SineOsc { | ||
| 86 | const B: f32 = 4.0 / PI; | ||
| 87 | const C: f32 = -4.0 / (PI * PI); | ||
| 88 | const P: f32 = 0.225; | ||
| 89 | |||
| 90 | pub fn new() -> Self { | ||
| 91 | Self { | ||
| 92 | amplitude: 1.0, | ||
| 93 | modulo: 0.0, | ||
| 94 | phase_inc: 0.0, | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | pub fn set_frequency(&mut self, freq: f32, inv_sample_rate: f32) { | ||
| 99 | self.phase_inc = freq * inv_sample_rate; | ||
| 100 | } | ||
| 101 | |||
| 102 | pub fn set_amplitude(&mut self, amplitude: f32) { | ||
| 103 | self.amplitude = amplitude; | ||
| 104 | } | ||
| 105 | |||
| 106 | pub fn generate(&mut self) -> f32 { | ||
| 107 | let signal = self.parabolic_sin(self.modulo); | ||
| 108 | self.modulo += self.phase_inc; | ||
| 109 | if self.modulo < 0.0 { | ||
| 110 | self.modulo += 1.0; | ||
| 111 | } else if self.modulo > 1.0 { | ||
| 112 | self.modulo -= 1.0; | ||
| 113 | } | ||
| 114 | signal * self.amplitude | ||
| 115 | } | ||
| 116 | |||
| 117 | fn parabolic_sin(&mut self, modulo: f32) -> f32 { | ||
| 118 | let angle = PI - modulo * 2.0 * PI; | ||
| 119 | let y = Self::B * angle + Self::C * angle * abs(angle); | ||
| 120 | Self::P * (y * abs(y) - y) + y | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | #[inline] | ||
| 125 | fn abs(value: f32) -> f32 { | ||
| 126 | if value < 0.0 { | ||
| 127 | -value | ||
| 128 | } else { | ||
| 129 | value | ||
| 37 | } | 130 | } |
| 38 | } | 131 | } |
| 39 | 132 | ||
| 40 | fn triangle_wave(x: i32, length: usize, amplitude: i32, phase: i32, periods: i32) -> i32 { | 133 | #[inline] |
| 41 | let length = length as i32; | 134 | fn bipolar_to_unipolar(value: f32) -> f32 { |
| 42 | amplitude | 135 | (value + 1.0) / 2.0 |
| 43 | - ((2 * periods * (x + phase + length / (4 * periods)) * amplitude / length) % (2 * amplitude) - amplitude) | ||
| 44 | .abs() | ||
| 45 | - amplitude / 2 | ||
| 46 | } | 136 | } |
