use crate::stm32::{I2C1, I2C2};
use cast::u8;
use crate::gpio::gpioa::{PA10, PA9};
use crate::gpio::gpiob::{PB6, PB7, PB8, PB9};
#[cfg(any(
feature = "stm32f302",
feature = "stm32f334",
feature = "stm32f303",
feature = "stm32f318",
feature = "stm32f328",
feature = "stm32f358",
feature = "stm32f398",
feature = "stm32f373",
feature = "stm32f378"
))]
use crate::gpio::gpiof::PF6;
use crate::gpio::gpiof::{PF0, PF1};
use crate::gpio::AF4;
use crate::hal::blocking::i2c::{Write, WriteRead};
use crate::rcc::{Clocks, APB1};
use crate::time::Hertz;
#[derive(Debug)]
pub enum Error {
Bus,
Arbitration,
#[doc(hidden)]
_Extensible,
}
pub unsafe trait SclPin<I2C> {}
pub unsafe trait SdaPin<I2C> {}
unsafe impl SclPin<I2C1> for PB6<AF4> {}
unsafe impl SclPin<I2C1> for PB8<AF4> {}
unsafe impl SclPin<I2C2> for PA9<AF4> {}
unsafe impl SclPin<I2C2> for PF1<AF4> {}
#[cfg(any(
feature = "stm32f302",
feature = "stm32f334",
feature = "stm32f303",
feature = "stm32f318",
feature = "stm32f328",
feature = "stm32f358",
feature = "stm32f398",
feature = "stm32f373",
feature = "stm32f378"
))]
unsafe impl SclPin<I2C2> for PF6<AF4> {}
unsafe impl SdaPin<I2C1> for PB7<AF4> {}
unsafe impl SdaPin<I2C1> for PB9<AF4> {}
unsafe impl SdaPin<I2C2> for PA10<AF4> {}
unsafe impl SdaPin<I2C2> for PF0<AF4> {}
pub struct I2c<I2C, PINS> {
i2c: I2C,
pins: PINS,
}
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! hal {
($($I2CX:ident: ($i2cX:ident, $i2cXen:ident, $i2cXrst:ident),)+) => {
$(
impl<SCL, SDA> I2c<$I2CX, (SCL, SDA)> {
pub fn $i2cX<F>(
i2c: $I2CX,
pins: (SCL, SDA),
freq: F,
clocks: Clocks,
apb1: &mut APB1,
) -> Self where
F: Into<Hertz>,
SCL: SclPin<$I2CX>,
SDA: SdaPin<$I2CX>,
{
apb1.enr().modify(|_, w| w.$i2cXen().set_bit());
apb1.rstr().modify(|_, w| w.$i2cXrst().set_bit());
apb1.rstr().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();
i2c.timingr.write(|w| {
w.presc()
.bits(presc)
.scll()
.bits(scll)
.sclh()
.bits(sclh)
.sdadel()
.bits(sdadel)
.scldel()
.bits(scldel)
});
i2c.cr1.write(|w| w.pe().set_bit());
I2c { i2c, pins }
}
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(u16::from(addr << 1))
.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(u16::from(addr << 1))
.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(u16::from(addr << 1))
.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(())
}
}
)+
}
}
#[cfg(any(
feature = "stm32f301",
feature = "stm32f302",
feature = "stm32f303",
feature = "stm32f318",
feature = "stm32f328",
feature = "stm32f358",
feature = "stm32f373",
feature = "stm32f378",
feature = "stm32f398",
))]
hal! {
I2C1: (i2c1, i2c1en, i2c1rst),
I2C2: (i2c2, i2c2en, i2c2rst),
}
#[cfg(feature = "stm32f334")]
hal! {
I2C1: (i2c1, i2c1en, i2c1rst),
}