use core::marker::PhantomData;
use crate::pac::spi1::RegisterBlock;
use crate::pac::spi1::{i2spr, sr};
use crate::{DualI2sPeripheral, I2sPeripheral, WsPin};
pub use crate::marker::{self, *};
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Channel {
Left,
Right,
}
pub struct Status<MS, DIR, STD> {
value: sr::R,
_ms: PhantomData<MS>,
_tr: PhantomData<DIR>,
_std: PhantomData<STD>,
}
impl<MS, DIR, STD> Status<MS, DIR, STD> {
pub fn bsy(&self) -> bool {
self.value.bsy().bit()
}
}
impl<MS, DIR, STD> Status<MS, DIR, STD>
where
STD: marker::ChannelFlag,
{
pub fn chside(&self) -> Channel {
match self.value.chside().bit() {
false => Channel::Left,
true => Channel::Right,
}
}
}
impl<DIR, STD> Status<Slave, DIR, STD> {
pub fn fre(&self) -> bool {
self.value.fre().bit()
}
}
impl<MS, STD> Status<MS, Receive, STD> {
pub fn ovr(&self) -> bool {
self.value.ovr().bit()
}
pub fn rxne(&self) -> bool {
self.value.rxne().bit()
}
}
impl<MS, STD> Status<MS, Transmit, STD> {
pub fn txe(&self) -> bool {
self.value.txe().bit()
}
}
impl<STD> Status<Slave, Transmit, STD> {
pub fn udr(&self) -> bool {
self.value.udr().bit()
}
}
#[derive(Debug, Clone, Copy)]
enum SlaveOrMaster {
Slave,
Master,
}
#[derive(Debug, Clone, Copy)]
enum Frequency {
Prescaler(bool, u8),
Request(u32),
Require(u32),
}
pub(crate) mod private {
#[derive(Debug, Clone, Copy)]
pub enum TransmitOrReceive {
Transmit,
Receive,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum I2sStandard {
Philips,
Msb,
Lsb,
PcmShortSync,
PcmLongSync,
}
use super::RegisterBlock;
pub trait I2sCoreRegisters {
fn registers(&self) -> &RegisterBlock;
}
}
pub(crate) use private::{I2sCoreRegisters, I2sStandard, TransmitOrReceive};
#[derive(Debug, Clone, Copy)]
pub enum ClockPolarity {
IdleLow,
IdleHigh,
}
#[derive(Debug, Clone, Copy)]
pub enum DataFormat {
Data16Channel16,
Data16Channel32,
Data24Channel32,
Data32Channel32,
}
impl Default for DataFormat {
fn default() -> Self {
DataFormat::Data16Channel16
}
}
#[derive(Debug, Clone, Copy)]
pub struct I2sDriverConfig<MS, DIR, STD> {
slave_or_master: SlaveOrMaster,
transmit_or_receive: TransmitOrReceive,
standard: I2sStandard,
clock_polarity: ClockPolarity,
data_format: DataFormat,
master_clock: bool,
frequency: Frequency,
_ms: PhantomData<MS>,
_tr: PhantomData<DIR>,
_std: PhantomData<STD>,
}
impl I2sDriverConfig<Slave, Transmit, Philips> {
pub fn new_slave() -> Self {
Self {
slave_or_master: SlaveOrMaster::Slave,
transmit_or_receive: TransmitOrReceive::Transmit,
standard: I2sStandard::Philips,
clock_polarity: ClockPolarity::IdleLow,
data_format: Default::default(),
master_clock: false,
frequency: Frequency::Prescaler(false, 0b10),
_ms: PhantomData,
_tr: PhantomData,
_std: PhantomData,
}
}
}
impl I2sDriverConfig<Master, Transmit, Philips> {
pub fn new_master() -> Self {
Self {
slave_or_master: SlaveOrMaster::Master,
transmit_or_receive: TransmitOrReceive::Transmit,
standard: I2sStandard::Philips,
clock_polarity: ClockPolarity::IdleLow,
data_format: Default::default(),
master_clock: false,
frequency: Frequency::Prescaler(false, 0b10),
_ms: PhantomData,
_tr: PhantomData,
_std: PhantomData,
}
}
}
fn div_round(n: u32, d: u32) -> u32 {
(n + (d >> 1)) / d
}
fn _set_prescaler(w: &mut i2spr::W, odd: bool, div: u8) {
w.odd().bit(odd);
unsafe { w.i2sdiv().bits(div) };
}
fn _set_request_frequency(
w: &mut i2spr::W,
i2s_clock: u32,
request_freq: u32,
mclk: bool,
std: I2sStandard,
data_format: DataFormat,
) {
let coef = _coef(mclk, std, data_format);
let division = div_round(i2s_clock, coef * request_freq);
let (odd, div) = if division < 4 {
(false, 2)
} else if division > 511 {
(true, 255)
} else {
((division & 1) == 1, (division >> 1) as u8)
};
_set_prescaler(w, odd, div);
}
#[allow(clippy::manual_range_contains)]
fn _set_require_frequency(
w: &mut i2spr::W,
i2s_clock: u32,
request_freq: u32,
mclk: bool,
std: I2sStandard,
data_format: DataFormat,
) {
let coef = _coef(mclk, std, data_format);
let division = i2s_clock / (coef * request_freq);
let rem = i2s_clock % (coef * request_freq);
if rem == 0 && division >= 4 && division <= 511 {
let odd = (division & 1) == 1;
let div = (division >> 1) as u8;
_set_prescaler(w, odd, div);
} else {
panic!("Cannot reach exactly the required frequency")
};
}
fn _coef(mclk: bool, std: I2sStandard, data_format: DataFormat) -> u32 {
use I2sStandard::*;
let nb_chan = match std {
Philips | Msb | Lsb => 2,
PcmShortSync | PcmLongSync => 1,
};
if mclk {
return 128 * nb_chan;
}
if let DataFormat::Data16Channel16 = data_format {
16 * nb_chan
} else {
32 * nb_chan
}
}
fn _sample_rate(registers: &RegisterBlock, i2s_freq: u32) -> u32 {
let i2scfgr = registers.i2scfgr.read();
let i2spr = registers.i2spr.read();
let nb_chan = if i2scfgr.i2sstd().is_pcm() { 1 } else { 2 };
let channel_length = if i2scfgr.chlen().bit() { 32 } else { 16 };
let mckoe = i2spr.mckoe().bit();
let odd = i2spr.odd().bit();
let div = i2spr.i2sdiv().bits();
if mckoe {
i2s_freq / (128 * nb_chan * ((2 * div as u32) + odd as u32))
} else {
i2s_freq / ((channel_length * nb_chan) * ((2 * div as u32) + odd as u32))
}
}
impl<MS, DIR, STD> I2sDriverConfig<MS, DIR, STD> {
pub fn i2s_driver<I: I2sPeripheral>(self, i2s_peripheral: I) -> I2sDriver<I, MS, DIR, STD> {
let driver = I2sDriver::<I, MS, DIR, STD> {
i2s_peripheral,
_ms: PhantomData,
_tr: PhantomData,
_std: PhantomData,
};
driver.registers().cr1.reset(); driver.registers().cr2.reset(); driver.registers().i2scfgr.write(|w| {
w.i2smod().i2smode();
match (self.slave_or_master, self.transmit_or_receive) {
(SlaveOrMaster::Slave, TransmitOrReceive::Transmit) => w.i2scfg().slave_tx(),
(SlaveOrMaster::Slave, TransmitOrReceive::Receive) => w.i2scfg().slave_rx(),
(SlaveOrMaster::Master, TransmitOrReceive::Transmit) => w.i2scfg().master_tx(),
(SlaveOrMaster::Master, TransmitOrReceive::Receive) => w.i2scfg().master_rx(),
};
match self.standard {
I2sStandard::Philips => w.i2sstd().philips(),
I2sStandard::Msb => w.i2sstd().msb(),
I2sStandard::Lsb => w.i2sstd().lsb(),
I2sStandard::PcmShortSync => w.i2sstd().pcm().pcmsync().short(),
I2sStandard::PcmLongSync => w.i2sstd().pcm().pcmsync().long(),
};
match self.data_format {
DataFormat::Data16Channel16 => w.datlen().sixteen_bit().chlen().sixteen_bit(),
DataFormat::Data16Channel32 => w.datlen().sixteen_bit().chlen().thirty_two_bit(),
DataFormat::Data24Channel32 => {
w.datlen().twenty_four_bit().chlen().thirty_two_bit()
}
DataFormat::Data32Channel32 => w.datlen().thirty_two_bit().chlen().thirty_two_bit(),
};
w
});
driver.registers().i2spr.write(|w| {
w.mckoe().bit(self.master_clock);
match self.frequency {
Frequency::Prescaler(odd, div) => _set_prescaler(w, odd, div),
Frequency::Request(freq) => _set_request_frequency(
w,
driver.i2s_peripheral.i2s_freq(),
freq,
self.master_clock,
self.standard,
self.data_format,
),
Frequency::Require(freq) => _set_require_frequency(
w,
driver.i2s_peripheral.i2s_freq(),
freq,
self.master_clock,
self.standard,
self.data_format,
),
}
w
});
driver
}
}
impl Default for I2sDriverConfig<Slave, Transmit, Philips> {
fn default() -> Self {
Self::new_slave()
}
}
impl<MS, DIR, STD> I2sDriverConfig<MS, DIR, STD> {
pub fn transmit(self) -> I2sDriverConfig<MS, Transmit, STD> {
I2sDriverConfig::<MS, Transmit, STD> {
slave_or_master: self.slave_or_master,
transmit_or_receive: TransmitOrReceive::Transmit,
standard: self.standard,
clock_polarity: self.clock_polarity,
data_format: self.data_format,
master_clock: self.master_clock,
frequency: self.frequency,
_ms: PhantomData,
_tr: PhantomData,
_std: PhantomData,
}
}
pub fn receive(self) -> I2sDriverConfig<MS, Receive, STD> {
I2sDriverConfig::<MS, Receive, STD> {
slave_or_master: self.slave_or_master,
transmit_or_receive: TransmitOrReceive::Receive,
standard: self.standard,
clock_polarity: self.clock_polarity,
data_format: self.data_format,
master_clock: self.master_clock,
frequency: self.frequency,
_ms: PhantomData,
_tr: PhantomData,
_std: PhantomData,
}
}
#[allow(non_camel_case_types)]
pub fn direction<NEW_DIR>(self, _dir: NEW_DIR) -> I2sDriverConfig<MS, NEW_DIR, STD>
where
NEW_DIR: marker::Direction,
{
I2sDriverConfig::<MS, NEW_DIR, STD> {
slave_or_master: self.slave_or_master,
transmit_or_receive: NEW_DIR::VALUE,
standard: self.standard,
clock_polarity: self.clock_polarity,
data_format: self.data_format,
master_clock: self.master_clock,
frequency: self.frequency,
_ms: PhantomData,
_tr: PhantomData,
_std: PhantomData,
}
}
#[allow(non_camel_case_types)]
pub fn standard<NEW_STD>(self, _standard: NEW_STD) -> I2sDriverConfig<MS, DIR, NEW_STD>
where
NEW_STD: marker::I2sStandard,
{
I2sDriverConfig::<MS, DIR, NEW_STD> {
slave_or_master: self.slave_or_master,
transmit_or_receive: self.transmit_or_receive,
standard: NEW_STD::VALUE,
clock_polarity: self.clock_polarity,
data_format: self.data_format,
master_clock: self.master_clock,
frequency: self.frequency,
_ms: PhantomData,
_tr: PhantomData,
_std: PhantomData,
}
}
pub fn clock_polarity(mut self, polarity: ClockPolarity) -> Self {
self.clock_polarity = polarity;
self
}
pub fn data_format(mut self, format: DataFormat) -> Self {
self.data_format = format;
self
}
pub fn to_slave(self) -> I2sDriverConfig<Slave, DIR, STD> {
let Self {
transmit_or_receive,
standard,
clock_polarity,
data_format,
..
} = self;
I2sDriverConfig::<Slave, DIR, STD> {
slave_or_master: SlaveOrMaster::Slave,
transmit_or_receive,
standard,
clock_polarity,
data_format,
master_clock: false,
frequency: Frequency::Prescaler(false, 0b10),
_ms: PhantomData,
_tr: PhantomData,
_std: PhantomData,
}
}
pub fn to_master(self) -> I2sDriverConfig<Master, DIR, STD> {
let Self {
transmit_or_receive,
standard,
clock_polarity,
data_format,
master_clock,
frequency,
..
} = self;
I2sDriverConfig::<Master, DIR, STD> {
slave_or_master: SlaveOrMaster::Master,
transmit_or_receive,
standard,
clock_polarity,
data_format,
master_clock,
frequency,
_ms: PhantomData,
_tr: PhantomData,
_std: PhantomData,
}
}
}
impl<DIR, STD> I2sDriverConfig<Master, DIR, STD> {
pub fn master_clock(mut self, enable: bool) -> Self {
self.master_clock = enable;
self
}
pub fn prescaler(mut self, odd: bool, div: u8) -> Self {
#[allow(clippy::manual_range_contains)]
if div < 2 {
panic!("div is less than 2, forbidden value")
}
self.frequency = Frequency::Prescaler(odd, div);
self
}
pub fn request_frequency(mut self, freq: u32) -> Self {
self.frequency = Frequency::Request(freq);
self
}
pub fn require_frequency(mut self, freq: u32) -> Self {
self.frequency = Frequency::Require(freq);
self
}
}
pub struct I2sDriver<I, MS, DIR, STD> {
i2s_peripheral: I,
_ms: PhantomData<MS>,
_tr: PhantomData<DIR>,
_std: PhantomData<STD>,
}
impl<I, MS, DIR, STD> I2sDriver<I, MS, DIR, STD>
where
I: I2sPeripheral,
{
fn registers(&self) -> &RegisterBlock {
unsafe { &*(I::REGISTERS as *const RegisterBlock) }
}
}
impl<I, MS, DIR, STD> I2sDriver<I, MS, DIR, STD>
where
I: I2sPeripheral,
{
pub fn new(i2s_peripheral: I, config: I2sDriverConfig<MS, DIR, STD>) -> Self {
config.i2s_driver(i2s_peripheral)
}
pub fn release(mut self) -> I {
self.i2s_peripheral.rcc_reset();
self.i2s_peripheral
}
#[allow(non_camel_case_types)]
pub fn reconfigure<NEW_MS, NEW_DIR, NEW_STD>(
self,
config: I2sDriverConfig<NEW_MS, NEW_DIR, NEW_STD>,
) -> I2sDriver<I, NEW_MS, NEW_DIR, NEW_STD> {
let i2s_peripheral = self.i2s_peripheral;
config.i2s_driver(i2s_peripheral)
}
}
impl<I, MS, DIR, STD> I2sDriver<I, MS, DIR, STD>
where
I: I2sPeripheral,
{
pub fn enable(&mut self) {
self.registers().i2scfgr.modify(|_, w| w.i2se().enabled());
}
pub fn disable(&mut self) {
self.registers().i2scfgr.modify(|_, w| w.i2se().disabled());
}
#[deprecated(
since = "0.4.0",
note = "may removed in future, use `ws_pin().is_high()` instead"
)]
pub fn ws_is_high(&self) -> bool {
self.i2s_peripheral.ws_pin().is_high()
}
#[deprecated(
since = "0.4.0",
note = "may removed in future, use `ws_pin().is_low()` instead"
)]
pub fn ws_is_low(&self) -> bool {
self.i2s_peripheral.ws_pin().is_low()
}
pub fn ws_pin(&self) -> &I::WsPin {
self.i2s_peripheral.ws_pin()
}
pub fn ws_pin_mut(&mut self) -> &mut I::WsPin {
self.i2s_peripheral.ws_pin_mut()
}
pub fn data_register_address(&self) -> u32 {
&(self.registers().dr) as *const _ as u32
}
pub fn status(&mut self) -> Status<MS, DIR, STD> {
Status::<MS, DIR, STD> {
value: self.registers().sr.read(),
_ms: PhantomData,
_tr: PhantomData,
_std: PhantomData,
}
}
}
impl<I, DIR, STD> I2sDriver<I, Master, DIR, STD>
where
I: I2sPeripheral,
{
pub fn reset_clocks(&mut self) {
let registers = self.registers();
let cr2 = registers.cr2.read().bits();
let i2scfgr = registers.i2scfgr.read().bits();
let i2spr = registers.i2spr.read().bits();
self.i2s_peripheral.rcc_reset();
let registers = self.registers();
registers.cr2.write(|w| unsafe { w.bits(cr2) });
registers.i2spr.write(|w| unsafe { w.bits(i2spr) });
registers.i2scfgr.write(|w| unsafe { w.bits(i2scfgr) });
}
pub fn sample_rate(&self) -> u32 {
_sample_rate(self.registers(), self.i2s_peripheral.i2s_freq())
}
}
impl<I, MS, STD> I2sDriver<I, MS, Transmit, STD>
where
I: I2sPeripheral,
{
pub fn write_data_register(&mut self, value: u16) {
self.registers().dr.write(|w| w.dr().bits(value));
}
pub fn set_tx_interrupt(&mut self, enabled: bool) {
self.registers().cr2.modify(|_, w| w.txeie().bit(enabled))
}
pub fn set_tx_dma(&mut self, enabled: bool) {
self.registers().cr2.modify(|_, w| w.txdmaen().bit(enabled))
}
}
impl<I, MS, STD> I2sDriver<I, MS, Receive, STD>
where
I: I2sPeripheral,
{
pub fn read_data_register(&mut self) -> u16 {
self.registers().dr.read().dr().bits()
}
pub fn set_rx_interrupt(&mut self, enabled: bool) {
self.registers().cr2.modify(|_, w| w.rxneie().bit(enabled))
}
pub fn set_rx_dma(&mut self, enabled: bool) {
self.registers().cr2.modify(|_, w| w.rxdmaen().bit(enabled))
}
}
impl<I, STD> I2sDriver<I, Master, Receive, STD>
where
I: I2sPeripheral,
{
pub fn set_error_interrupt(&mut self, enabled: bool) {
self.registers().cr2.modify(|_, w| w.errie().bit(enabled))
}
}
impl<I, DIR, STD> I2sDriver<I, Slave, DIR, STD>
where
I: I2sPeripheral,
{
pub fn set_error_interrupt(&mut self, enabled: bool) {
self.registers().cr2.modify(|_, w| w.errie().bit(enabled))
}
}
#[derive(Debug, Clone, Copy)]
#[allow(non_camel_case_types)]
pub struct DualI2sDriverConfig<MS, MAIN_DIR, EXT_DIR, STD> {
slave_or_master: SlaveOrMaster,
main_dir: TransmitOrReceive,
ext_dir: TransmitOrReceive,
standard: I2sStandard,
clock_polarity: ClockPolarity,
data_format: DataFormat,
master_clock: bool,
frequency: Frequency,
_ms: PhantomData<MS>,
_main_dir: PhantomData<MAIN_DIR>,
_ext_dir: PhantomData<EXT_DIR>,
_std: PhantomData<STD>,
}
impl DualI2sDriverConfig<Slave, Transmit, Transmit, Philips> {
pub fn new_slave() -> Self {
Self {
slave_or_master: SlaveOrMaster::Slave,
main_dir: TransmitOrReceive::Transmit,
ext_dir: TransmitOrReceive::Transmit,
standard: I2sStandard::Philips,
clock_polarity: ClockPolarity::IdleLow,
data_format: Default::default(),
master_clock: false,
frequency: Frequency::Prescaler(false, 0b10),
_ms: PhantomData,
_main_dir: PhantomData,
_ext_dir: PhantomData,
_std: PhantomData,
}
}
}
impl DualI2sDriverConfig<Master, Transmit, Transmit, Philips> {
pub fn new_master() -> Self {
Self {
slave_or_master: SlaveOrMaster::Master,
main_dir: TransmitOrReceive::Transmit,
ext_dir: TransmitOrReceive::Transmit,
standard: I2sStandard::Philips,
clock_polarity: ClockPolarity::IdleLow,
data_format: Default::default(),
master_clock: false,
frequency: Frequency::Prescaler(false, 0b10),
_ms: PhantomData,
_main_dir: PhantomData,
_ext_dir: PhantomData,
_std: PhantomData,
}
}
}
#[allow(non_camel_case_types)]
impl<MS, MAIN_DIR, EXT_DIR, STD> DualI2sDriverConfig<MS, MAIN_DIR, EXT_DIR, STD> {
pub fn dual_i2s_driver<I: DualI2sPeripheral>(
self,
dual_i2s_peripheral: I,
) -> DualI2sDriver<I, MS, MAIN_DIR, EXT_DIR, STD> {
let driver = DualI2sDriver::<I, MS, MAIN_DIR, EXT_DIR, STD> {
dual_i2s_peripheral,
main: I2sCore::new(),
ext: I2sCore::new(),
};
driver.main.registers().cr1.reset(); driver.main.registers().cr2.reset(); driver.main.registers().i2scfgr.write(|w| {
w.i2smod().i2smode();
match (self.slave_or_master, self.main_dir) {
(SlaveOrMaster::Slave, TransmitOrReceive::Transmit) => w.i2scfg().slave_tx(),
(SlaveOrMaster::Slave, TransmitOrReceive::Receive) => w.i2scfg().slave_rx(),
(SlaveOrMaster::Master, TransmitOrReceive::Transmit) => w.i2scfg().master_tx(),
(SlaveOrMaster::Master, TransmitOrReceive::Receive) => w.i2scfg().master_rx(),
};
match self.standard {
I2sStandard::Philips => w.i2sstd().philips(),
I2sStandard::Msb => w.i2sstd().msb(),
I2sStandard::Lsb => w.i2sstd().lsb(),
I2sStandard::PcmShortSync => w.i2sstd().pcm().pcmsync().short(),
I2sStandard::PcmLongSync => w.i2sstd().pcm().pcmsync().long(),
};
match self.data_format {
DataFormat::Data16Channel16 => w.datlen().sixteen_bit().chlen().sixteen_bit(),
DataFormat::Data16Channel32 => w.datlen().sixteen_bit().chlen().thirty_two_bit(),
DataFormat::Data24Channel32 => {
w.datlen().twenty_four_bit().chlen().thirty_two_bit()
}
DataFormat::Data32Channel32 => w.datlen().thirty_two_bit().chlen().thirty_two_bit(),
};
w
});
driver.main.registers().i2spr.write(|w| {
w.mckoe().bit(self.master_clock);
match self.frequency {
Frequency::Prescaler(odd, div) => _set_prescaler(w, odd, div),
Frequency::Request(freq) => _set_request_frequency(
w,
driver.dual_i2s_peripheral.i2s_freq(),
freq,
self.master_clock,
self.standard,
self.data_format,
),
Frequency::Require(freq) => _set_require_frequency(
w,
driver.dual_i2s_peripheral.i2s_freq(),
freq,
self.master_clock,
self.standard,
self.data_format,
),
}
w
});
driver.ext.registers().cr1.reset(); driver.ext.registers().cr2.reset(); driver.ext.registers().i2scfgr.write(|w| {
w.i2smod().i2smode();
match (self.slave_or_master, self.ext_dir) {
(_, TransmitOrReceive::Transmit) => w.i2scfg().slave_tx(),
(_, TransmitOrReceive::Receive) => w.i2scfg().slave_rx(),
};
match self.standard {
I2sStandard::Philips => w.i2sstd().philips(),
I2sStandard::Msb => w.i2sstd().msb(),
I2sStandard::Lsb => w.i2sstd().lsb(),
I2sStandard::PcmShortSync => w.i2sstd().pcm().pcmsync().short(),
I2sStandard::PcmLongSync => w.i2sstd().pcm().pcmsync().long(),
};
match self.data_format {
DataFormat::Data16Channel16 => w.datlen().sixteen_bit().chlen().sixteen_bit(),
DataFormat::Data16Channel32 => w.datlen().sixteen_bit().chlen().thirty_two_bit(),
DataFormat::Data24Channel32 => {
w.datlen().twenty_four_bit().chlen().thirty_two_bit()
}
DataFormat::Data32Channel32 => w.datlen().thirty_two_bit().chlen().thirty_two_bit(),
};
w
});
driver.ext.registers().i2spr.write(|w| {
w.mckoe().bit(self.master_clock);
match self.frequency {
Frequency::Prescaler(odd, div) => _set_prescaler(w, odd, div),
Frequency::Request(freq) => _set_request_frequency(
w,
driver.dual_i2s_peripheral.i2s_freq(),
freq,
self.master_clock,
self.standard,
self.data_format,
),
Frequency::Require(freq) => _set_require_frequency(
w,
driver.dual_i2s_peripheral.i2s_freq(),
freq,
self.master_clock,
self.standard,
self.data_format,
),
}
w
});
driver
}
}
impl Default for DualI2sDriverConfig<Slave, Transmit, Transmit, Philips> {
fn default() -> Self {
Self::new_slave()
}
}
#[allow(non_camel_case_types)]
impl<MS, MAIN_DIR, EXT_DIR, STD> DualI2sDriverConfig<MS, MAIN_DIR, EXT_DIR, STD> {
#[allow(non_camel_case_types)]
pub fn direction<NEW_MAIN_DIR, NEW_EXT_DIR>(
self,
_main: NEW_MAIN_DIR,
_ext: NEW_EXT_DIR,
) -> DualI2sDriverConfig<MS, NEW_MAIN_DIR, NEW_EXT_DIR, STD>
where
NEW_MAIN_DIR: marker::Direction,
NEW_EXT_DIR: marker::Direction,
{
DualI2sDriverConfig::<MS, NEW_MAIN_DIR, NEW_EXT_DIR, STD> {
slave_or_master: self.slave_or_master,
main_dir: NEW_MAIN_DIR::VALUE,
ext_dir: NEW_EXT_DIR::VALUE,
standard: self.standard,
clock_polarity: self.clock_polarity,
data_format: self.data_format,
master_clock: self.master_clock,
frequency: self.frequency,
_ms: PhantomData,
_main_dir: PhantomData,
_ext_dir: PhantomData,
_std: PhantomData,
}
}
#[allow(non_camel_case_types)]
pub fn standard<NEW_STD>(
self,
_standard: NEW_STD,
) -> DualI2sDriverConfig<MS, MAIN_DIR, EXT_DIR, NEW_STD>
where
NEW_STD: marker::I2sStandard,
{
DualI2sDriverConfig::<MS, MAIN_DIR, EXT_DIR, NEW_STD> {
slave_or_master: self.slave_or_master,
main_dir: self.main_dir,
ext_dir: self.ext_dir,
standard: NEW_STD::VALUE,
clock_polarity: self.clock_polarity,
data_format: self.data_format,
master_clock: self.master_clock,
frequency: self.frequency,
_ms: PhantomData,
_main_dir: PhantomData,
_ext_dir: PhantomData,
_std: PhantomData,
}
}
pub fn clock_polarity(mut self, polarity: ClockPolarity) -> Self {
self.clock_polarity = polarity;
self
}
pub fn data_format(mut self, format: DataFormat) -> Self {
self.data_format = format;
self
}
pub fn to_slave(self) -> DualI2sDriverConfig<Slave, MAIN_DIR, EXT_DIR, STD> {
let Self {
main_dir,
ext_dir,
standard,
clock_polarity,
data_format,
..
} = self;
DualI2sDriverConfig::<Slave, MAIN_DIR, EXT_DIR, STD> {
slave_or_master: SlaveOrMaster::Slave,
main_dir,
ext_dir,
standard,
clock_polarity,
data_format,
master_clock: false,
frequency: Frequency::Prescaler(false, 0b10),
_ms: PhantomData,
_main_dir: PhantomData,
_ext_dir: PhantomData,
_std: PhantomData,
}
}
pub fn to_master(self) -> DualI2sDriverConfig<Master, MAIN_DIR, EXT_DIR, STD> {
let Self {
main_dir,
ext_dir,
standard,
clock_polarity,
data_format,
master_clock,
frequency,
..
} = self;
DualI2sDriverConfig::<Master, MAIN_DIR, EXT_DIR, STD> {
slave_or_master: SlaveOrMaster::Master,
main_dir,
ext_dir,
standard,
clock_polarity,
data_format,
master_clock,
frequency,
_ms: PhantomData,
_main_dir: PhantomData,
_ext_dir: PhantomData,
_std: PhantomData,
}
}
}
#[allow(non_camel_case_types)]
impl<MAIN_DIR, EXT_DIR, STD> DualI2sDriverConfig<Master, MAIN_DIR, EXT_DIR, STD> {
pub fn master_clock(mut self, enable: bool) -> Self {
self.master_clock = enable;
self
}
pub fn prescaler(mut self, odd: bool, div: u8) -> Self {
#[allow(clippy::manual_range_contains)]
if div < 2 {
panic!("div is less than 2, forbidden value")
}
self.frequency = Frequency::Prescaler(odd, div);
self
}
pub fn request_frequency(mut self, freq: u32) -> Self {
self.frequency = Frequency::Request(freq);
self
}
pub fn require_frequency(mut self, freq: u32) -> Self {
self.frequency = Frequency::Require(freq);
self
}
}
pub struct I2sCore<I, PART, MS, DIR, STD> {
_dual_i2s_peripheral: PhantomData<I>,
_part: PhantomData<PART>,
_ms: PhantomData<MS>,
_dir: PhantomData<DIR>,
_std: PhantomData<STD>,
}
impl<I, PART, MS, DIR, STD> I2sCore<I, PART, MS, DIR, STD> {
fn new() -> Self {
Self {
_dual_i2s_peripheral: PhantomData,
_part: PhantomData,
_ms: PhantomData,
_dir: PhantomData,
_std: PhantomData,
}
}
}
impl<I: DualI2sPeripheral, MS, DIR, STD> I2sCoreRegisters for I2sCore<I, Main, MS, DIR, STD> {
fn registers(&self) -> &RegisterBlock {
unsafe { &*(I::MAIN_REGISTERS as *const RegisterBlock) }
}
}
impl<I: DualI2sPeripheral, MS, DIR, STD> I2sCoreRegisters for I2sCore<I, Ext, MS, DIR, STD> {
fn registers(&self) -> &RegisterBlock {
unsafe { &*(I::EXT_REGISTERS as *const RegisterBlock) }
}
}
impl<I: DualI2sPeripheral, PART, MS, DIR, STD> I2sCore<I, PART, MS, DIR, STD>
where
Self: I2sCoreRegisters,
{
pub fn enable(&mut self) {
self.registers().i2scfgr.modify(|_, w| w.i2se().enabled());
}
pub fn disable(&mut self) {
self.registers().i2scfgr.modify(|_, w| w.i2se().disabled());
}
pub fn data_register_address(&self) -> u32 {
&(self.registers().dr) as *const _ as u32
}
pub fn status(&mut self) -> Status<MS, DIR, STD> {
Status::<MS, DIR, STD> {
value: self.registers().sr.read(),
_ms: PhantomData,
_tr: PhantomData,
_std: PhantomData,
}
}
}
impl<I, PART, MS, STD> I2sCore<I, PART, MS, Transmit, STD>
where
I: DualI2sPeripheral,
Self: I2sCoreRegisters,
{
pub fn write_data_register(&mut self, value: u16) {
self.registers().dr.write(|w| w.dr().bits(value));
}
pub fn set_tx_interrupt(&mut self, enabled: bool) {
self.registers().cr2.modify(|_, w| w.txeie().bit(enabled))
}
pub fn set_tx_dma(&mut self, enabled: bool) {
self.registers().cr2.modify(|_, w| w.txdmaen().bit(enabled))
}
}
impl<I, PART, MS, STD> I2sCore<I, PART, MS, Receive, STD>
where
I: DualI2sPeripheral,
Self: I2sCoreRegisters,
{
pub fn read_data_register(&mut self) -> u16 {
self.registers().dr.read().dr().bits()
}
pub fn set_rx_interrupt(&mut self, enabled: bool) {
self.registers().cr2.modify(|_, w| w.rxneie().bit(enabled))
}
pub fn set_rx_dma(&mut self, enabled: bool) {
self.registers().cr2.modify(|_, w| w.rxdmaen().bit(enabled))
}
}
impl<I, STD> I2sCore<I, Main, Master, Receive, STD>
where
I: DualI2sPeripheral,
Self: I2sCoreRegisters,
{
pub fn set_error_interrupt(&mut self, enabled: bool) {
self.registers().cr2.modify(|_, w| w.errie().bit(enabled))
}
}
impl<I, PART, DIR, STD> I2sCore<I, PART, Slave, DIR, STD>
where
I: DualI2sPeripheral,
Self: I2sCoreRegisters,
{
pub fn set_error_interrupt(&mut self, enabled: bool) {
self.registers().cr2.modify(|_, w| w.errie().bit(enabled))
}
}
#[allow(non_camel_case_types)]
pub struct DualI2sDriver<I, MS, MAIN_DIR, EXT_DIR, STD> {
dual_i2s_peripheral: I,
main: I2sCore<I, Main, MS, MAIN_DIR, STD>,
ext: I2sCore<I, Ext, Slave, EXT_DIR, STD>,
}
#[allow(non_camel_case_types)]
impl<I, MS, MAIN_DIR, EXT_DIR, STD> DualI2sDriver<I, MS, MAIN_DIR, EXT_DIR, STD>
where
I: DualI2sPeripheral,
{
pub fn new(
dual_i2s_peripheral: I,
config: DualI2sDriverConfig<MS, MAIN_DIR, EXT_DIR, STD>,
) -> Self {
config.dual_i2s_driver(dual_i2s_peripheral)
}
pub fn release(mut self) -> I {
self.dual_i2s_peripheral.rcc_reset();
self.dual_i2s_peripheral
}
#[allow(non_camel_case_types)]
pub fn reconfigure<NEW_MS, NEW_MAIN_DIR, NEW_EXT_DIR, NEW_STD>(
self,
config: DualI2sDriverConfig<NEW_MS, NEW_MAIN_DIR, NEW_EXT_DIR, NEW_STD>,
) -> DualI2sDriver<I, NEW_MS, NEW_MAIN_DIR, NEW_EXT_DIR, NEW_STD> {
let i2s_peripheral = self.dual_i2s_peripheral;
config.dual_i2s_driver(i2s_peripheral)
}
}
#[allow(non_camel_case_types)]
impl<I, MS, MAIN_DIR, EXT_DIR, STD> DualI2sDriver<I, MS, MAIN_DIR, EXT_DIR, STD>
where
I: DualI2sPeripheral,
{
pub fn main(&mut self) -> &mut I2sCore<I, Main, MS, MAIN_DIR, STD> {
&mut self.main
}
pub fn ext(&mut self) -> &mut I2sCore<I, Ext, Slave, EXT_DIR, STD> {
&mut self.ext
}
pub fn ws_pin(&self) -> &I::WsPin {
self.dual_i2s_peripheral.ws_pin()
}
pub fn ws_pin_mut(&mut self) -> &mut I::WsPin {
self.dual_i2s_peripheral.ws_pin_mut()
}
}
#[allow(non_camel_case_types)]
impl<I, MAIN_DIR, EXT_DIR, STD> DualI2sDriver<I, Master, MAIN_DIR, EXT_DIR, STD>
where
I: DualI2sPeripheral,
{
pub fn reset_clocks(&mut self) {
let main_registers = self.main.registers();
let main_cr2 = main_registers.cr2.read().bits();
let main_i2scfgr = main_registers.i2scfgr.read().bits();
let main_i2spr = main_registers.i2spr.read().bits();
let ext_registers = self.ext.registers();
let ext_cr2 = ext_registers.cr2.read().bits();
let ext_i2scfgr = ext_registers.i2scfgr.read().bits();
let ext_i2spr = ext_registers.i2spr.read().bits();
self.dual_i2s_peripheral.rcc_reset();
let ext_registers = self.ext.registers();
ext_registers.cr2.write(|w| unsafe { w.bits(ext_cr2) });
ext_registers.i2spr.write(|w| unsafe { w.bits(ext_i2spr) });
ext_registers
.i2scfgr
.write(|w| unsafe { w.bits(ext_i2scfgr) });
let main_registers = self.main.registers();
main_registers.cr2.write(|w| unsafe { w.bits(main_cr2) });
main_registers
.i2spr
.write(|w| unsafe { w.bits(main_i2spr) });
main_registers
.i2scfgr
.write(|w| unsafe { w.bits(main_i2scfgr) });
}
pub fn sample_rate(&self) -> u32 {
_sample_rate(self.main.registers(), self.dual_i2s_peripheral.i2s_freq())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_div_round() {
let fracs = [(1, 2), (2, 2), (1, 3), (2, 3), (2, 4), (3, 5), (9, 2)];
for (n, d) in fracs {
let res = div_round(n, d);
let check = f32::round((n as f32) / (d as f32)) as u32;
assert_eq!(res, check);
}
}
}