diff options
| author | Christian Perez Llamas <[email protected]> | 2022-11-19 19:18:20 +0100 |
|---|---|---|
| committer | Christian Perez Llamas <[email protected]> | 2022-11-19 19:18:20 +0100 |
| commit | 15a93246d6bb3e0bea268ff919bca073a9890247 (patch) | |
| tree | b7ac9969e2ec491cf1d200ba9f2239ecedd6f2f5 | |
| parent | f5391efe22374e0c55005f20c6a644bda3acd50c (diff) | |
Buffer management in line with other peripherals. Constructor and config redesign
| -rw-r--r-- | embassy-nrf/src/i2s.rs | 715 | ||||
| -rw-r--r-- | examples/nrf/src/bin/i2s_waveform.rs (renamed from examples/nrf/src/bin/i2s-generate.rs) | 103 |
2 files changed, 392 insertions, 426 deletions
diff --git a/embassy-nrf/src/i2s.rs b/embassy-nrf/src/i2s.rs index 11c09a229..d5815160a 100644 --- a/embassy-nrf/src/i2s.rs +++ b/embassy-nrf/src/i2s.rs | |||
| @@ -4,6 +4,8 @@ | |||
| 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::mem::size_of; | ||
| 8 | use core::ops::{Deref, DerefMut}; | ||
| 7 | use core::sync::atomic::{compiler_fence, Ordering}; | 9 | use core::sync::atomic::{compiler_fence, Ordering}; |
| 8 | use core::task::Poll; | 10 | use core::task::Poll; |
| 9 | 11 | ||
| @@ -14,14 +16,9 @@ use embassy_hal_common::{into_ref, PeripheralRef}; | |||
| 14 | use crate::gpio::{AnyPin, Pin as GpioPin}; | 16 | use crate::gpio::{AnyPin, Pin as GpioPin}; |
| 15 | use crate::interrupt::Interrupt; | 17 | use crate::interrupt::Interrupt; |
| 16 | use crate::pac::i2s::RegisterBlock; | 18 | use crate::pac::i2s::RegisterBlock; |
| 19 | use crate::util::{slice_in_ram_or, slice_ptr_parts}; | ||
| 17 | use crate::{Peripheral, EASY_DMA_SIZE}; | 20 | use crate::{Peripheral, EASY_DMA_SIZE}; |
| 18 | 21 | ||
| 19 | // TODO: Define those in lib.rs somewhere else | ||
| 20 | |||
| 21 | /// Limits for Easy DMA - it can only read from data ram | ||
| 22 | pub const SRAM_LOWER: usize = 0x2000_0000; | ||
| 23 | pub const SRAM_UPPER: usize = 0x3000_0000; | ||
| 24 | |||
| 25 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 22 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 26 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 23 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 27 | #[non_exhaustive] | 24 | #[non_exhaustive] |
| @@ -33,159 +30,42 @@ pub enum Error { | |||
| 33 | BufferLengthMisaligned, | 30 | BufferLengthMisaligned, |
| 34 | } | 31 | } |
| 35 | 32 | ||
| 36 | /// Approximate sample rates. | 33 | /// I2S configuration. |
| 37 | /// | 34 | #[derive(Clone)] |
| 38 | /// Those are common sample rates that can not be configured without an small error. | 35 | #[non_exhaustive] |
| 39 | /// | 36 | pub struct Config { |
| 40 | /// For custom master clock configuration, please refer to [Mode]. | 37 | pub sample_width: SampleWidth, |
| 41 | #[derive(Clone, Copy)] | 38 | pub align: Align, |
| 42 | pub enum ApproxSampleRate { | 39 | pub format: Format, |
| 43 | _11025, | 40 | pub channels: Channels, |
| 44 | _16000, | ||
| 45 | _22050, | ||
| 46 | _32000, | ||
| 47 | _44100, | ||
| 48 | _48000, | ||
| 49 | } | 41 | } |
| 50 | 42 | ||
| 51 | impl From<ApproxSampleRate> for Mode { | 43 | impl Config { |
| 52 | fn from(value: ApproxSampleRate) -> Self { | 44 | pub fn sample_width(mut self, sample_width: SampleWidth) -> Self { |
| 53 | match value { | 45 | self.sample_width = sample_width; |
| 54 | // error = 86 | 46 | self |
| 55 | ApproxSampleRate::_11025 => Mode::Master { | ||
| 56 | freq: MckFreq::_32MDiv15, | ||
| 57 | ratio: Ratio::_192x, | ||
| 58 | }, | ||
| 59 | // error = 127 | ||
| 60 | ApproxSampleRate::_16000 => Mode::Master { | ||
| 61 | freq: MckFreq::_32MDiv21, | ||
| 62 | ratio: Ratio::_96x, | ||
| 63 | }, | ||
| 64 | // error = 172 | ||
| 65 | ApproxSampleRate::_22050 => Mode::Master { | ||
| 66 | freq: MckFreq::_32MDiv15, | ||
| 67 | ratio: Ratio::_96x, | ||
| 68 | }, | ||
| 69 | // error = 254 | ||
| 70 | ApproxSampleRate::_32000 => Mode::Master { | ||
| 71 | freq: MckFreq::_32MDiv21, | ||
| 72 | ratio: Ratio::_48x, | ||
| 73 | }, | ||
| 74 | // error = 344 | ||
| 75 | ApproxSampleRate::_44100 => Mode::Master { | ||
| 76 | freq: MckFreq::_32MDiv15, | ||
| 77 | ratio: Ratio::_48x, | ||
| 78 | }, | ||
| 79 | // error = 381 | ||
| 80 | ApproxSampleRate::_48000 => Mode::Master { | ||
| 81 | freq: MckFreq::_32MDiv21, | ||
| 82 | ratio: Ratio::_32x, | ||
| 83 | }, | ||
| 84 | } | ||
| 85 | } | 47 | } |
| 86 | } | ||
| 87 | 48 | ||
| 88 | impl ApproxSampleRate { | 49 | pub fn align(mut self, align: Align) -> Self { |
| 89 | pub fn sample_rate(&self) -> u32 { | 50 | self.align = align; |
| 90 | // This will always provide a Master mode, so it is safe to unwrap. | 51 | self |
| 91 | Mode::from(*self).sample_rate().unwrap() | ||
| 92 | } | 52 | } |
| 93 | } | ||
| 94 | 53 | ||
| 95 | /// Exact sample rates. | 54 | pub fn format(mut self, format: Format) -> Self { |
| 96 | /// | 55 | self.format = format; |
| 97 | /// Those are non standard sample rates that can be configured without error. | 56 | self |
| 98 | /// | ||
| 99 | /// For custom master clock configuration, please refer to [Mode]. | ||
| 100 | #[derive(Clone, Copy)] | ||
| 101 | pub enum ExactSampleRate { | ||
| 102 | _8000, | ||
| 103 | _10582, | ||
| 104 | _12500, | ||
| 105 | _15625, | ||
| 106 | _15873, | ||
| 107 | _25000, | ||
| 108 | _31250, | ||
| 109 | _50000, | ||
| 110 | _62500, | ||
| 111 | _100000, | ||
| 112 | _125000, | ||
| 113 | } | ||
| 114 | |||
| 115 | impl ExactSampleRate { | ||
| 116 | pub fn sample_rate(&self) -> u32 { | ||
| 117 | // This will always provide a Master mode, so it is safe to unwrap. | ||
| 118 | Mode::from(*self).sample_rate().unwrap() | ||
| 119 | } | 57 | } |
| 120 | } | ||
| 121 | 58 | ||
| 122 | impl From<ExactSampleRate> for Mode { | 59 | pub fn channels(mut self, channels: Channels) -> Self { |
| 123 | fn from(value: ExactSampleRate) -> Self { | 60 | self.channels = channels; |
| 124 | match value { | 61 | self |
| 125 | ExactSampleRate::_8000 => Mode::Master { | ||
| 126 | freq: MckFreq::_32MDiv125, | ||
| 127 | ratio: Ratio::_32x, | ||
| 128 | }, | ||
| 129 | ExactSampleRate::_10582 => Mode::Master { | ||
| 130 | freq: MckFreq::_32MDiv63, | ||
| 131 | ratio: Ratio::_48x, | ||
| 132 | }, | ||
| 133 | ExactSampleRate::_12500 => Mode::Master { | ||
| 134 | freq: MckFreq::_32MDiv10, | ||
| 135 | ratio: Ratio::_256x, | ||
| 136 | }, | ||
| 137 | ExactSampleRate::_15625 => Mode::Master { | ||
| 138 | freq: MckFreq::_32MDiv32, | ||
| 139 | ratio: Ratio::_64x, | ||
| 140 | }, | ||
| 141 | ExactSampleRate::_15873 => Mode::Master { | ||
| 142 | freq: MckFreq::_32MDiv63, | ||
| 143 | ratio: Ratio::_32x, | ||
| 144 | }, | ||
| 145 | ExactSampleRate::_25000 => Mode::Master { | ||
| 146 | freq: MckFreq::_32MDiv10, | ||
| 147 | ratio: Ratio::_128x, | ||
| 148 | }, | ||
| 149 | ExactSampleRate::_31250 => Mode::Master { | ||
| 150 | freq: MckFreq::_32MDiv32, | ||
| 151 | ratio: Ratio::_32x, | ||
| 152 | }, | ||
| 153 | ExactSampleRate::_50000 => Mode::Master { | ||
| 154 | freq: MckFreq::_32MDiv10, | ||
| 155 | ratio: Ratio::_64x, | ||
| 156 | }, | ||
| 157 | ExactSampleRate::_62500 => Mode::Master { | ||
| 158 | freq: MckFreq::_32MDiv16, | ||
| 159 | ratio: Ratio::_32x, | ||
| 160 | }, | ||
| 161 | ExactSampleRate::_100000 => Mode::Master { | ||
| 162 | freq: MckFreq::_32MDiv10, | ||
| 163 | ratio: Ratio::_32x, | ||
| 164 | }, | ||
| 165 | ExactSampleRate::_125000 => Mode::Master { | ||
| 166 | freq: MckFreq::_32MDiv8, | ||
| 167 | ratio: Ratio::_32x, | ||
| 168 | }, | ||
| 169 | } | ||
| 170 | } | 62 | } |
| 171 | } | 63 | } |
| 172 | 64 | ||
| 173 | /// I2S configuration. | ||
| 174 | #[derive(Clone)] | ||
| 175 | #[non_exhaustive] | ||
| 176 | pub struct Config { | ||
| 177 | pub mode: Mode, | ||
| 178 | pub swidth: SampleWidth, | ||
| 179 | pub align: Align, | ||
| 180 | pub format: Format, | ||
| 181 | pub channels: Channels, | ||
| 182 | } | ||
| 183 | |||
| 184 | impl Default for Config { | 65 | impl Default for Config { |
| 185 | fn default() -> Self { | 66 | fn default() -> Self { |
| 186 | Self { | 67 | Self { |
| 187 | mode: ExactSampleRate::_31250.into(), | 68 | sample_width: SampleWidth::_16bit, |
| 188 | swidth: SampleWidth::_16bit, | ||
| 189 | align: Align::Left, | 69 | align: Align::Left, |
| 190 | format: Format::I2S, | 70 | format: Format::I2S, |
| 191 | channels: Channels::Stereo, | 71 | channels: Channels::Stereo, |
| @@ -195,17 +75,20 @@ impl Default for Config { | |||
| 195 | 75 | ||
| 196 | /// I2S Mode | 76 | /// I2S Mode |
| 197 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | 77 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] |
| 198 | pub enum Mode { | 78 | pub struct MasterClock { |
| 199 | Master { freq: MckFreq, ratio: Ratio }, | 79 | freq: MckFreq, |
| 200 | Slave, | 80 | ratio: Ratio, |
| 201 | } | 81 | } |
| 202 | 82 | ||
| 203 | impl Mode { | 83 | impl MasterClock { |
| 204 | pub fn sample_rate(&self) -> Option<u32> { | 84 | pub fn new(freq: MckFreq, ratio: Ratio) -> Self { |
| 205 | match self { | 85 | Self { freq, ratio } |
| 206 | Mode::Master { freq, ratio } => Some(freq.to_frequency() / ratio.to_divisor()), | 86 | } |
| 207 | Mode::Slave => None, | 87 | } |
| 208 | } | 88 | |
| 89 | impl MasterClock { | ||
| 90 | pub fn sample_rate(&self) -> u32 { | ||
| 91 | self.freq.to_frequency() / self.ratio.to_divisor() | ||
| 209 | } | 92 | } |
| 210 | } | 93 | } |
| 211 | 94 | ||
| @@ -275,17 +158,106 @@ pub enum Ratio { | |||
| 275 | impl Ratio { | 158 | impl Ratio { |
| 276 | const RATIOS: &'static [u32] = &[32, 48, 64, 96, 128, 192, 256, 384, 512]; | 159 | const RATIOS: &'static [u32] = &[32, 48, 64, 96, 128, 192, 256, 384, 512]; |
| 277 | 160 | ||
| 161 | /// Return the value that needs to be written to the register. | ||
| 162 | pub fn to_register_value(&self) -> u8 { | ||
| 163 | usize::from(*self) as u8 | ||
| 164 | } | ||
| 165 | |||
| 278 | pub fn to_divisor(&self) -> u32 { | 166 | pub fn to_divisor(&self) -> u32 { |
| 279 | Self::RATIOS[u8::from(*self) as usize] | 167 | Self::RATIOS[usize::from(*self)] |
| 280 | } | 168 | } |
| 281 | } | 169 | } |
| 282 | 170 | ||
| 283 | impl From<Ratio> for u8 { | 171 | impl From<Ratio> for usize { |
| 284 | fn from(variant: Ratio) -> Self { | 172 | fn from(variant: Ratio) -> Self { |
| 285 | variant as _ | 173 | variant as _ |
| 286 | } | 174 | } |
| 287 | } | 175 | } |
| 288 | 176 | ||
| 177 | /// Approximate sample rates. | ||
| 178 | /// | ||
| 179 | /// Those are common sample rates that can not be configured without an small error. | ||
| 180 | /// | ||
| 181 | /// For custom master clock configuration, please refer to [MasterClock]. | ||
| 182 | #[derive(Clone, Copy)] | ||
| 183 | pub enum ApproxSampleRate { | ||
| 184 | _11025, | ||
| 185 | _16000, | ||
| 186 | _22050, | ||
| 187 | _32000, | ||
| 188 | _44100, | ||
| 189 | _48000, | ||
| 190 | } | ||
| 191 | |||
| 192 | impl From<ApproxSampleRate> for MasterClock { | ||
| 193 | fn from(value: ApproxSampleRate) -> Self { | ||
| 194 | match value { | ||
| 195 | // error = 86 | ||
| 196 | ApproxSampleRate::_11025 => MasterClock::new(MckFreq::_32MDiv15, Ratio::_192x), | ||
| 197 | // error = 127 | ||
| 198 | ApproxSampleRate::_16000 => MasterClock::new(MckFreq::_32MDiv21, Ratio::_96x), | ||
| 199 | // error = 172 | ||
| 200 | ApproxSampleRate::_22050 => MasterClock::new(MckFreq::_32MDiv15, Ratio::_96x), | ||
| 201 | // error = 254 | ||
| 202 | ApproxSampleRate::_32000 => MasterClock::new(MckFreq::_32MDiv21, Ratio::_48x), | ||
| 203 | // error = 344 | ||
| 204 | ApproxSampleRate::_44100 => MasterClock::new(MckFreq::_32MDiv15, Ratio::_48x), | ||
| 205 | // error = 381 | ||
| 206 | ApproxSampleRate::_48000 => MasterClock::new(MckFreq::_32MDiv21, Ratio::_32x), | ||
| 207 | } | ||
| 208 | } | ||
| 209 | } | ||
| 210 | |||
| 211 | impl ApproxSampleRate { | ||
| 212 | pub fn sample_rate(&self) -> u32 { | ||
| 213 | MasterClock::from(*self).sample_rate() | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | /// Exact sample rates. | ||
| 218 | /// | ||
| 219 | /// Those are non standard sample rates that can be configured without error. | ||
| 220 | /// | ||
| 221 | /// For custom master clock configuration, please refer to [Mode]. | ||
| 222 | #[derive(Clone, Copy)] | ||
| 223 | pub enum ExactSampleRate { | ||
| 224 | _8000, | ||
| 225 | _10582, | ||
| 226 | _12500, | ||
| 227 | _15625, | ||
| 228 | _15873, | ||
| 229 | _25000, | ||
| 230 | _31250, | ||
| 231 | _50000, | ||
| 232 | _62500, | ||
| 233 | _100000, | ||
| 234 | _125000, | ||
| 235 | } | ||
| 236 | |||
| 237 | impl ExactSampleRate { | ||
| 238 | pub fn sample_rate(&self) -> u32 { | ||
| 239 | MasterClock::from(*self).sample_rate() | ||
| 240 | } | ||
| 241 | } | ||
| 242 | |||
| 243 | impl From<ExactSampleRate> for MasterClock { | ||
| 244 | fn from(value: ExactSampleRate) -> Self { | ||
| 245 | match value { | ||
| 246 | ExactSampleRate::_8000 => MasterClock::new(MckFreq::_32MDiv125, Ratio::_32x), | ||
| 247 | ExactSampleRate::_10582 => MasterClock::new(MckFreq::_32MDiv63, Ratio::_48x), | ||
| 248 | ExactSampleRate::_12500 => MasterClock::new(MckFreq::_32MDiv10, Ratio::_256x), | ||
| 249 | ExactSampleRate::_15625 => MasterClock::new(MckFreq::_32MDiv32, Ratio::_64x), | ||
| 250 | ExactSampleRate::_15873 => MasterClock::new(MckFreq::_32MDiv63, Ratio::_32x), | ||
| 251 | ExactSampleRate::_25000 => MasterClock::new(MckFreq::_32MDiv10, Ratio::_128x), | ||
| 252 | ExactSampleRate::_31250 => MasterClock::new(MckFreq::_32MDiv32, Ratio::_32x), | ||
| 253 | ExactSampleRate::_50000 => MasterClock::new(MckFreq::_32MDiv10, Ratio::_64x), | ||
| 254 | ExactSampleRate::_62500 => MasterClock::new(MckFreq::_32MDiv16, Ratio::_32x), | ||
| 255 | ExactSampleRate::_100000 => MasterClock::new(MckFreq::_32MDiv10, Ratio::_32x), | ||
| 256 | ExactSampleRate::_125000 => MasterClock::new(MckFreq::_32MDiv8, Ratio::_32x), | ||
| 257 | } | ||
| 258 | } | ||
| 259 | } | ||
| 260 | |||
| 289 | /// Sample width. | 261 | /// Sample width. |
| 290 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | 262 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] |
| 291 | pub enum SampleWidth { | 263 | pub enum SampleWidth { |
| @@ -336,10 +308,8 @@ impl From<Format> for bool { | |||
| 336 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | 308 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] |
| 337 | pub enum Channels { | 309 | pub enum Channels { |
| 338 | Stereo, | 310 | Stereo, |
| 339 | /// Mono left | 311 | MonoLeft, |
| 340 | Left, | 312 | MonoRight, |
| 341 | /// Mono right | ||
| 342 | Right, | ||
| 343 | } | 313 | } |
| 344 | 314 | ||
| 345 | impl From<Channels> for u8 { | 315 | impl From<Channels> for u8 { |
| @@ -350,131 +320,160 @@ impl From<Channels> for u8 { | |||
| 350 | 320 | ||
| 351 | /// Interface to the I2S peripheral using EasyDMA to offload the transmission and reception workload. | 321 | /// Interface to the I2S peripheral using EasyDMA to offload the transmission and reception workload. |
| 352 | pub struct I2S<'d, T: Instance> { | 322 | pub struct I2S<'d, T: Instance> { |
| 353 | _p: PeripheralRef<'d, T>, | 323 | i2s: PeripheralRef<'d, T>, |
| 324 | irq: PeripheralRef<'d, T::Interrupt>, | ||
| 325 | mck: Option<PeripheralRef<'d, AnyPin>>, | ||
| 326 | sck: PeripheralRef<'d, AnyPin>, | ||
| 327 | lrck: PeripheralRef<'d, AnyPin>, | ||
| 328 | sdin: Option<PeripheralRef<'d, AnyPin>>, | ||
| 329 | sdout: Option<PeripheralRef<'d, AnyPin>>, | ||
| 330 | master_clock: Option<MasterClock>, | ||
| 331 | config: Config, | ||
| 354 | } | 332 | } |
| 355 | 333 | ||
| 356 | impl<'d, T: Instance> I2S<'d, T> { | 334 | impl<'d, T: Instance> I2S<'d, T> { |
| 357 | /// Create a new I2S | 335 | /// Create a new I2S in master mode |
| 358 | pub fn new( | 336 | pub fn master( |
| 359 | i2s: impl Peripheral<P = T> + 'd, | 337 | i2s: impl Peripheral<P = T> + 'd, |
| 360 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 338 | irq: impl Peripheral<P = T::Interrupt> + 'd, |
| 361 | mck: impl Peripheral<P = impl GpioPin> + 'd, | 339 | mck: impl Peripheral<P = impl GpioPin> + 'd, |
| 362 | sck: impl Peripheral<P = impl GpioPin> + 'd, | 340 | sck: impl Peripheral<P = impl GpioPin> + 'd, |
| 363 | lrck: impl Peripheral<P = impl GpioPin> + 'd, | 341 | lrck: impl Peripheral<P = impl GpioPin> + 'd, |
| 364 | sdin: impl Peripheral<P = impl GpioPin> + 'd, | 342 | master_clock: MasterClock, |
| 365 | sdout: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 366 | config: Config, | 343 | config: Config, |
| 367 | ) -> Self { | 344 | ) -> Self { |
| 368 | into_ref!(mck, sck, lrck, sdin, sdout); | 345 | into_ref!(i2s, irq, mck, sck, lrck); |
| 369 | Self::new_inner( | 346 | Self { |
| 370 | i2s, | 347 | i2s, |
| 371 | irq, | 348 | irq, |
| 372 | mck.map_into(), | 349 | mck: Some(mck.map_into()), |
| 373 | sck.map_into(), | 350 | sck: sck.map_into(), |
| 374 | lrck.map_into(), | 351 | lrck: lrck.map_into(), |
| 375 | sdin.map_into(), | 352 | sdin: None, |
| 376 | sdout.map_into(), | 353 | sdout: None, |
| 354 | master_clock: Some(master_clock), | ||
| 377 | config, | 355 | config, |
| 378 | ) | 356 | } |
| 379 | } | 357 | } |
| 380 | 358 | ||
| 381 | fn new_inner( | 359 | /// Create a new I2S in slave mode |
| 360 | pub fn slave( | ||
| 382 | i2s: impl Peripheral<P = T> + 'd, | 361 | i2s: impl Peripheral<P = T> + 'd, |
| 383 | irq: impl Peripheral<P = T::Interrupt> + 'd, | 362 | irq: impl Peripheral<P = T::Interrupt> + 'd, |
| 384 | mck: PeripheralRef<'d, AnyPin>, | 363 | sck: impl Peripheral<P = impl GpioPin> + 'd, |
| 385 | sck: PeripheralRef<'d, AnyPin>, | 364 | lrck: impl Peripheral<P = impl GpioPin> + 'd, |
| 386 | lrck: PeripheralRef<'d, AnyPin>, | ||
| 387 | sdin: PeripheralRef<'d, AnyPin>, | ||
| 388 | sdout: PeripheralRef<'d, AnyPin>, | ||
| 389 | config: Config, | 365 | config: Config, |
| 390 | ) -> Self { | 366 | ) -> Self { |
| 391 | into_ref!(i2s, irq, mck, sck, lrck, sdin, sdout); | 367 | into_ref!(i2s, irq, sck, lrck); |
| 392 | 368 | Self { | |
| 393 | Self::apply_config(&config); | 369 | i2s, |
| 394 | Self::select_pins(mck, sck, lrck, sdin, sdout); | 370 | irq, |
| 395 | Self::setup_interrupt(irq); | 371 | mck: None, |
| 396 | 372 | sck: sck.map_into(), | |
| 397 | T::regs().enable.write(|w| w.enable().enabled()); | 373 | lrck: lrck.map_into(), |
| 398 | 374 | sdin: None, | |
| 399 | Self { _p: i2s } | 375 | sdout: None, |
| 376 | master_clock: None, | ||
| 377 | config, | ||
| 378 | } | ||
| 400 | } | 379 | } |
| 401 | 380 | ||
| 402 | /// I2S output only | 381 | /// I2S output only |
| 403 | pub fn output(self) -> Output<'d, T> { | 382 | pub fn output(mut self, sdout: impl Peripheral<P = impl GpioPin> + 'd) -> OutputStream<'d, T> { |
| 404 | Output { _p: self._p } | 383 | self.sdout = Some(sdout.into_ref().map_into()); |
| 384 | OutputStream { _p: self.build() } | ||
| 405 | } | 385 | } |
| 406 | 386 | ||
| 407 | /// I2S input only | 387 | /// I2S input only |
| 408 | pub fn input(self) -> Input<'d, T> { | 388 | pub fn input(mut self, sdin: impl Peripheral<P = impl GpioPin> + 'd) -> InputStream<'d, T> { |
| 409 | Input { _p: self._p } | 389 | self.sdin = Some(sdin.into_ref().map_into()); |
| 390 | InputStream { _p: self.build() } | ||
| 410 | } | 391 | } |
| 411 | 392 | ||
| 412 | /// I2S full duplex (input and output) | 393 | /// I2S full duplex (input and output) |
| 413 | pub fn full_duplex(self) -> FullDuplex<'d, T> { | 394 | pub fn full_duplex( |
| 414 | FullDuplex { _p: self._p } | 395 | mut self, |
| 396 | sdin: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 397 | sdout: impl Peripheral<P = impl GpioPin> + 'd, | ||
| 398 | ) -> FullDuplexStream<'d, T> { | ||
| 399 | self.sdout = Some(sdout.into_ref().map_into()); | ||
| 400 | self.sdin = Some(sdin.into_ref().map_into()); | ||
| 401 | FullDuplexStream { _p: self.build() } | ||
| 415 | } | 402 | } |
| 416 | 403 | ||
| 417 | fn apply_config(config: &Config) { | 404 | fn build(self) -> PeripheralRef<'d, T> { |
| 405 | self.apply_config(); | ||
| 406 | self.select_pins(); | ||
| 407 | self.setup_interrupt(); | ||
| 408 | |||
| 409 | let device = Device::<T>::new(); | ||
| 410 | device.enable(); | ||
| 411 | |||
| 412 | self.i2s | ||
| 413 | } | ||
| 414 | |||
| 415 | fn apply_config(&self) { | ||
| 418 | let c = &T::regs().config; | 416 | let c = &T::regs().config; |
| 419 | match config.mode { | 417 | match &self.master_clock { |
| 420 | Mode::Master { freq, ratio } => { | 418 | Some(MasterClock { freq, ratio }) => { |
| 421 | c.mode.write(|w| w.mode().master()); | 419 | c.mode.write(|w| w.mode().master()); |
| 422 | c.mcken.write(|w| w.mcken().enabled()); | 420 | c.mcken.write(|w| w.mcken().enabled()); |
| 423 | c.mckfreq | 421 | c.mckfreq |
| 424 | .write(|w| unsafe { w.mckfreq().bits(freq.to_register_value()) }); | 422 | .write(|w| unsafe { w.mckfreq().bits(freq.to_register_value()) }); |
| 425 | c.ratio.write(|w| unsafe { w.ratio().bits(ratio.into()) }); | 423 | c.ratio.write(|w| unsafe { w.ratio().bits(ratio.to_register_value()) }); |
| 426 | } | 424 | } |
| 427 | Mode::Slave => { | 425 | None => { |
| 428 | c.mode.write(|w| w.mode().slave()); | 426 | c.mode.write(|w| w.mode().slave()); |
| 429 | } | 427 | } |
| 430 | }; | 428 | }; |
| 431 | 429 | ||
| 432 | c.swidth.write(|w| unsafe { w.swidth().bits(config.swidth.into()) }); | 430 | c.swidth |
| 433 | c.align.write(|w| w.align().bit(config.align.into())); | 431 | .write(|w| unsafe { w.swidth().bits(self.config.sample_width.into()) }); |
| 434 | c.format.write(|w| w.format().bit(config.format.into())); | 432 | c.align.write(|w| w.align().bit(self.config.align.into())); |
| 433 | c.format.write(|w| w.format().bit(self.config.format.into())); | ||
| 435 | c.channels | 434 | c.channels |
| 436 | .write(|w| unsafe { w.channels().bits(config.channels.into()) }); | 435 | .write(|w| unsafe { w.channels().bits(self.config.channels.into()) }); |
| 437 | } | 436 | } |
| 438 | 437 | ||
| 439 | fn select_pins( | 438 | fn select_pins(&self) { |
| 440 | mck: PeripheralRef<'d, AnyPin>, | ||
| 441 | sck: PeripheralRef<'d, AnyPin>, | ||
| 442 | lrck: PeripheralRef<'d, AnyPin>, | ||
| 443 | sdin: PeripheralRef<'d, AnyPin>, | ||
| 444 | sdout: PeripheralRef<'d, AnyPin>, | ||
| 445 | ) { | ||
| 446 | let psel = &T::regs().psel; | 439 | let psel = &T::regs().psel; |
| 447 | 440 | ||
| 448 | psel.mck.write(|w| { | 441 | if let Some(mck) = &self.mck { |
| 449 | unsafe { w.bits(mck.psel_bits()) }; | 442 | psel.mck.write(|w| { |
| 450 | w.connect().connected() | 443 | unsafe { w.bits(mck.psel_bits()) }; |
| 451 | }); | 444 | w.connect().connected() |
| 445 | }); | ||
| 446 | } | ||
| 452 | 447 | ||
| 453 | psel.sck.write(|w| { | 448 | psel.sck.write(|w| { |
| 454 | unsafe { w.bits(sck.psel_bits()) }; | 449 | unsafe { w.bits(self.sck.psel_bits()) }; |
| 455 | w.connect().connected() | 450 | w.connect().connected() |
| 456 | }); | 451 | }); |
| 457 | 452 | ||
| 458 | psel.lrck.write(|w| { | 453 | psel.lrck.write(|w| { |
| 459 | unsafe { w.bits(lrck.psel_bits()) }; | 454 | unsafe { w.bits(self.lrck.psel_bits()) }; |
| 460 | w.connect().connected() | 455 | w.connect().connected() |
| 461 | }); | 456 | }); |
| 462 | 457 | ||
| 463 | psel.sdin.write(|w| { | 458 | if let Some(sdin) = &self.sdin { |
| 464 | unsafe { w.bits(sdin.psel_bits()) }; | 459 | psel.sdin.write(|w| { |
| 465 | w.connect().connected() | 460 | unsafe { w.bits(sdin.psel_bits()) }; |
| 466 | }); | 461 | w.connect().connected() |
| 462 | }); | ||
| 463 | } | ||
| 467 | 464 | ||
| 468 | psel.sdout.write(|w| { | 465 | if let Some(sdout) = &self.sdout { |
| 469 | unsafe { w.bits(sdout.psel_bits()) }; | 466 | psel.sdout.write(|w| { |
| 470 | w.connect().connected() | 467 | unsafe { w.bits(sdout.psel_bits()) }; |
| 471 | }); | 468 | w.connect().connected() |
| 469 | }); | ||
| 470 | } | ||
| 472 | } | 471 | } |
| 473 | 472 | ||
| 474 | fn setup_interrupt(irq: PeripheralRef<'d, T::Interrupt>) { | 473 | fn setup_interrupt(&self) { |
| 475 | irq.set_handler(Self::on_interrupt); | 474 | self.irq.set_handler(Self::on_interrupt); |
| 476 | irq.unpend(); | 475 | self.irq.unpend(); |
| 477 | irq.enable(); | 476 | self.irq.enable(); |
| 478 | 477 | ||
| 479 | let device = Device::<T>::new(); | 478 | let device = Device::<T>::new(); |
| 480 | device.disable_tx_ptr_interrupt(); | 479 | device.disable_tx_ptr_interrupt(); |
| @@ -538,17 +537,32 @@ impl<'d, T: Instance> I2S<'d, T> { | |||
| 538 | device.disable(); | 537 | device.disable(); |
| 539 | } | 538 | } |
| 540 | 539 | ||
| 541 | async fn send<B>(buffer: B) -> Result<(), Error> | 540 | async fn send_from_ram<S>(buffer_ptr: *const [S]) -> Result<(), Error> |
| 542 | where | 541 | where |
| 543 | B: Buffer, | 542 | S: Sample, |
| 544 | { | 543 | { |
| 545 | trace!("SEND: {}", buffer.bytes_ptr() as u32); | 544 | trace!("SEND: {}", buffer_ptr as *const S as u32); |
| 546 | 545 | ||
| 547 | let device = Device::<T>::new(); | 546 | slice_in_ram_or(buffer_ptr, Error::BufferNotInDataMemory)?; |
| 548 | let drop = device.on_tx_drop(); | ||
| 549 | 547 | ||
| 550 | compiler_fence(Ordering::SeqCst); | 548 | compiler_fence(Ordering::SeqCst); |
| 551 | 549 | ||
| 550 | let device = Device::<T>::new(); | ||
| 551 | |||
| 552 | let drop = OnDrop::new(move || { | ||
| 553 | trace!("TX DROP: Stopping"); | ||
| 554 | |||
| 555 | let device = Device::<T>::new(); | ||
| 556 | device.disable_tx_ptr_interrupt(); | ||
| 557 | device.reset_tx_ptr_event(); | ||
| 558 | device.disable_tx(); | ||
| 559 | |||
| 560 | // TX is stopped almost instantly, spinning is fine. | ||
| 561 | while !device.is_tx_ptr_updated() {} | ||
| 562 | |||
| 563 | trace!("TX DROP: Stopped"); | ||
| 564 | }); | ||
| 565 | |||
| 552 | poll_fn(|cx| { | 566 | poll_fn(|cx| { |
| 553 | T::state().tx_waker.register(cx.waker()); | 567 | T::state().tx_waker.register(cx.waker()); |
| 554 | 568 | ||
| @@ -564,7 +578,7 @@ impl<'d, T: Instance> I2S<'d, T> { | |||
| 564 | }) | 578 | }) |
| 565 | .await; | 579 | .await; |
| 566 | 580 | ||
| 567 | device.set_tx_buffer(buffer)?; | 581 | device.update_tx(buffer_ptr)?; |
| 568 | 582 | ||
| 569 | compiler_fence(Ordering::SeqCst); | 583 | compiler_fence(Ordering::SeqCst); |
| 570 | drop.defuse(); | 584 | drop.defuse(); |
| @@ -572,17 +586,33 @@ impl<'d, T: Instance> I2S<'d, T> { | |||
| 572 | Ok(()) | 586 | Ok(()) |
| 573 | } | 587 | } |
| 574 | 588 | ||
| 575 | async fn receive<B>(buffer: B) -> Result<(), Error> | 589 | async fn receive_from_ram<S>(buffer_ptr: *mut [S]) -> Result<(), Error> |
| 576 | where | 590 | where |
| 577 | B: Buffer, | 591 | S: Sample, |
| 578 | { | 592 | { |
| 579 | trace!("RECEIVE: {}", buffer.bytes_ptr() as u32); | 593 | trace!("RECEIVE: {}", buffer_ptr as *const S as u32); |
| 580 | 594 | ||
| 581 | let device = Device::<T>::new(); | 595 | // NOTE: RAM slice check for rx is not necessary, as a mutable |
| 582 | let drop = device.on_rx_drop(); | 596 | // slice can only be built from data located in RAM. |
| 583 | 597 | ||
| 584 | compiler_fence(Ordering::SeqCst); | 598 | compiler_fence(Ordering::SeqCst); |
| 585 | 599 | ||
| 600 | let device = Device::<T>::new(); | ||
| 601 | |||
| 602 | let drop = OnDrop::new(move || { | ||
| 603 | trace!("RX DROP: Stopping"); | ||
| 604 | |||
| 605 | let device = Device::<T>::new(); | ||
| 606 | device.disable_rx_ptr_interrupt(); | ||
| 607 | device.reset_rx_ptr_event(); | ||
| 608 | device.disable_rx(); | ||
| 609 | |||
| 610 | // TX is stopped almost instantly, spinning is fine. | ||
| 611 | while !device.is_rx_ptr_updated() {} | ||
| 612 | |||
| 613 | trace!("RX DROP: Stopped"); | ||
| 614 | }); | ||
| 615 | |||
| 586 | poll_fn(|cx| { | 616 | poll_fn(|cx| { |
| 587 | T::state().rx_waker.register(cx.waker()); | 617 | T::state().rx_waker.register(cx.waker()); |
| 588 | 618 | ||
| @@ -598,9 +628,10 @@ impl<'d, T: Instance> I2S<'d, T> { | |||
| 598 | }) | 628 | }) |
| 599 | .await; | 629 | .await; |
| 600 | 630 | ||
| 601 | device.set_rx_buffer(buffer)?; | 631 | device.update_rx(buffer_ptr)?; |
| 602 | 632 | ||
| 603 | compiler_fence(Ordering::SeqCst); | 633 | compiler_fence(Ordering::SeqCst); |
| 634 | |||
| 604 | drop.defuse(); | 635 | drop.defuse(); |
| 605 | 636 | ||
| 606 | Ok(()) | 637 | Ok(()) |
| @@ -608,15 +639,15 @@ impl<'d, T: Instance> I2S<'d, T> { | |||
| 608 | } | 639 | } |
| 609 | 640 | ||
| 610 | /// I2S output | 641 | /// I2S output |
| 611 | pub struct Output<'d, T: Instance> { | 642 | pub struct OutputStream<'d, T: Instance> { |
| 612 | _p: PeripheralRef<'d, T>, | 643 | _p: PeripheralRef<'d, T>, |
| 613 | } | 644 | } |
| 614 | 645 | ||
| 615 | impl<'d, T: Instance> Output<'d, T> { | 646 | impl<'d, T: Instance> OutputStream<'d, T> { |
| 616 | /// Prepare the initial buffer and start the I2S transfer. | 647 | /// Prepare the initial buffer and start the I2S transfer. |
| 617 | pub async fn start<B>(&self, buffer: B) -> Result<(), Error> | 648 | pub async fn start<S>(&self, buffer: &[S]) -> Result<(), Error> |
| 618 | where | 649 | where |
| 619 | B: Buffer, | 650 | S: Sample, |
| 620 | { | 651 | { |
| 621 | let device = Device::<T>::new(); | 652 | let device = Device::<T>::new(); |
| 622 | 653 | ||
| @@ -627,7 +658,8 @@ impl<'d, T: Instance> Output<'d, T> { | |||
| 627 | 658 | ||
| 628 | device.enable(); | 659 | device.enable(); |
| 629 | device.enable_tx(); | 660 | device.enable_tx(); |
| 630 | device.set_tx_buffer(buffer)?; | 661 | |
| 662 | device.update_tx(buffer as *const [S])?; | ||
| 631 | 663 | ||
| 632 | s.started.store(true, Ordering::Relaxed); | 664 | s.started.store(true, Ordering::Relaxed); |
| 633 | 665 | ||
| @@ -647,24 +679,24 @@ impl<'d, T: Instance> Output<'d, T> { | |||
| 647 | /// The buffer must not be written while being used by the DMA, | 679 | /// The buffer must not be written while being used by the DMA, |
| 648 | /// which takes two other `send`s being awaited. | 680 | /// which takes two other `send`s being awaited. |
| 649 | #[allow(unused_mut)] | 681 | #[allow(unused_mut)] |
| 650 | pub async fn send<B>(&mut self, buffer: B) -> Result<(), Error> | 682 | pub async fn send_from_ram<S>(&mut self, buffer: &[S]) -> Result<(), Error> |
| 651 | where | 683 | where |
| 652 | B: Buffer, | 684 | S: Sample, |
| 653 | { | 685 | { |
| 654 | I2S::<T>::send(buffer).await | 686 | I2S::<T>::send_from_ram(buffer as *const [S]).await |
| 655 | } | 687 | } |
| 656 | } | 688 | } |
| 657 | 689 | ||
| 658 | /// I2S input | 690 | /// I2S input |
| 659 | pub struct Input<'d, T: Instance> { | 691 | pub struct InputStream<'d, T: Instance> { |
| 660 | _p: PeripheralRef<'d, T>, | 692 | _p: PeripheralRef<'d, T>, |
| 661 | } | 693 | } |
| 662 | 694 | ||
| 663 | impl<'d, T: Instance> Input<'d, T> { | 695 | impl<'d, T: Instance> InputStream<'d, T> { |
| 664 | /// Prepare the initial buffer and start the I2S transfer. | 696 | /// Prepare the initial buffer and start the I2S transfer. |
| 665 | pub async fn start<B>(&self, buffer: B) -> Result<(), Error> | 697 | pub async fn start<S>(&self, buffer: &mut [S]) -> Result<(), Error> |
| 666 | where | 698 | where |
| 667 | B: Buffer, | 699 | S: Sample, |
| 668 | { | 700 | { |
| 669 | let device = Device::<T>::new(); | 701 | let device = Device::<T>::new(); |
| 670 | 702 | ||
| @@ -675,7 +707,8 @@ impl<'d, T: Instance> Input<'d, T> { | |||
| 675 | 707 | ||
| 676 | device.enable(); | 708 | device.enable(); |
| 677 | device.enable_rx(); | 709 | device.enable_rx(); |
| 678 | device.set_rx_buffer(buffer)?; | 710 | |
| 711 | device.update_rx(buffer as *mut [S])?; | ||
| 679 | 712 | ||
| 680 | s.started.store(true, Ordering::Relaxed); | 713 | s.started.store(true, Ordering::Relaxed); |
| 681 | 714 | ||
| @@ -695,24 +728,24 @@ impl<'d, T: Instance> Input<'d, T> { | |||
| 695 | /// The buffer must not be read while being used by the DMA, | 728 | /// The buffer must not be read while being used by the DMA, |
| 696 | /// which takes two other `receive`s being awaited. | 729 | /// which takes two other `receive`s being awaited. |
| 697 | #[allow(unused_mut)] | 730 | #[allow(unused_mut)] |
| 698 | pub async fn receive<B>(&mut self, buffer: B) -> Result<(), Error> | 731 | pub async fn receive_from_ram<S>(&mut self, buffer: &mut [S]) -> Result<(), Error> |
| 699 | where | 732 | where |
| 700 | B: Buffer, | 733 | S: Sample, |
| 701 | { | 734 | { |
| 702 | I2S::<T>::receive(buffer).await | 735 | I2S::<T>::receive_from_ram(buffer as *mut [S]).await |
| 703 | } | 736 | } |
| 704 | } | 737 | } |
| 705 | 738 | ||
| 706 | /// I2S ful duplex (input & output) | 739 | /// I2S full duplex stream (input & output) |
| 707 | pub struct FullDuplex<'d, T: Instance> { | 740 | pub struct FullDuplexStream<'d, T: Instance> { |
| 708 | _p: PeripheralRef<'d, T>, | 741 | _p: PeripheralRef<'d, T>, |
| 709 | } | 742 | } |
| 710 | 743 | ||
| 711 | impl<'d, T: Instance> FullDuplex<'d, T> { | 744 | impl<'d, T: Instance> FullDuplexStream<'d, T> { |
| 712 | /// Prepare the initial buffers and start the I2S transfer. | 745 | /// Prepare the initial buffers and start the I2S transfer. |
| 713 | pub async fn start<B>(&self, buffer_out: B, buffer_in: B) -> Result<(), Error> | 746 | pub async fn start<S>(&self, buffer_out: &[S], buffer_in: &mut [S]) -> Result<(), Error> |
| 714 | where | 747 | where |
| 715 | B: Buffer, | 748 | S: Sample, |
| 716 | { | 749 | { |
| 717 | let device = Device::<T>::new(); | 750 | let device = Device::<T>::new(); |
| 718 | 751 | ||
| @@ -724,8 +757,9 @@ impl<'d, T: Instance> FullDuplex<'d, T> { | |||
| 724 | device.enable(); | 757 | device.enable(); |
| 725 | device.enable_tx(); | 758 | device.enable_tx(); |
| 726 | device.enable_rx(); | 759 | device.enable_rx(); |
| 727 | device.set_tx_buffer(buffer_out)?; | 760 | |
| 728 | device.set_rx_buffer(buffer_in)?; | 761 | device.update_tx(buffer_out as *const [S])?; |
| 762 | device.update_rx(buffer_in as *mut [S])?; | ||
| 729 | 763 | ||
| 730 | s.started.store(true, Ordering::Relaxed); | 764 | s.started.store(true, Ordering::Relaxed); |
| 731 | 765 | ||
| @@ -745,12 +779,12 @@ impl<'d, T: Instance> FullDuplex<'d, T> { | |||
| 745 | /// The buffers must not be written/read while being used by the DMA, | 779 | /// The buffers must not be written/read while being used by the DMA, |
| 746 | /// which takes two other `send_and_receive` operations being awaited. | 780 | /// which takes two other `send_and_receive` operations being awaited. |
| 747 | #[allow(unused_mut)] | 781 | #[allow(unused_mut)] |
| 748 | pub async fn send_and_receive<B>(&mut self, buffer_out: B, buffer_in: B) -> Result<(), Error> | 782 | pub async fn send_and_receive_from_ram<S>(&mut self, buffer_out: &[S], buffer_in: &mut [S]) -> Result<(), Error> |
| 749 | where | 783 | where |
| 750 | B: Buffer, | 784 | S: Sample, |
| 751 | { | 785 | { |
| 752 | I2S::<T>::send(buffer_out).await?; | 786 | I2S::<T>::send_from_ram(buffer_out as *const [S]).await?; |
| 753 | I2S::<T>::receive(buffer_in).await?; | 787 | I2S::<T>::receive_from_ram(buffer_in as *mut [S]).await?; |
| 754 | Ok(()) | 788 | Ok(()) |
| 755 | } | 789 | } |
| 756 | } | 790 | } |
| @@ -833,38 +867,6 @@ impl<T: Instance> Device<T> { | |||
| 833 | self.0.intenset.write(|w| w.stopped().set()); | 867 | self.0.intenset.write(|w| w.stopped().set()); |
| 834 | } | 868 | } |
| 835 | 869 | ||
| 836 | #[inline] | ||
| 837 | fn set_tx_buffer<B>(&self, buffer: B) -> Result<(), Error> | ||
| 838 | where | ||
| 839 | B: Buffer, | ||
| 840 | { | ||
| 841 | let (ptr, maxcnt) = Self::validate_buffer(buffer)?; | ||
| 842 | self.0.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) }); | ||
| 843 | self.0.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr) }); | ||
| 844 | Ok(()) | ||
| 845 | } | ||
| 846 | |||
| 847 | #[inline] | ||
| 848 | fn set_rx_buffer<B>(&self, buffer: B) -> Result<(), Error> | ||
| 849 | where | ||
| 850 | B: Buffer, | ||
| 851 | { | ||
| 852 | let (ptr, maxcnt) = Self::validate_buffer(buffer)?; | ||
| 853 | self.0.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) }); | ||
| 854 | self.0.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr) }); | ||
| 855 | Ok(()) | ||
| 856 | } | ||
| 857 | |||
| 858 | #[inline(always)] | ||
| 859 | fn is_tx_ptr_updated(&self) -> bool { | ||
| 860 | self.0.events_txptrupd.read().bits() != 0 | ||
| 861 | } | ||
| 862 | |||
| 863 | #[inline(always)] | ||
| 864 | fn is_rx_ptr_updated(&self) -> bool { | ||
| 865 | self.0.events_rxptrupd.read().bits() != 0 | ||
| 866 | } | ||
| 867 | |||
| 868 | #[inline(always)] | 870 | #[inline(always)] |
| 869 | fn reset_tx_ptr_event(&self) { | 871 | fn reset_tx_ptr_event(&self) { |
| 870 | trace!("TX PTR EVENT: Reset"); | 872 | trace!("TX PTR EVENT: Reset"); |
| @@ -901,58 +903,44 @@ impl<T: Instance> Device<T> { | |||
| 901 | self.0.intenclr.write(|w| w.rxptrupd().clear()); | 903 | self.0.intenclr.write(|w| w.rxptrupd().clear()); |
| 902 | } | 904 | } |
| 903 | 905 | ||
| 904 | #[inline] | 906 | #[inline(always)] |
| 905 | fn on_tx_drop(&self) -> OnDrop<fn()> { | 907 | fn is_tx_ptr_updated(&self) -> bool { |
| 906 | OnDrop::new(move || { | 908 | self.0.events_txptrupd.read().bits() != 0 |
| 907 | trace!("TX DROP: Stopping"); | 909 | } |
| 908 | |||
| 909 | let device = Device::<T>::new(); | ||
| 910 | device.disable_tx_ptr_interrupt(); | ||
| 911 | device.reset_tx_ptr_event(); | ||
| 912 | device.disable_tx(); | ||
| 913 | |||
| 914 | // TX is stopped almost instantly, spinning is fine. | ||
| 915 | while !device.is_tx_ptr_updated() {} | ||
| 916 | 910 | ||
| 917 | trace!("TX DROP: Stopped"); | 911 | #[inline(always)] |
| 918 | }) | 912 | fn is_rx_ptr_updated(&self) -> bool { |
| 913 | self.0.events_rxptrupd.read().bits() != 0 | ||
| 919 | } | 914 | } |
| 920 | 915 | ||
| 921 | #[inline] | 916 | #[inline] |
| 922 | fn on_rx_drop(&self) -> OnDrop<fn()> { | 917 | fn update_tx<S>(&self, buffer_ptr: *const [S]) -> Result<(), Error> { |
| 923 | OnDrop::new(move || { | 918 | let (ptr, maxcnt) = Self::validated_dma_parts(buffer_ptr)?; |
| 924 | trace!("RX DROP: Stopping"); | 919 | self.0.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) }); |
| 925 | 920 | self.0.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr) }); | |
| 926 | let device = Device::<T>::new(); | 921 | Ok(()) |
| 927 | device.disable_rx_ptr_interrupt(); | 922 | } |
| 928 | device.reset_rx_ptr_event(); | ||
| 929 | device.disable_rx(); | ||
| 930 | |||
| 931 | // TX is stopped almost instantly, spinning is fine. | ||
| 932 | while !device.is_rx_ptr_updated() {} | ||
| 933 | 923 | ||
| 934 | trace!("RX DROP: Stopped"); | 924 | #[inline] |
| 935 | }) | 925 | fn update_rx<S>(&self, buffer_ptr: *const [S]) -> Result<(), Error> { |
| 926 | let (ptr, maxcnt) = Self::validated_dma_parts(buffer_ptr)?; | ||
| 927 | self.0.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) }); | ||
| 928 | self.0.rxd.ptr.write(|w| unsafe { w.ptr().bits(ptr) }); | ||
| 929 | Ok(()) | ||
| 936 | } | 930 | } |
| 937 | 931 | ||
| 938 | fn validate_buffer<B>(buffer: B) -> Result<(u32, u32), Error> | 932 | fn validated_dma_parts<S>(buffer_ptr: *const [S]) -> Result<(u32, u32), Error> { |
| 939 | where | 933 | let (ptr, len) = slice_ptr_parts(buffer_ptr); |
| 940 | B: Buffer, | 934 | let ptr = ptr as u32; |
| 941 | { | 935 | let bytes_len = len * size_of::<S>(); |
| 942 | let ptr = buffer.bytes_ptr() as u32; | 936 | let maxcnt = (bytes_len / size_of::<u32>()) as u32; |
| 943 | let len = buffer.bytes_len(); | ||
| 944 | let maxcnt = ((len + core::mem::size_of::<u32>() - 1) / core::mem::size_of::<u32>()) as u32; | ||
| 945 | 937 | ||
| 946 | trace!("PTR={}, MAXCNT={}", ptr, maxcnt); | 938 | trace!("PTR={}, MAXCNT={}", ptr, maxcnt); |
| 947 | 939 | ||
| 948 | // TODO can we avoid repeating all those runtime checks for the same buffer again and again? | ||
| 949 | |||
| 950 | if ptr % 4 != 0 { | 940 | if ptr % 4 != 0 { |
| 951 | Err(Error::BufferMisaligned) | 941 | Err(Error::BufferMisaligned) |
| 952 | } else if len % 4 != 0 { | 942 | } else if bytes_len % 4 != 0 { |
| 953 | Err(Error::BufferLengthMisaligned) | 943 | Err(Error::BufferLengthMisaligned) |
| 954 | } else if (ptr as usize) < SRAM_LOWER || (ptr as usize) > SRAM_UPPER { | ||
| 955 | Err(Error::BufferNotInDataMemory) | ||
| 956 | } else if maxcnt as usize > EASY_DMA_SIZE { | 944 | } else if maxcnt as usize > EASY_DMA_SIZE { |
| 957 | Err(Error::BufferTooLong) | 945 | Err(Error::BufferTooLong) |
| 958 | } else { | 946 | } else { |
| @@ -998,60 +986,19 @@ impl<T: Sample, const N: usize> Default for AlignedBuffer<T, N> { | |||
| 998 | } | 986 | } |
| 999 | } | 987 | } |
| 1000 | 988 | ||
| 1001 | impl<T: Sample, const N: usize> AsRef<[T]> for AlignedBuffer<T, N> { | 989 | impl<T: Sample, const N: usize> Deref for AlignedBuffer<T, N> { |
| 1002 | fn as_ref(&self) -> &[T] { | 990 | type Target = [T]; |
| 991 | fn deref(&self) -> &Self::Target { | ||
| 1003 | self.0.as_slice() | 992 | self.0.as_slice() |
| 1004 | } | 993 | } |
| 1005 | } | 994 | } |
| 1006 | 995 | ||
| 1007 | impl<T: Sample, const N: usize> AsMut<[T]> for AlignedBuffer<T, N> { | 996 | impl<T: Sample, const N: usize> DerefMut for AlignedBuffer<T, N> { |
| 1008 | fn as_mut(&mut self) -> &mut [T] { | 997 | fn deref_mut(&mut self) -> &mut Self::Target { |
| 1009 | self.0.as_mut_slice() | 998 | self.0.as_mut_slice() |
| 1010 | } | 999 | } |
| 1011 | } | 1000 | } |
| 1012 | 1001 | ||
| 1013 | /// Common operations required for a buffer to be used by the DMA | ||
| 1014 | pub trait Buffer: Sized { | ||
| 1015 | fn bytes_ptr(&self) -> *const u8; | ||
| 1016 | fn bytes_len(&self) -> usize; | ||
| 1017 | } | ||
| 1018 | |||
| 1019 | impl Buffer for &[i8] { | ||
| 1020 | #[inline] | ||
| 1021 | fn bytes_ptr(&self) -> *const u8 { | ||
| 1022 | self.as_ptr() as *const u8 | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | #[inline] | ||
| 1026 | fn bytes_len(&self) -> usize { | ||
| 1027 | self.len() | ||
| 1028 | } | ||
| 1029 | } | ||
| 1030 | |||
| 1031 | impl Buffer for &[i16] { | ||
| 1032 | #[inline] | ||
| 1033 | fn bytes_ptr(&self) -> *const u8 { | ||
| 1034 | self.as_ptr() as *const u8 | ||
| 1035 | } | ||
| 1036 | |||
| 1037 | #[inline] | ||
| 1038 | fn bytes_len(&self) -> usize { | ||
| 1039 | self.len() * core::mem::size_of::<i16>() | ||
| 1040 | } | ||
| 1041 | } | ||
| 1042 | |||
| 1043 | impl Buffer for &[i32] { | ||
| 1044 | #[inline] | ||
| 1045 | fn bytes_ptr(&self) -> *const u8 { | ||
| 1046 | self.as_ptr() as *const u8 | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | #[inline] | ||
| 1050 | fn bytes_len(&self) -> usize { | ||
| 1051 | self.len() * core::mem::size_of::<i32>() | ||
| 1052 | } | ||
| 1053 | } | ||
| 1054 | |||
| 1055 | pub(crate) mod sealed { | 1002 | pub(crate) mod sealed { |
| 1056 | use core::sync::atomic::AtomicBool; | 1003 | use core::sync::atomic::AtomicBool; |
| 1057 | 1004 | ||
diff --git a/examples/nrf/src/bin/i2s-generate.rs b/examples/nrf/src/bin/i2s_waveform.rs index c2b5578f3..81858ff59 100644 --- a/examples/nrf/src/bin/i2s-generate.rs +++ b/examples/nrf/src/bin/i2s_waveform.rs | |||
| @@ -6,33 +6,29 @@ use core::f32::consts::PI; | |||
| 6 | 6 | ||
| 7 | use defmt::{error, info}; | 7 | use defmt::{error, info}; |
| 8 | use embassy_executor::Spawner; | 8 | use embassy_executor::Spawner; |
| 9 | use embassy_nrf::i2s::{self, Sample as _}; | 9 | use embassy_nrf::i2s::{self, Channels, Config, MasterClock, Sample as _, SampleWidth, I2S}; |
| 10 | use embassy_nrf::interrupt; | 10 | use embassy_nrf::interrupt; |
| 11 | use {defmt_rtt as _, panic_probe as _}; | 11 | use {defmt_rtt as _, panic_probe as _}; |
| 12 | 12 | ||
| 13 | type Sample = i16; | ||
| 14 | |||
| 15 | const NUM_SAMPLES: usize = 6000; | ||
| 16 | |||
| 13 | #[embassy_executor::main] | 17 | #[embassy_executor::main] |
| 14 | async fn main(_spawner: Spawner) { | 18 | async fn main(_spawner: Spawner) { |
| 15 | let p = embassy_nrf::init(Default::default()); | 19 | let p = embassy_nrf::init(Default::default()); |
| 16 | 20 | ||
| 17 | let mut config = i2s::Config::default(); | 21 | let master_clock: MasterClock = i2s::ExactSampleRate::_50000.into(); |
| 18 | config.mode = i2s::ExactSampleRate::_50000.into(); | ||
| 19 | config.channels = i2s::Channels::Left; | ||
| 20 | config.swidth = i2s::SampleWidth::_16bit; | ||
| 21 | let sample_rate = config.mode.sample_rate().expect("I2S Master"); | ||
| 22 | let inv_sample_rate = 1.0 / sample_rate as f32; | ||
| 23 | 22 | ||
| 23 | let sample_rate = master_clock.sample_rate(); | ||
| 24 | info!("Sample rate: {}", sample_rate); | 24 | info!("Sample rate: {}", sample_rate); |
| 25 | 25 | ||
| 26 | // Wait for a button press | 26 | let config = Config::default() |
| 27 | // use embassy_nrf::gpio::{Input, Pin, Pull}; | 27 | .sample_width(SampleWidth::_16bit) |
| 28 | // let mut btn1 = Input::new(p.P1_00.degrade(), Pull::Up); | 28 | .channels(Channels::MonoLeft); |
| 29 | // btn1.wait_for_low().await; | ||
| 30 | 29 | ||
| 31 | let irq = interrupt::take!(I2S); | 30 | let irq = interrupt::take!(I2S); |
| 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).output(); | 31 | 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); |
| 33 | |||
| 34 | type Sample = i16; | ||
| 35 | const NUM_SAMPLES: usize = 6000; | ||
| 36 | 32 | ||
| 37 | let mut buffers: [i2s::AlignedBuffer<Sample, NUM_SAMPLES>; 3] = [ | 33 | let mut buffers: [i2s::AlignedBuffer<Sample, NUM_SAMPLES>; 3] = [ |
| 38 | i2s::AlignedBuffer::default(), | 34 | i2s::AlignedBuffer::default(), |
| @@ -40,36 +36,16 @@ async fn main(_spawner: Spawner) { | |||
| 40 | i2s::AlignedBuffer::default(), | 36 | i2s::AlignedBuffer::default(), |
| 41 | ]; | 37 | ]; |
| 42 | 38 | ||
| 43 | let mut carrier = SineOsc::new(); | 39 | let mut waveform = Waveform::new(1.0 / sample_rate as f32); |
| 44 | |||
| 45 | let mut freq_mod = SineOsc::new(); | ||
| 46 | freq_mod.set_frequency(8.0, inv_sample_rate); | ||
| 47 | freq_mod.set_amplitude(1.0); | ||
| 48 | |||
| 49 | let mut amp_mod = SineOsc::new(); | ||
| 50 | amp_mod.set_frequency(16.0, inv_sample_rate); | ||
| 51 | amp_mod.set_amplitude(0.5); | ||
| 52 | |||
| 53 | let mut generate = |buf: &mut [Sample]| { | ||
| 54 | for sample in &mut buf.chunks_mut(1) { | ||
| 55 | let freq_modulation = bipolar_to_unipolar(freq_mod.generate()); | ||
| 56 | carrier.set_frequency(220.0 + 440.0 * freq_modulation, inv_sample_rate); | ||
| 57 | let amp_modulation = bipolar_to_unipolar(amp_mod.generate()); | ||
| 58 | carrier.set_amplitude(amp_modulation); | ||
| 59 | let signal = carrier.generate(); | ||
| 60 | let value = (Sample::SCALE as f32 * signal) as Sample; | ||
| 61 | sample[0] = value; | ||
| 62 | } | ||
| 63 | }; | ||
| 64 | 40 | ||
| 65 | generate(buffers[0].as_mut()); | 41 | waveform.process(&mut buffers[0]); |
| 66 | generate(buffers[1].as_mut()); | 42 | waveform.process(&mut buffers[1]); |
| 67 | 43 | ||
| 68 | i2s.start(buffers[0].as_ref()).await.expect("I2S Start"); | 44 | output_stream.start(&buffers[0]).await.expect("I2S Start"); |
| 69 | 45 | ||
| 70 | let mut index = 1; | 46 | let mut index = 1; |
| 71 | loop { | 47 | loop { |
| 72 | if let Err(err) = i2s.send(buffers[index].as_ref()).await { | 48 | if let Err(err) = output_stream.send_from_ram(&buffers[index]).await { |
| 73 | error!("{}", err); | 49 | error!("{}", err); |
| 74 | } | 50 | } |
| 75 | 51 | ||
| @@ -77,11 +53,54 @@ async fn main(_spawner: Spawner) { | |||
| 77 | if index >= 3 { | 53 | if index >= 3 { |
| 78 | index = 0; | 54 | index = 0; |
| 79 | } | 55 | } |
| 80 | generate(buffers[index].as_mut()); | 56 | |
| 57 | waveform.process(&mut buffers[index]); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | struct Waveform { | ||
| 62 | inv_sample_rate: f32, | ||
| 63 | carrier: SineOsc, | ||
| 64 | freq_mod: SineOsc, | ||
| 65 | amp_mod: SineOsc, | ||
| 66 | } | ||
| 67 | |||
| 68 | impl Waveform { | ||
| 69 | fn new(inv_sample_rate: f32) -> Self { | ||
| 70 | let carrier = SineOsc::new(); | ||
| 71 | |||
| 72 | let mut freq_mod = SineOsc::new(); | ||
| 73 | freq_mod.set_frequency(8.0, inv_sample_rate); | ||
| 74 | freq_mod.set_amplitude(1.0); | ||
| 75 | |||
| 76 | let mut amp_mod = SineOsc::new(); | ||
| 77 | amp_mod.set_frequency(16.0, inv_sample_rate); | ||
| 78 | amp_mod.set_amplitude(0.5); | ||
| 79 | |||
| 80 | Self { | ||
| 81 | inv_sample_rate, | ||
| 82 | carrier, | ||
| 83 | freq_mod, | ||
| 84 | amp_mod, | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | fn process(&mut self, buf: &mut [Sample]) { | ||
| 89 | for sample in buf.chunks_mut(1) { | ||
| 90 | let freq_modulation = bipolar_to_unipolar(self.freq_mod.generate()); | ||
| 91 | self.carrier | ||
| 92 | .set_frequency(110.0 + 440.0 * freq_modulation, self.inv_sample_rate); | ||
| 93 | |||
| 94 | let amp_modulation = bipolar_to_unipolar(self.amp_mod.generate()); | ||
| 95 | self.carrier.set_amplitude(amp_modulation); | ||
| 96 | |||
| 97 | let signal = self.carrier.generate(); | ||
| 98 | |||
| 99 | sample[0] = (Sample::SCALE as f32 * signal) as Sample; | ||
| 100 | } | ||
| 81 | } | 101 | } |
| 82 | } | 102 | } |
| 83 | 103 | ||
| 84 | #[derive(Clone)] | ||
| 85 | struct SineOsc { | 104 | struct SineOsc { |
| 86 | amplitude: f32, | 105 | amplitude: f32, |
| 87 | modulo: f32, | 106 | modulo: f32, |
