use core::ops::Deref;
use crate::i2c::{Error, NoAcknowledgeSource, Pins};
use crate::pac::{fmpi2c1, FMPI2C1, RCC};
use crate::rcc::{Enable, Reset};
use fugit::{HertzU32 as Hertz, RateExtU32};
mod hal_02;
mod hal_1;
pub struct FMPI2c<I2C, PINS> {
i2c: I2C,
pins: PINS,
}
pub type FMPI2c1<PINS> = FMPI2c<FMPI2C1, PINS>;
#[derive(Debug, PartialEq)]
pub enum FmpMode {
Standard { frequency: Hertz },
Fast { frequency: Hertz },
FastPlus { frequency: Hertz },
}
impl FmpMode {
pub fn standard(frequency: Hertz) -> Self {
Self::Standard {
frequency: frequency.into(),
}
}
pub fn fast(frequency: Hertz) -> Self {
Self::Fast { frequency }
}
pub fn fast_plus(frequency: Hertz) -> Self {
Self::FastPlus { frequency }
}
pub fn get_frequency(&self) -> Hertz {
match *self {
Self::Standard { frequency } => frequency,
Self::Fast { frequency } => frequency,
Self::FastPlus { frequency } => frequency,
}
}
}
impl From<Hertz> for FmpMode {
fn from(frequency: Hertz) -> Self {
let k100: Hertz = 100.kHz();
let k400: Hertz = 400.kHz();
if frequency <= k100 {
Self::Standard { frequency }
} else if frequency <= k400 {
Self::Fast { frequency }
} else {
Self::FastPlus { frequency }
}
}
}
impl<PINS> FMPI2c<FMPI2C1, PINS>
where
PINS: Pins<FMPI2C1>,
{
pub fn new<M: Into<FmpMode>>(i2c: FMPI2C1, mut pins: PINS, mode: M) -> Self {
unsafe {
let rcc = &(*RCC::ptr());
FMPI2C1::enable(rcc);
FMPI2C1::reset(rcc);
rcc.dckcfgr2.modify(|_, w| w.fmpi2c1sel().hsi());
}
pins.set_alt_mode();
let i2c = FMPI2c { i2c, pins };
i2c.i2c_init(mode);
i2c
}
pub fn release(mut self) -> (FMPI2C1, PINS) {
self.pins.restore_mode();
(self.i2c, self.pins)
}
}
impl<I2C, PINS> FMPI2c<I2C, PINS>
where
I2C: Deref<Target = fmpi2c1::RegisterBlock>,
{
fn i2c_init<M: Into<FmpMode>>(&self, mode: M) {
let mode = mode.into();
use core::cmp;
self.i2c.cr1.modify(|_, w| w.pe().clear_bit());
let presc;
let scldel;
let sdadel;
let sclh;
let scll;
const FREQ: u32 = 16_000_000;
match mode {
FmpMode::Standard { frequency } => {
presc = 3;
scll = cmp::max((((FREQ >> presc) >> 1) / frequency.raw()) - 1, 255) as u8;
sclh = scll - 4;
sdadel = 2;
scldel = 4;
}
FmpMode::Fast { frequency } => {
presc = 1;
scll = cmp::max((((FREQ >> presc) >> 1) / frequency.raw()) - 1, 255) as u8;
sclh = scll - 6;
sdadel = 2;
scldel = 3;
}
FmpMode::FastPlus { frequency } => {
presc = 0;
scll = cmp::max((((FREQ >> presc) >> 1) / frequency.raw()) - 4, 255) as u8;
sclh = scll - 2;
sdadel = 0;
scldel = 2;
}
}
self.i2c.timingr.write(|w| {
w.presc()
.bits(presc)
.scldel()
.bits(scldel)
.sdadel()
.bits(sdadel)
.sclh()
.bits(sclh)
.scll()
.bits(scll)
});
self.i2c.cr1.modify(|_, w| w.pe().set_bit());
}
fn check_and_clear_error_flags(&self, isr: &fmpi2c1::isr::R) -> Result<(), Error> {
if isr.nackf().bit_is_set() {
self.i2c
.icr
.write(|w| w.stopcf().set_bit().nackcf().set_bit());
return Err(Error::NoAcknowledge(NoAcknowledgeSource::Unknown));
}
Ok(())
}
fn end_transaction(&self) -> Result<(), Error> {
self.check_and_clear_error_flags(&self.i2c.isr.read())
.map_err(Error::nack_data)?;
Ok(())
}
fn send_byte(&self, byte: u8) -> Result<(), Error> {
while {
let isr = self.i2c.isr.read();
self.check_and_clear_error_flags(&isr)
.map_err(Error::nack_addr)?;
isr.txis().bit_is_clear()
} {}
self.i2c.txdr.write(|w| unsafe { w.bits(u32::from(byte)) });
self.end_transaction()
}
fn recv_byte(&self) -> Result<u8, Error> {
while {
let isr = self.i2c.isr.read();
self.check_and_clear_error_flags(&isr)
.map_err(Error::nack_data)?;
isr.rxne().bit_is_clear()
} {}
let value = self.i2c.rxdr.read().bits() as u8;
Ok(value)
}
pub fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> {
self.i2c.cr2.modify(|_, w| {
w.sadd()
.bits(u16::from(addr) << 1)
.nbytes()
.bits(buffer.len() as u8)
.rd_wrn()
.set_bit()
});
self.i2c.cr2.modify(|_, w| w.start().set_bit());
self.i2c.cr2.modify(|_, w| w.autoend().set_bit());
for c in buffer.iter_mut() {
*c = self.recv_byte()?;
}
self.end_transaction()
}
pub fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
self.i2c.cr2.modify(|_, w| {
w.sadd()
.bits(u16::from(addr) << 1)
.nbytes()
.bits(bytes.len() as u8)
.rd_wrn()
.clear_bit()
.autoend()
.set_bit()
});
self.i2c.cr2.modify(|_, w| w.start().set_bit());
for c in bytes {
self.send_byte(*c)?;
}
self.end_transaction()
}
pub fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
self.i2c.cr2.modify(|_, w| {
w.sadd()
.bits(u16::from(addr) << 1)
.nbytes()
.bits(bytes.len() as u8)
.rd_wrn()
.clear_bit()
.autoend()
.clear_bit()
});
self.i2c.cr2.modify(|_, w| w.start().set_bit());
while {
let isr = self.i2c.isr.read();
self.check_and_clear_error_flags(&isr)
.map_err(Error::nack_addr)?;
isr.txis().bit_is_clear() && isr.tc().bit_is_clear()
} {}
for c in bytes {
self.send_byte(*c)?;
}
while {
let isr = self.i2c.isr.read();
self.check_and_clear_error_flags(&isr)
.map_err(Error::nack_data)?;
isr.tc().bit_is_clear()
} {}
self.i2c.cr2.modify(|_, w| {
w.sadd()
.bits(u16::from(addr) << 1)
.nbytes()
.bits(buffer.len() as u8)
.rd_wrn()
.set_bit()
});
self.i2c.cr2.modify(|_, w| w.start().set_bit());
self.i2c.cr2.modify(|_, w| w.autoend().set_bit());
for c in buffer.iter_mut() {
*c = self.recv_byte()?;
}
self.end_transaction()
}
}