use cast::u8;
use crate::pac::{I2C1, I2C2, RCC};
use crate::gpio::{AltFn, PinMode, PullType};
use crate::gpio::{HighSpeed, PushPull, AF4};
use crate::gpio::{PA10, PA14, PA15, PA9};
use crate::gpio::{PB6, PB7, PB8, PB9};
use crate::gpio::{PF0, PF1, PF6};
use crate::rcc::Clocks;
use crate::time::Hertz;
use hal::blocking::i2c::{Read, Write, WriteRead};
#[derive(Debug)]
pub enum Error {
Bus,
Arbitration,
#[doc(hidden)]
_Extensible,
}
pub struct I2c<I2C, PINS> {
i2c: I2C,
pins: PINS,
}
pub trait I2cExt<I2C, ISCL, ISDA, SCL, SDA> {
fn i2c<F>(self,
pins: (ISCL, ISDA),
freq: F,
clocks: Clocks)
-> I2c<I2C, (SCL, SDA)>
where F: Into<Hertz<u32>>;
}
macro_rules! busy_wait {
($i2c:expr, $flag:ident) => {
loop {
let isr = $i2c.isr.read();
if isr.berr().bit_is_set() {
return Err(Error::Bus);
} else if isr.arlo().bit_is_set() {
return Err(Error::Arbitration);
} else if isr.$flag().bit_is_set() {
break;
} else {
}
}
};
}
macro_rules! i2c {
($I2CX:ident,
$i2cXen:ident,
$i2cXrst:ident,
$afn:ident,
$speed:ident,
scl: [$($scl: ident, )+],
sda: $sda: tt
) => {
i2c!{
$I2CX,
$i2cXen,
$i2cXrst,
$afn,
$speed,
[$(
($scl, $sda),
)+]
}
};
($I2CX:ident,
$i2cXen:ident,
$i2cXrst:ident,
$afn:ident,
$speed:ident,
[$(($scl: ident, [$($sda:ident, )+]),)+]
) => {
$(
$(
impl<PT: PullType, PM: PinMode>
I2cExt<$I2CX,
$scl<PT, PM>,
$sda<PT, PM>,
$scl<PT, AltFn<$afn, PushPull, $speed>>,
$sda<PT, AltFn<$afn, PushPull, $speed>>> for $I2CX
{
fn i2c<F>(
self,
pins: ($scl<PT, PM>, $sda<PT, PM>),
freq: F,
clocks: Clocks)
-> I2c<$I2CX,
($scl<PT, AltFn<$afn, PushPull, $speed>>,
$sda<PT, AltFn<$afn, PushPull, $speed>>)> where
F: Into<Hertz<u32>>,
{
let outpins = (pins.0.alternating($afn).output_speed($speed),
pins.1.alternating($afn).output_speed($speed));
let apbenr = unsafe { &(*RCC::ptr()).apb1enr };
let apbrstr = unsafe { &(*RCC::ptr()).apb1rstr };
apbenr.modify(|_, w| w.$i2cXen().enabled());
apbrstr.modify(|_, w| w.$i2cXrst().set_bit());
apbrstr.modify(|_, w| w.$i2cXrst().clear_bit());
let freq = freq.into().0;
assert!(freq <= 1_000_000);
let i2cclk = clocks.pclk1().0;
let ratio = i2cclk / freq - 4;
let (presc, scll, sclh, sdadel, scldel) = if freq >= 100_000 {
let presc = ratio / 387;
let sclh = ((ratio / (presc + 1)) - 3) / 3;
let scll = 2 * (sclh + 1) - 1;
let (sdadel, scldel) = if freq > 400_000 {
let sdadel = 0;
let scldel = i2cclk / 4_000_000 / (presc + 1) - 1;
(sdadel, scldel)
} else {
let sdadel = i2cclk / 8_000_000 / (presc + 1);
let scldel = i2cclk / 2_000_000 / (presc + 1) - 1;
(sdadel, scldel)
};
(presc, scll, sclh, sdadel, scldel)
} else {
let presc = ratio / 514;
let sclh = ((ratio / (presc + 1)) - 2) / 2;
let scll = sclh;
let sdadel = i2cclk / 2_000_000 / (presc + 1);
let scldel = i2cclk / 800_000 / (presc + 1) - 1;
(presc, scll, sclh, sdadel, scldel)
};
let presc = u8(presc).unwrap();
assert!(presc < 16);
let scldel = u8(scldel).unwrap();
assert!(scldel < 16);
let sdadel = u8(sdadel).unwrap();
assert!(sdadel < 16);
let sclh = u8(sclh).unwrap();
let scll = u8(scll).unwrap();
self.timingr.write(|w|
w.presc()
.bits(presc)
.scll()
.bits(scll)
.sclh()
.bits(sclh)
.sdadel()
.bits(sdadel)
.scldel()
.bits(scldel)
);
self.cr1.write(|w| w.pe().set_bit());
I2c { i2c: self, pins: outpins }
}
}
)+
)+
impl<SCL, SDA> I2c<$I2CX, (SCL, SDA)> {
pub fn free(self) -> ($I2CX, (SCL, SDA)) {
(self.i2c, self.pins)
}
}
impl<PINS> Write for I2c<$I2CX, PINS> {
type Error = Error;
fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
assert!(bytes.len() < 256 && bytes.len() > 0);
self.i2c.cr2.write(|w| {
w.sadd()
.bits((addr << 1) as u16)
.rd_wrn()
.clear_bit()
.nbytes()
.bits(bytes.len() as u8)
.start()
.set_bit()
.autoend()
.set_bit()
});
for byte in bytes {
busy_wait!(self.i2c, txis);
self.i2c.txdr.write(|w| w.txdata().bits(*byte));
}
Ok(())
}
}
impl<PINS> WriteRead for I2c<$I2CX, PINS> {
type Error = Error;
fn write_read(
&mut self,
addr: u8,
bytes: &[u8],
buffer: &mut [u8],
) -> Result<(), Error> {
assert!(bytes.len() < 256 && bytes.len() > 0);
assert!(buffer.len() < 256 && buffer.len() > 0);
self.i2c.cr2.write(|w| {
w.sadd()
.bits((addr << 1) as u16)
.rd_wrn()
.clear_bit()
.nbytes()
.bits(bytes.len() as u8)
.start()
.set_bit()
.autoend()
.clear_bit()
});
for byte in bytes {
busy_wait!(self.i2c, txis);
self.i2c.txdr.write(|w| w.txdata().bits(*byte));
}
busy_wait!(self.i2c, tc);
self.i2c.cr2.write(|w| {
w.sadd()
.bits((addr << 1) as u16)
.rd_wrn()
.set_bit()
.nbytes()
.bits(buffer.len() as u8)
.start()
.set_bit()
.autoend()
.set_bit()
});
for byte in buffer {
busy_wait!(self.i2c, rxne);
*byte = self.i2c.rxdr.read().rxdata().bits();
}
Ok(())
}
}
impl<PINS> Read for I2c<$I2CX, PINS> {
type Error = Error;
fn read(
&mut self,
addr: u8,
buffer: &mut [u8],
) -> Result<(), Error> {
assert!(buffer.len() < 256 && buffer.len() > 0);
self.i2c.cr2.write(|w| {
w.sadd()
.bits((addr << 1) as u16)
.rd_wrn()
.set_bit()
.nbytes()
.bits(buffer.len() as u8)
.start()
.set_bit()
.autoend()
.set_bit()
});
for byte in buffer {
busy_wait!(self.i2c, rxne);
*byte = self.i2c.rxdr.read().rxdata().bits();
}
Ok(())
}
}
}
}
i2c!(I2C1, i2c1en, i2c1rst, AF4, HighSpeed,
scl: [PB6, PB8, PA15, ],
sda: [PB7, PB9, PA14, ]);
i2c!(I2C2, i2c2en, i2c2rst, AF4, HighSpeed,
scl: [PA9, PF1, PF6, ],
sda: [PA10, PF0, ]);