Interrupts, async, sine oscillator
This commit is contained in:
		
							parent
							
								
									10e3c3f2ec
								
							
						
					
					
						commit
						122a31d208
					
				@ -2,17 +2,18 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
//! I2S
 | 
					//! I2S
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//use core::future::poll_fn;
 | 
					use core::future::poll_fn;
 | 
				
			||||||
//use core::sync::atomic::{compiler_fence, Ordering};
 | 
					use core::sync::atomic::{compiler_fence, Ordering};
 | 
				
			||||||
//use core::task::Poll;
 | 
					use core::task::Poll;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//use embassy_hal_common::drop::OnDrop;
 | 
					use embassy_cortex_m::interrupt::{InterruptExt, Priority};
 | 
				
			||||||
 | 
					use embassy_hal_common::drop::OnDrop;
 | 
				
			||||||
use embassy_hal_common::{into_ref, PeripheralRef};
 | 
					use embassy_hal_common::{into_ref, PeripheralRef};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//use crate::gpio::sealed::Pin as _;
 | 
					//use crate::gpio::sealed::Pin as _;
 | 
				
			||||||
use crate::gpio::{AnyPin, Pin as GpioPin};
 | 
					use crate::gpio::{AnyPin, Pin as GpioPin};
 | 
				
			||||||
use crate::interrupt::Interrupt;
 | 
					use crate::interrupt::Interrupt;
 | 
				
			||||||
use crate::pac::i2s::CONFIG;
 | 
					use crate::pac::i2s::{RegisterBlock, CONFIG, PSEL};
 | 
				
			||||||
use crate::Peripheral;
 | 
					use crate::Peripheral;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: Define those in lib.rs somewhere else
 | 
					// TODO: Define those in lib.rs somewhere else
 | 
				
			||||||
@ -35,10 +36,39 @@ pub enum Error {
 | 
				
			|||||||
    // TODO: add other error variants.
 | 
					    // TODO: add other error variants.
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub const MODE_MASTER_8000: Mode = Mode::Master {
 | 
				
			||||||
 | 
					    freq: MckFreq::_32MDiv125,
 | 
				
			||||||
 | 
					    ratio: Ratio::_32x,
 | 
				
			||||||
 | 
					}; // error = 0
 | 
				
			||||||
 | 
					pub const MODE_MASTER_11025: Mode = Mode::Master {
 | 
				
			||||||
 | 
					    freq: MckFreq::_32MDiv15,
 | 
				
			||||||
 | 
					    ratio: Ratio::_192x,
 | 
				
			||||||
 | 
					}; // error = 86
 | 
				
			||||||
 | 
					pub const MODE_MASTER_16000: Mode = Mode::Master {
 | 
				
			||||||
 | 
					    freq: MckFreq::_32MDiv21,
 | 
				
			||||||
 | 
					    ratio: Ratio::_96x,
 | 
				
			||||||
 | 
					}; // error = 127
 | 
				
			||||||
 | 
					pub const MODE_MASTER_22050: Mode = Mode::Master {
 | 
				
			||||||
 | 
					    freq: MckFreq::_32MDiv15,
 | 
				
			||||||
 | 
					    ratio: Ratio::_96x,
 | 
				
			||||||
 | 
					}; // error = 172
 | 
				
			||||||
 | 
					pub const MODE_MASTER_32000: Mode = Mode::Master {
 | 
				
			||||||
 | 
					    freq: MckFreq::_32MDiv21,
 | 
				
			||||||
 | 
					    ratio: Ratio::_48x,
 | 
				
			||||||
 | 
					}; // error = 254
 | 
				
			||||||
 | 
					pub const MODE_MASTER_44100: Mode = Mode::Master {
 | 
				
			||||||
 | 
					    freq: MckFreq::_32MDiv15,
 | 
				
			||||||
 | 
					    ratio: Ratio::_48x,
 | 
				
			||||||
 | 
					}; // error = 344
 | 
				
			||||||
 | 
					pub const MODE_MASTER_48000: Mode = Mode::Master {
 | 
				
			||||||
 | 
					    freq: MckFreq::_32MDiv21,
 | 
				
			||||||
 | 
					    ratio: Ratio::_32x,
 | 
				
			||||||
 | 
					}; // error = 381
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone)]
 | 
					#[derive(Clone)]
 | 
				
			||||||
#[non_exhaustive]
 | 
					#[non_exhaustive]
 | 
				
			||||||
pub struct Config {
 | 
					pub struct Config {
 | 
				
			||||||
    pub ratio: Ratio,
 | 
					    pub mode: Mode,
 | 
				
			||||||
    pub swidth: SampleWidth,
 | 
					    pub swidth: SampleWidth,
 | 
				
			||||||
    pub align: Align,
 | 
					    pub align: Align,
 | 
				
			||||||
    pub format: Format,
 | 
					    pub format: Format,
 | 
				
			||||||
@ -48,7 +78,7 @@ pub struct Config {
 | 
				
			|||||||
impl Default for Config {
 | 
					impl Default for Config {
 | 
				
			||||||
    fn default() -> Self {
 | 
					    fn default() -> Self {
 | 
				
			||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            ratio: Ratio::_32x,
 | 
					            mode: MODE_MASTER_32000,
 | 
				
			||||||
            swidth: SampleWidth::_16bit,
 | 
					            swidth: SampleWidth::_16bit,
 | 
				
			||||||
            align: Align::Left,
 | 
					            align: Align::Left,
 | 
				
			||||||
            format: Format::I2S,
 | 
					            format: Format::I2S,
 | 
				
			||||||
@ -57,6 +87,66 @@ impl Default for Config {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// I2S Mode
 | 
				
			||||||
 | 
					#[derive(Debug, Eq, PartialEq, Clone, Copy)]
 | 
				
			||||||
 | 
					pub enum Mode {
 | 
				
			||||||
 | 
					    Master { freq: MckFreq, ratio: Ratio },
 | 
				
			||||||
 | 
					    Slave,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Mode {
 | 
				
			||||||
 | 
					    pub fn sample_rate(&self) -> Option<u32> {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Mode::Master { freq, ratio } => Some(freq.to_frequency() / ratio.to_divisor()),
 | 
				
			||||||
 | 
					            Mode::Slave => None,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Master clock generator frequency.
 | 
				
			||||||
 | 
					#[derive(Debug, Eq, PartialEq, Clone, Copy)]
 | 
				
			||||||
 | 
					pub enum MckFreq {
 | 
				
			||||||
 | 
					    _32MDiv8,
 | 
				
			||||||
 | 
					    _32MDiv10,
 | 
				
			||||||
 | 
					    _32MDiv11,
 | 
				
			||||||
 | 
					    _32MDiv15,
 | 
				
			||||||
 | 
					    _32MDiv16,
 | 
				
			||||||
 | 
					    _32MDiv21,
 | 
				
			||||||
 | 
					    _32MDiv23,
 | 
				
			||||||
 | 
					    _32MDiv30,
 | 
				
			||||||
 | 
					    _32MDiv31,
 | 
				
			||||||
 | 
					    _32MDiv32,
 | 
				
			||||||
 | 
					    _32MDiv42,
 | 
				
			||||||
 | 
					    _32MDiv63,
 | 
				
			||||||
 | 
					    _32MDiv125,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl MckFreq {
 | 
				
			||||||
 | 
					    const REGISTER_VALUES: &[u32] = &[
 | 
				
			||||||
 | 
					        0x20000000, 0x18000000, 0x16000000, 0x11000000, 0x10000000, 0x0C000000, 0x0B000000, 0x08800000, 0x08400000,
 | 
				
			||||||
 | 
					        0x08000000, 0x06000000, 0x04100000, 0x020C0000,
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const FREQUENCIES: &[u32] = &[
 | 
				
			||||||
 | 
					        4000000, 3200000, 2909090, 2133333, 2000000, 1523809, 1391304, 1066666, 1032258, 1000000, 761904, 507936,
 | 
				
			||||||
 | 
					        256000,
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn to_register_value(&self) -> u32 {
 | 
				
			||||||
 | 
					        Self::REGISTER_VALUES[usize::from(*self)]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn to_frequency(&self) -> u32 {
 | 
				
			||||||
 | 
					        Self::FREQUENCIES[usize::from(*self)]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<MckFreq> for usize {
 | 
				
			||||||
 | 
					    fn from(variant: MckFreq) -> Self {
 | 
				
			||||||
 | 
					        variant as _
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// MCK / LRCK ratio.
 | 
					/// MCK / LRCK ratio.
 | 
				
			||||||
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
 | 
					#[derive(Debug, Eq, PartialEq, Clone, Copy)]
 | 
				
			||||||
pub enum Ratio {
 | 
					pub enum Ratio {
 | 
				
			||||||
@ -71,6 +161,14 @@ pub enum Ratio {
 | 
				
			|||||||
    _512x,
 | 
					    _512x,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Ratio {
 | 
				
			||||||
 | 
					    const RATIOS: &[u32] = &[32, 48, 64, 96, 128, 192, 256, 384, 512];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn to_divisor(&self) -> u32 {
 | 
				
			||||||
 | 
					        Self::RATIOS[u8::from(*self) as usize]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl From<Ratio> for u8 {
 | 
					impl From<Ratio> for u8 {
 | 
				
			||||||
    fn from(variant: Ratio) -> Self {
 | 
					    fn from(variant: Ratio) -> Self {
 | 
				
			||||||
        variant as _
 | 
					        variant as _
 | 
				
			||||||
@ -136,31 +234,6 @@ impl From<Channels> for u8 {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// I2S Mode
 | 
					 | 
				
			||||||
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
 | 
					 | 
				
			||||||
pub enum Mode {
 | 
					 | 
				
			||||||
    Controller,
 | 
					 | 
				
			||||||
    Peripheral,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// /// Master clock generator frequency.
 | 
					 | 
				
			||||||
// #[derive(Debug, Eq, PartialEq, Clone, Copy)]
 | 
					 | 
				
			||||||
// pub enum MckFreq {
 | 
					 | 
				
			||||||
//     _32MDiv8 = 0x20000000,
 | 
					 | 
				
			||||||
//     _32MDiv10 = 0x18000000,
 | 
					 | 
				
			||||||
//     _32MDiv11 = 0x16000000,
 | 
					 | 
				
			||||||
//     _32MDiv15 = 0x11000000,
 | 
					 | 
				
			||||||
//     _32MDiv16 = 0x10000000,
 | 
					 | 
				
			||||||
//     _32MDiv21 = 0x0C000000,
 | 
					 | 
				
			||||||
//     _32MDiv23 = 0x0B000000,
 | 
					 | 
				
			||||||
//     _32MDiv30 = 0x08800000,
 | 
					 | 
				
			||||||
//     _32MDiv31 = 0x08400000,
 | 
					 | 
				
			||||||
//     _32MDiv32 = 0x08000000,
 | 
					 | 
				
			||||||
//     _32MDiv42 = 0x06000000,
 | 
					 | 
				
			||||||
//     _32MDiv63 = 0x04100000,
 | 
					 | 
				
			||||||
//     _32MDiv125 = 0x020C0000,
 | 
					 | 
				
			||||||
// }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Interface to the UARTE peripheral using EasyDMA to offload the transmission and reception workload.
 | 
					/// Interface to the UARTE peripheral using EasyDMA to offload the transmission and reception workload.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// For more details about EasyDMA, consult the module documentation.
 | 
					/// For more details about EasyDMA, consult the module documentation.
 | 
				
			||||||
@ -185,7 +258,7 @@ impl<'d, T: Instance> I2S<'d, T> {
 | 
				
			|||||||
    /// Create a new I2S
 | 
					    /// Create a new I2S
 | 
				
			||||||
    pub fn new(
 | 
					    pub fn new(
 | 
				
			||||||
        i2s: impl Peripheral<P = T> + 'd,
 | 
					        i2s: impl Peripheral<P = T> + 'd,
 | 
				
			||||||
        // irq: impl Peripheral<P = T::Interrupt> + 'd,
 | 
					        irq: impl Peripheral<P = T::Interrupt> + 'd,
 | 
				
			||||||
        mck: impl Peripheral<P = impl GpioPin> + 'd,
 | 
					        mck: impl Peripheral<P = impl GpioPin> + 'd,
 | 
				
			||||||
        sck: impl Peripheral<P = impl GpioPin> + 'd,
 | 
					        sck: impl Peripheral<P = impl GpioPin> + 'd,
 | 
				
			||||||
        lrck: impl Peripheral<P = impl GpioPin> + 'd,
 | 
					        lrck: impl Peripheral<P = impl GpioPin> + 'd,
 | 
				
			||||||
@ -196,7 +269,7 @@ impl<'d, T: Instance> I2S<'d, T> {
 | 
				
			|||||||
        into_ref!(mck, sck, lrck, sdin, sdout);
 | 
					        into_ref!(mck, sck, lrck, sdin, sdout);
 | 
				
			||||||
        Self::new_inner(
 | 
					        Self::new_inner(
 | 
				
			||||||
            i2s,
 | 
					            i2s,
 | 
				
			||||||
            // irq,
 | 
					            irq,
 | 
				
			||||||
            mck.map_into(),
 | 
					            mck.map_into(),
 | 
				
			||||||
            sck.map_into(),
 | 
					            sck.map_into(),
 | 
				
			||||||
            lrck.map_into(),
 | 
					            lrck.map_into(),
 | 
				
			||||||
@ -208,7 +281,7 @@ impl<'d, T: Instance> I2S<'d, T> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    fn new_inner(
 | 
					    fn new_inner(
 | 
				
			||||||
        i2s: impl Peripheral<P = T> + 'd,
 | 
					        i2s: impl Peripheral<P = T> + 'd,
 | 
				
			||||||
        // irq: impl Peripheral<P = T::Interrupt> + 'd,
 | 
					        irq: impl Peripheral<P = T::Interrupt> + 'd,
 | 
				
			||||||
        mck: PeripheralRef<'d, AnyPin>,
 | 
					        mck: PeripheralRef<'d, AnyPin>,
 | 
				
			||||||
        sck: PeripheralRef<'d, AnyPin>,
 | 
					        sck: PeripheralRef<'d, AnyPin>,
 | 
				
			||||||
        lrck: PeripheralRef<'d, AnyPin>,
 | 
					        lrck: PeripheralRef<'d, AnyPin>,
 | 
				
			||||||
@ -216,36 +289,12 @@ impl<'d, T: Instance> I2S<'d, T> {
 | 
				
			|||||||
        sdout: PeripheralRef<'d, AnyPin>,
 | 
					        sdout: PeripheralRef<'d, AnyPin>,
 | 
				
			||||||
        config: Config,
 | 
					        config: Config,
 | 
				
			||||||
    ) -> Self {
 | 
					    ) -> Self {
 | 
				
			||||||
        into_ref!(i2s, /* irq, */ mck, sck, lrck, sdin, sdout);
 | 
					        into_ref!(i2s, irq, mck, sck, lrck, sdin, sdout);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let r = T::regs();
 | 
					        let r = T::regs();
 | 
				
			||||||
 | 
					 | 
				
			||||||
        Self::apply_config(&r.config, &config);
 | 
					        Self::apply_config(&r.config, &config);
 | 
				
			||||||
 | 
					        Self::select_pins(&r.psel, mck, sck, lrck, sdin, sdout);
 | 
				
			||||||
        r.psel.mck.write(|w| {
 | 
					        Self::setup_interrupt(irq, r);
 | 
				
			||||||
            unsafe { w.bits(mck.psel_bits()) };
 | 
					 | 
				
			||||||
            w.connect().connected()
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        r.psel.sck.write(|w| {
 | 
					 | 
				
			||||||
            unsafe { w.bits(sck.psel_bits()) };
 | 
					 | 
				
			||||||
            w.connect().connected()
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        r.psel.lrck.write(|w| {
 | 
					 | 
				
			||||||
            unsafe { w.bits(lrck.psel_bits()) };
 | 
					 | 
				
			||||||
            w.connect().connected()
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        r.psel.sdin.write(|w| {
 | 
					 | 
				
			||||||
            unsafe { w.bits(sdin.psel_bits()) };
 | 
					 | 
				
			||||||
            w.connect().connected()
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        r.psel.sdout.write(|w| {
 | 
					 | 
				
			||||||
            unsafe { w.bits(sdout.psel_bits()) };
 | 
					 | 
				
			||||||
            w.connect().connected()
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        r.enable.write(|w| w.enable().enabled());
 | 
					        r.enable.write(|w| w.enable().enabled());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -322,19 +371,87 @@ impl<'d, T: Instance> I2S<'d, T> {
 | 
				
			|||||||
        self.input.rx(buffer).await
 | 
					        self.input.rx(buffer).await
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn apply_config(c: &CONFIG, config: &Config) {
 | 
					    fn on_interrupt(_: *mut ()) {
 | 
				
			||||||
        // TODO support slave too
 | 
					        let r = T::regs();
 | 
				
			||||||
        c.mcken.write(|w| w.mcken().enabled());
 | 
					        let s = T::state();
 | 
				
			||||||
        c.mckfreq.write(|w| w.mckfreq()._32mdiv16());
 | 
					
 | 
				
			||||||
        c.mode.write(|w| w.mode().master());
 | 
					        if r.events_txptrupd.read().bits() != 0 {
 | 
				
			||||||
 | 
					            s.tx_waker.wake();
 | 
				
			||||||
 | 
					            r.intenclr.write(|w| w.txptrupd().clear());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if r.events_rxptrupd.read().bits() != 0 {
 | 
				
			||||||
 | 
					            s.rx_waker.wake();
 | 
				
			||||||
 | 
					            r.intenclr.write(|w| w.rxptrupd().clear());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn apply_config(c: &CONFIG, config: &Config) {
 | 
				
			||||||
 | 
					        match config.mode {
 | 
				
			||||||
 | 
					            Mode::Master { freq, ratio } => {
 | 
				
			||||||
 | 
					                c.mode.write(|w| w.mode().master());
 | 
				
			||||||
 | 
					                c.mcken.write(|w| w.mcken().enabled());
 | 
				
			||||||
 | 
					                c.mckfreq
 | 
				
			||||||
 | 
					                    .write(|w| unsafe { w.mckfreq().bits(freq.to_register_value()) });
 | 
				
			||||||
 | 
					                c.ratio.write(|w| unsafe { w.ratio().bits(ratio.into()) });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Mode::Slave => {
 | 
				
			||||||
 | 
					                c.mode.write(|w| w.mode().slave());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        c.ratio.write(|w| unsafe { w.ratio().bits(config.ratio.into()) });
 | 
					 | 
				
			||||||
        c.swidth.write(|w| unsafe { w.swidth().bits(config.swidth.into()) });
 | 
					        c.swidth.write(|w| unsafe { w.swidth().bits(config.swidth.into()) });
 | 
				
			||||||
        c.align.write(|w| w.align().bit(config.align.into()));
 | 
					        c.align.write(|w| w.align().bit(config.align.into()));
 | 
				
			||||||
        c.format.write(|w| w.format().bit(config.format.into()));
 | 
					        c.format.write(|w| w.format().bit(config.format.into()));
 | 
				
			||||||
        c.channels
 | 
					        c.channels
 | 
				
			||||||
            .write(|w| unsafe { w.channels().bits(config.channels.into()) });
 | 
					            .write(|w| unsafe { w.channels().bits(config.channels.into()) });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn select_pins(
 | 
				
			||||||
 | 
					        psel: &PSEL,
 | 
				
			||||||
 | 
					        mck: PeripheralRef<'d, AnyPin>,
 | 
				
			||||||
 | 
					        sck: PeripheralRef<'d, AnyPin>,
 | 
				
			||||||
 | 
					        lrck: PeripheralRef<'d, AnyPin>,
 | 
				
			||||||
 | 
					        sdin: PeripheralRef<'d, AnyPin>,
 | 
				
			||||||
 | 
					        sdout: PeripheralRef<'d, AnyPin>,
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        psel.mck.write(|w| {
 | 
				
			||||||
 | 
					            unsafe { w.bits(mck.psel_bits()) };
 | 
				
			||||||
 | 
					            w.connect().connected()
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        psel.sck.write(|w| {
 | 
				
			||||||
 | 
					            unsafe { w.bits(sck.psel_bits()) };
 | 
				
			||||||
 | 
					            w.connect().connected()
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        psel.lrck.write(|w| {
 | 
				
			||||||
 | 
					            unsafe { w.bits(lrck.psel_bits()) };
 | 
				
			||||||
 | 
					            w.connect().connected()
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        psel.sdin.write(|w| {
 | 
				
			||||||
 | 
					            unsafe { w.bits(sdin.psel_bits()) };
 | 
				
			||||||
 | 
					            w.connect().connected()
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        psel.sdout.write(|w| {
 | 
				
			||||||
 | 
					            unsafe { w.bits(sdout.psel_bits()) };
 | 
				
			||||||
 | 
					            w.connect().connected()
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn setup_interrupt(irq: PeripheralRef<'d, T::Interrupt>, r: &RegisterBlock) {
 | 
				
			||||||
 | 
					        irq.set_handler(Self::on_interrupt);
 | 
				
			||||||
 | 
					        irq.set_priority(Priority::P1); // TODO review priorities
 | 
				
			||||||
 | 
					        irq.unpend();
 | 
				
			||||||
 | 
					        irq.enable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        r.intenclr.write(|w| w.rxptrupd().clear());
 | 
				
			||||||
 | 
					        r.intenclr.write(|w| w.txptrupd().clear());
 | 
				
			||||||
 | 
					        r.events_rxptrupd.reset();
 | 
				
			||||||
 | 
					        r.events_txptrupd.reset();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'d, T: Instance> I2sOutput<'d, T> {
 | 
					impl<'d, T: Instance> I2sOutput<'d, T> {
 | 
				
			||||||
@ -360,15 +477,40 @@ impl<'d, T: Instance> I2sOutput<'d, T> {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let r = T::regs();
 | 
					        let r = T::regs();
 | 
				
			||||||
        let _s = T::state();
 | 
					        let s = T::state();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // TODO we can not progress until the last buffer written in TXD.PTR
 | 
					        let drop = OnDrop::new(move || {
 | 
				
			||||||
        // has started the transmission.
 | 
					            trace!("write drop: stopping");
 | 
				
			||||||
        // We can use some sync primitive from `embassy-sync`.
 | 
					
 | 
				
			||||||
 | 
					            r.intenclr.write(|w| w.txptrupd().clear());
 | 
				
			||||||
 | 
					            r.events_txptrupd.reset();
 | 
				
			||||||
 | 
					            r.config.txen.write(|w| w.txen().disabled());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // TX is stopped almost instantly, spinning is fine.
 | 
				
			||||||
 | 
					            while r.events_txptrupd.read().bits() == 0 {}
 | 
				
			||||||
 | 
					            trace!("write drop: stopped");
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
 | 
					        r.txd.ptr.write(|w| unsafe { w.ptr().bits(ptr as u32) });
 | 
				
			||||||
        r.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) });
 | 
					        r.rxtxd.maxcnt.write(|w| unsafe { w.bits(maxcnt) });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        r.intenset.write(|w| w.txptrupd().set());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        compiler_fence(Ordering::SeqCst);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        poll_fn(|cx| {
 | 
				
			||||||
 | 
					            s.tx_waker.register(cx.waker());
 | 
				
			||||||
 | 
					            if r.events_txptrupd.read().bits() != 0 {
 | 
				
			||||||
 | 
					                Poll::Ready(())
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                Poll::Pending
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .await;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        compiler_fence(Ordering::SeqCst);
 | 
				
			||||||
 | 
					        drop.defuse();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -451,23 +593,19 @@ impl Buffer for &[i32] {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub(crate) mod sealed {
 | 
					pub(crate) mod sealed {
 | 
				
			||||||
    use core::sync::atomic::AtomicU8;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    use embassy_sync::waitqueue::AtomicWaker;
 | 
					    use embassy_sync::waitqueue::AtomicWaker;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //use super::*;
 | 
					    //use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub struct State {
 | 
					    pub struct State {
 | 
				
			||||||
        pub input_waker: AtomicWaker,
 | 
					        pub rx_waker: AtomicWaker,
 | 
				
			||||||
        pub output_waker: AtomicWaker,
 | 
					        pub tx_waker: AtomicWaker,
 | 
				
			||||||
        pub buffers_refcount: AtomicU8,
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    impl State {
 | 
					    impl State {
 | 
				
			||||||
        pub const fn new() -> Self {
 | 
					        pub const fn new() -> Self {
 | 
				
			||||||
            Self {
 | 
					            Self {
 | 
				
			||||||
                input_waker: AtomicWaker::new(),
 | 
					                rx_waker: AtomicWaker::new(),
 | 
				
			||||||
                output_waker: AtomicWaker::new(),
 | 
					                tx_waker: AtomicWaker::new(),
 | 
				
			||||||
                buffers_refcount: AtomicU8::new(0),
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -74,7 +74,7 @@ pub mod buffered_uarte;
 | 
				
			|||||||
pub mod gpio;
 | 
					pub mod gpio;
 | 
				
			||||||
#[cfg(feature = "gpiote")]
 | 
					#[cfg(feature = "gpiote")]
 | 
				
			||||||
pub mod gpiote;
 | 
					pub mod gpiote;
 | 
				
			||||||
#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840",))]
 | 
					#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
 | 
				
			||||||
pub mod i2s;
 | 
					pub mod i2s;
 | 
				
			||||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
 | 
					#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
 | 
				
			||||||
pub mod nvmc;
 | 
					pub mod nvmc;
 | 
				
			||||||
 | 
				
			|||||||
@ -4,43 +4,133 @@
 | 
				
			|||||||
#![no_main]
 | 
					#![no_main]
 | 
				
			||||||
#![feature(type_alias_impl_trait)]
 | 
					#![feature(type_alias_impl_trait)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//use defmt::*;
 | 
					use core::f32::consts::PI;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use defmt::{error, info};
 | 
				
			||||||
use embassy_executor::Spawner;
 | 
					use embassy_executor::Spawner;
 | 
				
			||||||
use embassy_nrf::i2s;
 | 
					use embassy_nrf::i2s::{MckFreq, Mode, Ratio, MODE_MASTER_16000, MODE_MASTER_8000};
 | 
				
			||||||
 | 
					use embassy_nrf::{i2s, interrupt};
 | 
				
			||||||
use {defmt_rtt as _, panic_probe as _};
 | 
					use {defmt_rtt as _, panic_probe as _};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[repr(align(4))]
 | 
					#[repr(align(4))]
 | 
				
			||||||
pub struct Aligned<T: ?Sized>(T);
 | 
					pub struct AlignedBuffer<T: ?Sized>(T);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T> AsRef<T> for AlignedBuffer<T> {
 | 
				
			||||||
 | 
					    fn as_ref(&self) -> &T {
 | 
				
			||||||
 | 
					        &self.0
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T> AsMut<T> for AlignedBuffer<T> {
 | 
				
			||||||
 | 
					    fn as_mut(&mut self) -> &mut T {
 | 
				
			||||||
 | 
					        &mut self.0
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[embassy_executor::main]
 | 
					#[embassy_executor::main]
 | 
				
			||||||
async fn main(_spawner: Spawner) {
 | 
					async fn main(_spawner: Spawner) {
 | 
				
			||||||
    let p = embassy_nrf::init(Default::default());
 | 
					    let p = embassy_nrf::init(Default::default());
 | 
				
			||||||
    let config = i2s::Config::default();
 | 
					    let mut config = i2s::Config::default();
 | 
				
			||||||
 | 
					    // config.mode = MODE_MASTER_16000;
 | 
				
			||||||
 | 
					    config.mode = Mode::Master {
 | 
				
			||||||
 | 
					        freq: MckFreq::_32MDiv10,
 | 
				
			||||||
 | 
					        ratio: Ratio::_256x,
 | 
				
			||||||
 | 
					    }; // 12500 Hz
 | 
				
			||||||
 | 
					    let sample_rate = config.mode.sample_rate().expect("I2S Master");
 | 
				
			||||||
 | 
					    let inv_sample_rate = 1.0 / sample_rate as f32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut i2s = i2s::I2S::new(p.I2S, p.P0_28, p.P0_29, p.P0_31, p.P0_11, p.P0_30, config);
 | 
					    info!("Sample rate: {}", sample_rate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut signal_buf: Aligned<[i16; 32]> = Aligned([0i16; 32]);
 | 
					    let irq = interrupt::take!(I2S);
 | 
				
			||||||
    let len = signal_buf.0.len() / 2;
 | 
					    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);
 | 
				
			||||||
    for x in 0..len {
 | 
					
 | 
				
			||||||
        signal_buf.0[2 * x] = triangle_wave(x as i32, len, 2048, 0, 1) as i16;
 | 
					    const BUF_SAMPLES: usize = 250;
 | 
				
			||||||
        signal_buf.0[2 * x + 1] = triangle_wave(x as i32, len, 2048, 0, 1) as i16;
 | 
					    const BUF_SIZE: usize = BUF_SAMPLES * 2;
 | 
				
			||||||
    }
 | 
					    let mut buf = AlignedBuffer([0i16; BUF_SIZE]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut carrier = SineOsc::new();
 | 
				
			||||||
 | 
					    carrier.set_frequency(300.0, inv_sample_rate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut modulator = SineOsc::new();
 | 
				
			||||||
 | 
					    modulator.set_frequency(0.01, inv_sample_rate);
 | 
				
			||||||
 | 
					    modulator.set_amplitude(0.2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    i2s.set_tx_enabled(true);
 | 
					    i2s.set_tx_enabled(true);
 | 
				
			||||||
    i2s.start();
 | 
					    i2s.start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    loop {
 | 
					    loop {
 | 
				
			||||||
        match i2s.tx(signal_buf.0.as_slice()).await {
 | 
					        for sample in buf.as_mut().chunks_mut(2) {
 | 
				
			||||||
            Ok(_) => todo!(),
 | 
					            let signal = carrier.generate();
 | 
				
			||||||
            Err(_) => todo!(),
 | 
					            // let modulation = bipolar_to_unipolar(modulator.generate());
 | 
				
			||||||
        };
 | 
					            // carrier.set_frequency(200.0 + 100.0 * modulation, inv_sample_rate);
 | 
				
			||||||
 | 
					            // carrier.set_amplitude((modulation);
 | 
				
			||||||
 | 
					            let value = (i16::MAX as f32 * signal) as i16;
 | 
				
			||||||
 | 
					            sample[0] = value;
 | 
				
			||||||
 | 
					            sample[1] = value;
 | 
				
			||||||
 | 
					            // info!("{}", signal);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if let Err(err) = i2s.tx(buf.as_ref().as_slice()).await {
 | 
				
			||||||
 | 
					            error!("{}", err);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn triangle_wave(x: i32, length: usize, amplitude: i32, phase: i32, periods: i32) -> i32 {
 | 
					struct SineOsc {
 | 
				
			||||||
    let length = length as i32;
 | 
					    amplitude: f32,
 | 
				
			||||||
    amplitude
 | 
					    modulo: f32,
 | 
				
			||||||
        - ((2 * periods * (x + phase + length / (4 * periods)) * amplitude / length) % (2 * amplitude) - amplitude)
 | 
					    phase_inc: f32,
 | 
				
			||||||
            .abs()
 | 
					}
 | 
				
			||||||
        - amplitude / 2
 | 
					
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user