use core::marker::PhantomData;
use stm32f429::{SPI1, SPI2, SPI3};
use gpio::gpioa::PA4;
use gpio::gpiob::{PB5, PB9, PB10, PB12, PB13, PB14, PB15};
use gpio::gpioc::{PC2, PC3, PC6, PC7};
use gpio::{AF5, AF6};
use rcc::{APB1, APB2, Clocks};
use dma::*;
pub unsafe trait SdPin<I2S> {}
unsafe impl SdPin<SPI3> for PB5<AF6> {}
unsafe impl SdPin<SPI2> for PB15<AF5> {}
unsafe impl SdPin<SPI2> for PC3<AF5> {}
pub unsafe trait WsPin<SPI1> {}
unsafe impl WsPin<SPI3> for PA4<AF6> {}
unsafe impl WsPin<SPI2> for PB9<AF5> {}
unsafe impl WsPin<SPI2> for PB12<AF5> {}
pub unsafe trait CkPin<I2S> {}
unsafe impl CkPin<SPI2> for PB10<AF5> {}
unsafe impl CkPin<SPI2> for PB13<AF5> {}
pub unsafe trait ExtSdPin<I2S> {}
unsafe impl ExtSdPin<SPI2> for PB14<AF6> {}
unsafe impl ExtSdPin<SPI2> for PC2<AF6> {}
pub unsafe trait MckPin<I2S> {}
unsafe impl MckPin<SPI2> for PC6<AF5> {}
unsafe impl MckPin<SPI3> for PC7<AF6> {}
pub struct DmaRx;
pub struct DmaTx;
pub unsafe trait I2sDmaStream<STREAM, CHANNEL, DIRECTION> {}
unsafe impl I2sDmaStream<SPI3, C0, DmaRx> for dma1::S0 {}
unsafe impl I2sDmaStream<SPI3, C0, DmaRx> for dma1::S2 {}
unsafe impl I2sDmaStream<SPI2, C0, DmaRx> for dma1::S3 {}
unsafe impl I2sDmaStream<SPI2, C0, DmaTx> for dma1::S4 {}
unsafe impl I2sDmaStream<SPI3, C0, DmaTx> for dma1::S5 {}
unsafe impl I2sDmaStream<SPI3, C0, DmaTx> for dma1::S7 {}
unsafe impl I2sDmaStream<SPI1, C3, DmaRx> for dma2::S0 {}
unsafe impl I2sDmaStream<SPI1, C3, DmaRx> for dma2::S2 {}
unsafe impl I2sDmaStream<SPI1, C3, DmaTx> for dma2::S3 {}
unsafe impl I2sDmaStream<SPI1, C3, DmaTx> for dma2::S5 {}
pub struct SlaveRole {}
pub struct MasterRole {}
pub enum I2sStandard {
Philips = 0b00,
MsbJustified = 0b01,
LsbJustified = 0b10,
Pcm = 0b11,
}
#[allow(unused)]
pub struct I2s<SPI, SD, CK, WS> {
spi: SPI,
sd: SD,
ck: CK,
ws: WS,
}
#[allow(unused)]
pub struct I2sOutput<Role, Data, SPI, SD, CK, WS> {
role: PhantomData<Role>,
data: PhantomData<Data>,
spi: SPI,
sd: SD,
ck: CK,
ws: WS,
}
pub trait I2sData {
fn datlen() -> u8;
fn for_u16<F: Fn(u16)>(&self, f: F);
}
impl I2sData for u16 {
fn datlen() -> u8 {
0b00
}
#[inline]
fn for_u16<F: Fn(u16)>(&self, f: F) {
f(*self);
}
}
impl I2sData for u32 {
fn datlen() -> u8 {
0b10
}
#[inline]
fn for_u16<F: Fn(u16)>(&self, f: F) {
f((*self >> 16) as u16);
f(*self as u16);
}
}
macro_rules! hal {
($($SPIX:ident: ($spiX:ident, $APBX:ident, $spiXen:ident, $spiXrst:ident),)+) => {
$(
/// I2S interface on SPI pins
impl<SD, CK, WS> I2s<$SPIX, SD, CK, WS> {
/// Initialize I2S interface
pub fn $spiX(
spi: $SPIX,
sd: SD,
ck: CK,
ws: WS,
_clocks: Clocks,
apb: &mut $APBX,
) -> Self where
SD: SdPin<$SPIX>,
CK: CkPin<$SPIX>,
WS: WsPin<$SPIX>,
{
apb.enr().modify(|_, w| w.$spiXen().set_bit());
apb.rstr().modify(|_, w| w.$spiXrst().set_bit());
apb.rstr().modify(|_, w| w.$spiXrst().clear_bit());
I2s { spi, sd, ck, ws }
}
pub fn into_slave_output<S: I2sData>(self, standard: I2sStandard) -> I2sOutput<SlaveRole, S, $SPIX, SD, CK, WS> {
self.spi.i2scfgr.modify(|_, w| {
unsafe {
w.i2smod().set_bit()
.i2scfg().bits(0b00)
.i2sstd().bits(standard as u8)
.datlen().bits(S::datlen())
.chlen().clear_bit()
}
});
self.spi.i2scfgr.modify(|_, w| w.i2se().set_bit());
I2sOutput {
role: PhantomData,
data: PhantomData,
spi: self.spi,
sd: self.sd,
ck: self.ck,
ws: self.ws,
}
}
}
impl<'s, Role, S: I2sData + Sized + 's, SD, CK, WS> I2sOutput<Role, S, $SPIX, SD, CK, WS> {
pub fn into_i2s(self) -> I2s<$SPIX, SD, CK, WS> {
while self.spi.sr.read().bsy().bit() ||
! self.spi.sr.read().txe().bit() {}
self.spi.i2scfgr.modify(|_, w| w.i2se().clear_bit());
I2s {
spi: self.spi,
sd: self.sd,
ck: self.ck,
ws: self.ws,
}
}
pub fn write(&mut self, data: S) {
data.for_u16(|word| {
while ! self.spi.sr.read().txe().bit() {}
self.spi.dr.write(|w| unsafe { w.dr().bits(word) });
});
}
}
)+
}
}
hal! {
SPI1: (spi1, APB2, spi1en, spi1rst),
SPI2: (spi2, APB1, spi2en, spi2rst),
SPI3: (spi3, APB1, spi3en, spi3rst),
}