use core::marker::PhantomData;
use crate::pac::spi1::RegisterBlock;
use crate::pac::spi1::{i2spr, sr};
use crate::I2sPeripheral;
pub use crate::marker::{self, *};
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Channel {
Left,
Right,
}
pub struct Status<MS, TR, STD> {
value: sr::R,
_ms: PhantomData<MS>,
_tr: PhantomData<TR>,
_std: PhantomData<STD>,
}
impl<MS, TR, STD> Status<MS, TR, STD> {
pub fn bsy(&self) -> bool {
self.value.bsy().bit()
}
}
impl<MS, TR, STD> Status<MS, TR, STD>
where
STD: marker::ChannelFlag,
{
pub fn chside(&self) -> Channel {
match self.value.chside().bit() {
false => Channel::Left,
true => Channel::Right,
}
}
}
impl<TR, STD> Status<Slave, TR, 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 TransmitOrReceive {
Transmit,
Receive,
}
#[derive(Debug, Clone, Copy)]
enum Frequency {
Prescaler(bool, u8),
Request(u32),
Require(u32),
}
pub(crate) mod private {
#[derive(Debug, Clone, Copy)]
pub enum I2sStandard {
Philips,
Msb,
Lsb,
PcmShortSync,
PcmLongSync,
}
}
pub(crate) use private::I2sStandard;
#[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, TR, 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<TR>,
_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,
data_format: DataFormat,
) {
let coef = _coef(mclk, 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);
}
fn _set_require_frequency(
w: &mut i2spr::W,
i2s_clock: u32,
request_freq: u32,
mclk: bool,
data_format: DataFormat,
) {
let coef = _coef(mclk, 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, data_format: DataFormat) -> u32 {
if mclk {
return 256;
}
if let DataFormat::Data16Channel16 = data_format {
32
} else {
64
}
}
impl<MS, TR, STD> I2sDriverConfig<MS, TR, STD> {
pub fn i2s_driver<I: I2sPeripheral>(self, i2s_peripheral: I) -> I2sDriver<I, MS, TR, STD> {
let driver = I2sDriver::<I, MS, TR, 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.data_format,
),
Frequency::Require(freq) => _set_require_frequency(
w,
driver.i2s_peripheral.i2s_freq(),
freq,
self.master_clock,
self.data_format,
),
}
w
});
driver
}
}
impl Default for I2sDriverConfig<Slave, Transmit, Philips> {
fn default() -> Self {
Self::new_slave()
}
}
impl<MS, TR, STD> I2sDriverConfig<MS, TR, 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 standard<NEW_STD>(self, _standard: NEW_STD) -> I2sDriverConfig<MS, TR, NEW_STD>
where
NEW_STD: marker::I2sStandard,
{
I2sDriverConfig::<MS, TR, 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, TR, STD> {
let Self {
transmit_or_receive,
standard,
clock_polarity,
data_format,
..
} = self;
I2sDriverConfig::<Slave, TR, 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, TR, STD> {
let Self {
transmit_or_receive,
standard,
clock_polarity,
data_format,
master_clock,
frequency,
..
} = self;
I2sDriverConfig::<Master, TR, STD> {
slave_or_master: SlaveOrMaster::Master,
transmit_or_receive,
standard,
clock_polarity,
data_format,
master_clock,
frequency,
_ms: PhantomData,
_tr: PhantomData,
_std: PhantomData,
}
}
}
impl<TR, STD> I2sDriverConfig<Master, TR, 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, TR, STD> {
i2s_peripheral: I,
_ms: PhantomData<MS>,
_tr: PhantomData<TR>,
_std: PhantomData<STD>,
}
impl<I, MS, TR, STD> I2sDriver<I, MS, TR, STD>
where
I: I2sPeripheral,
{
fn registers(&self) -> &RegisterBlock {
unsafe { &*(I::REGISTERS as *const RegisterBlock) }
}
}
impl<I, MS, TR, STD> I2sDriver<I, MS, TR, STD>
where
I: I2sPeripheral,
{
pub fn new(i2s_peripheral: I, config: I2sDriverConfig<MS, TR, STD>) -> Self {
config.i2s_driver(i2s_peripheral)
}
pub fn release(self) -> I {
let registers = self.registers();
registers.cr1.reset();
registers.cr2.reset();
registers.i2scfgr.reset();
registers.i2spr.reset();
self.i2s_peripheral
}
#[allow(non_camel_case_types)]
pub fn reconfigure<NEW_MS, NEW_TR, NEW_STD>(
self,
config: I2sDriverConfig<NEW_MS, NEW_TR, NEW_STD>,
) -> I2sDriver<I, NEW_MS, NEW_TR, NEW_STD> {
let i2s_peripheral = self.i2s_peripheral;
config.i2s_driver(i2s_peripheral)
}
}
impl<I, MS, TR, STD> I2sDriver<I, MS, TR, STD>
where
I: I2sPeripheral,
{
pub fn i2s_peripheral(&self) -> &I {
&self.i2s_peripheral
}
pub fn i2s_peripheral_mut(&mut self) -> &mut I {
&mut self.i2s_peripheral
}
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 ws_is_high(&self) -> bool {
self.i2s_peripheral.ws_is_high()
}
pub fn ws_is_low(&self) -> bool {
self.i2s_peripheral.ws_is_low()
}
}
impl<I, MS, TR, STD> I2sDriver<I, MS, TR, STD>
where
I: I2sPeripheral,
{
pub fn status(&mut self) -> Status<MS, TR, STD> {
Status::<MS, TR, STD> {
value: self.registers().sr.read(),
_ms: PhantomData,
_tr: PhantomData,
_std: PhantomData,
}
}
}
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, TR, STD> I2sDriver<I, Slave, TR, STD>
where
I: I2sPeripheral,
{
pub fn set_error_interrupt(&mut self, enabled: bool) {
self.registers().cr2.modify(|_, w| w.errie().bit(enabled))
}
}
impl<I, TR, STD> I2sDriver<I, Master, TR, STD>
where
I: I2sPeripheral,
{
pub fn sample_rate(&self) -> u32 {
let i2spr = self.registers().i2spr.read();
let mckoe = i2spr.mckoe().bit();
let odd = i2spr.odd().bit();
let div = i2spr.i2sdiv().bits();
let i2s_freq = self.i2s_peripheral.i2s_freq();
if mckoe {
i2s_freq / (256 * ((2 * div as u32) + odd as u32))
} else {
match self.registers().i2scfgr.read().chlen().bit() {
false => i2s_freq / ((16 * 2) * ((2 * div as u32) + odd as u32)),
true => i2s_freq / ((32 * 2) * ((2 * div as u32) + odd as u32)),
}
}
}
}
#[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);
}
}
}