use core::ops::Deref;
use embedded_hal_02::blocking::i2c::{Read, Write, WriteRead};
use crate::{
gpio::*,
pac,
rcc::{Clocks, Enable, Reset},
time::{kHz, Hertz, KiloHertz},
};
pub struct I2c<I2C: Instance, SCLPIN, SDAPIN> {
i2c: I2C,
pins: (SCLPIN, SDAPIN),
}
pub trait SclPin<I2C> {}
pub trait SdaPin<I2C> {}
macro_rules! i2c_pins {
($($I2C:ident => {
scl => [$($scl:ty),+ $(,)*],
sda => [$($sda:ty),+ $(,)*],
})+) => {
$(
$(
impl SclPin<crate::pac::$I2C> for $scl {}
)+
$(
impl SdaPin<crate::pac::$I2C> for $sda {}
)+
)+
}
}
#[cfg(any(feature = "py32f030", feature = "py32f003", feature = "py32f002a"))]
i2c_pins! {
I2C => {
scl => [
gpioa::PA3<Alternate<AF12>>,
gpioa::PA8<Alternate<AF12>>,
gpioa::PA9<Alternate<AF6>>,
gpioa::PA10<Alternate<AF12>>,
gpioa::PA11<Alternate<AF6>>,
gpiob::PB6<Alternate<AF6>>,
gpiob::PB8<Alternate<AF6>>,
gpiof::PF1<Alternate<AF12>>
],
sda => [
gpioa::PA2<Alternate<AF12>>,
gpioa::PA7<Alternate<AF12>>,
gpioa::PA9<Alternate<AF12>>,
gpioa::PA10<Alternate<AF6>>,
gpioa::PA12<Alternate<AF6>>,
gpiob::PB7<Alternate<AF6>>,
gpiob::PB8<Alternate<AF12>>,
gpiof::PF0<Alternate<AF12>>
],
}
}
#[cfg(feature = "py32f002b")]
i2c_pins! {
I2C => {
scl => [
gpioa::PA2<Alternate<AF6>>,
gpiob::PB3<Alternate<AF6>>,
],
sda => [
gpiob::PB4<Alternate<AF6>>,
gpiob::PB6<Alternate<AF6>>,
],
}
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
OVERRUN,
NACK,
BUS,
PEC,
}
#[allow(dead_code)]
type I2cRegisterBlock = crate::pac::i2c::RegisterBlock;
pub trait Instance: Deref<Target = I2cRegisterBlock> + crate::Sealed + Enable + Reset {
#[doc(hidden)]
fn ptr() -> *const I2cRegisterBlock;
}
macro_rules! i2c {
($($I2C:ident: $i2c:ident,)+) => {
$(
use crate::pac::$I2C;
impl Instance for $I2C {
fn ptr() -> *const I2cRegisterBlock {
<$I2C>::ptr()
}
}
impl<SCLPIN, SDAPIN> I2c<$I2C, SCLPIN, SDAPIN> {
pub fn $i2c(i2c: $I2C, pins: (SCLPIN, SDAPIN), speed: KiloHertz, clocks: &Clocks) -> Self
where
SCLPIN: SclPin<$I2C>,
SDAPIN: SdaPin<$I2C>,
{
let rcc = unsafe { &(*pac::RCC::ptr()) };
$I2C::enable(rcc);
$I2C::reset(rcc);
I2c { i2c, pins }.i2c_init(clocks.pclk(), speed)
}
}
)+
}
}
i2c! {
I2C: i2c,
}
impl<I2C, SCLPIN, SDAPIN> I2c<I2C, SCLPIN, SDAPIN>
where
I2C: Instance,
{
fn i2c_init(self, freq: Hertz, speed: KiloHertz) -> Self {
self.i2c.cr1.modify(|_, w| w.pe().clear_bit());
let f = freq.raw() / 1_000_000;
self.i2c
.cr2
.write(|w| unsafe { w.freq().bits(f.clamp(4, 48) as u8) });
let (f_s, ccr) = if speed <= kHz(100) {
(false, freq.raw() / (speed.raw() * 2))
} else {
(
true,
if self.i2c.ccr.read().duty().bit_is_set() {
freq.raw() / (speed.raw() * 25)
} else {
freq.raw() / (speed.raw() * 3)
},
)
};
self.i2c
.ccr
.modify(|_, w| unsafe { w.f_s().bit(f_s).ccr().bits(ccr.clamp(4, 4095) as u16) });
self.i2c.cr1.modify(|_, w| w.pe().set_bit());
self
}
pub fn release(self) -> (I2C, (SCLPIN, SDAPIN)) {
(self.i2c, self.pins)
}
fn check_and_clear_error_flags(&self, sr: &crate::pac::i2c::sr1::R) -> Result<(), Error> {
if sr.pecerr().bit_is_set() {
self.i2c.sr1.write(|w| w.pecerr().clear_bit());
return Err(Error::PEC);
}
if sr.ovr().bit_is_set() {
self.i2c.sr1.write(|w| w.ovr().clear_bit());
return Err(Error::OVERRUN);
}
if sr.arlo().bit_is_set() | sr.berr().bit_is_set() {
self.i2c
.sr1
.write(|w| w.arlo().clear_bit().berr().clear_bit());
return Err(Error::BUS);
}
if sr.af().bit_is_set() {
self.i2c.sr1.write(|w| w.af().clear_bit());
return Err(Error::NACK);
}
Ok(())
}
fn send_byte(&self, byte: u8) -> Result<(), Error> {
loop {
let sr = self.i2c.sr1.read();
self.check_and_clear_error_flags(&sr)?;
if sr.txe().bit_is_set() {
break;
}
}
self.i2c.dr.write(|w| unsafe { w.bits(u32::from(byte)) });
self.check_and_clear_error_flags(&self.i2c.sr1.read())?;
Ok(())
}
fn recv_byte(&self) -> Result<u8, Error> {
loop {
let sr = self.i2c.sr1.read();
self.check_and_clear_error_flags(&sr)?;
if sr.rxne().bit_is_set() {
break;
}
}
let value = self.i2c.dr.read().bits() as u8;
Ok(value)
}
}
impl<I2C, SCLPIN, SDAPIN> WriteRead for I2c<I2C, SCLPIN, SDAPIN>
where
I2C: Instance,
{
type Error = Error;
fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
self.i2c.oar1.modify(|_, w| w.add().bits(addr));
self.i2c.cr1.modify(|_, w| w.start().set_bit());
loop {
let sr = self.i2c.sr1.read();
self.check_and_clear_error_flags(&sr)?;
if sr.txe().bit_is_set() {
break;
}
}
for c in bytes {
self.send_byte(*c)?;
}
loop {
let sr = self.i2c.sr1.read();
self.check_and_clear_error_flags(&sr)?;
if sr.btf().bit_is_set() {
break;
}
}
self.i2c.oar1.modify(|_, w| w.add().bits(addr));
self.i2c.cr1.modify(|_, w| w.start().set_bit());
for c in buffer.iter_mut() {
*c = self.recv_byte()?;
}
self.check_and_clear_error_flags(&self.i2c.sr1.read())?;
Ok(())
}
}
impl<I2C, SCLPIN, SDAPIN> Read for I2c<I2C, SCLPIN, SDAPIN>
where
I2C: Instance,
{
type Error = Error;
fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Error> {
self.i2c.oar1.modify(|_, w| w.add().bits(addr));
self.i2c.cr1.modify(|_, w| w.start().set_bit());
for c in buffer.iter_mut() {
*c = self.recv_byte()?;
}
self.check_and_clear_error_flags(&self.i2c.sr1.read())?;
Ok(())
}
}
impl<I2C, SCLPIN, SDAPIN> Write for I2c<I2C, SCLPIN, SDAPIN>
where
I2C: Instance,
{
type Error = Error;
fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Error> {
self.i2c.oar1.modify(|_, w| w.add().bits(addr));
self.i2c.cr1.modify(|_, w| w.start().set_bit());
for c in bytes {
self.send_byte(*c)?;
}
self.check_and_clear_error_flags(&self.i2c.sr1.read())?;
Ok(())
}
}