Skip to content

Commit

Permalink
i2c nack type
Browse files Browse the repository at this point in the history
  • Loading branch information
burrbull committed Dec 30, 2021
1 parent 1f94ebb commit f5451d3
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 30 deletions.
27 changes: 13 additions & 14 deletions src/fmpi2c.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use core::ops::Deref;

use crate::gpio::{Const, OpenDrain, PinA, SetAlternate};
use crate::i2c::{Error, Scl, Sda};
use crate::i2c::{Error, Pins};
use crate::pac::{fmpi2c1, FMPI2C1, RCC};
use crate::rcc::{Enable, Reset};
use crate::time::{Hertz, U32Ext};
Expand Down Expand Up @@ -66,12 +65,11 @@ where
}
}

impl<SCL, SDA, const SCLA: u8, const SDAA: u8> FMPI2c<FMPI2C1, (SCL, SDA)>
impl<PINS> FMPI2c<FMPI2C1, PINS>
where
SCL: PinA<Scl, FMPI2C1, A = Const<SCLA>> + SetAlternate<OpenDrain, SCLA>,
SDA: PinA<Sda, FMPI2C1, A = Const<SDAA>> + SetAlternate<OpenDrain, SDAA>,
PINS: Pins<FMPI2C1>,
{
pub fn new<M: Into<FmpMode>>(i2c: FMPI2C1, mut pins: (SCL, SDA), mode: M) -> Self {
pub fn new<M: Into<FmpMode>>(i2c: FMPI2C1, mut pins: PINS, mode: M) -> Self {
unsafe {
// NOTE(unsafe) this reference will only be used for atomic writes with no side effects.
let rcc = &(*RCC::ptr());
Expand All @@ -83,17 +81,15 @@ where
rcc.dckcfgr2.modify(|_, w| w.fmpi2c1sel().hsi());
}

pins.0.set_alt_mode();
pins.1.set_alt_mode();
pins.set_alt_mode();

let i2c = FMPI2c { i2c, pins };
i2c.i2c_init(mode);
i2c
}

pub fn release(mut self) -> (FMPI2C1, (SCL, SDA)) {
self.pins.0.restore_mode();
self.pins.1.restore_mode();
pub fn release(mut self) -> (FMPI2C1, PINS) {
self.pins.restore_mode();

(self.i2c, self.pins)
}
Expand Down Expand Up @@ -180,21 +176,24 @@ where
// Wait until we're ready for sending
while {
let isr = self.i2c.isr.read();
self.check_and_clear_error_flags(&isr)?;
self.check_and_clear_error_flags(&isr)
.map_err(Error::nack_addr)?;
isr.txis().bit_is_clear()
} {}

// Push out a byte of data
self.i2c.txdr.write(|w| unsafe { w.bits(u32::from(byte)) });

self.check_and_clear_error_flags(&self.i2c.isr.read())?;
self.check_and_clear_error_flags(&self.i2c.isr.read())
.map_err(Error::nack_data)?;
Ok(())
}

fn recv_byte(&self) -> Result<u8, Error> {
while {
let isr = self.i2c.isr.read();
self.check_and_clear_error_flags(&isr)?;
self.check_and_clear_error_flags(&isr)
.map_err(Error::nack_data)?;
isr.rxne().bit_is_clear()
} {}

Expand Down
15 changes: 10 additions & 5 deletions src/fmpi2c/hal_02.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ mod blocking {
// Wait until the transmit buffer is empty and there hasn't been any error condition
while {
let isr = self.i2c.isr.read();
self.check_and_clear_error_flags(&isr)?;
self.check_and_clear_error_flags(&isr)
.map_err(Error::nack_addr)?;
isr.txis().bit_is_clear() && isr.tc().bit_is_clear()
} {}

Expand All @@ -40,7 +41,8 @@ mod blocking {
// Wait until data was sent
while {
let isr = self.i2c.isr.read();
self.check_and_clear_error_flags(&isr)?;
self.check_and_clear_error_flags(&isr)
.map_err(Error::nack_data)?;
isr.tc().bit_is_clear()
} {}

Expand All @@ -66,7 +68,8 @@ mod blocking {
}

// Check and clear flags if they somehow ended up set
self.check_and_clear_error_flags(&self.i2c.isr.read())?;
self.check_and_clear_error_flags(&self.i2c.isr.read())
.map_err(Error::nack_data)?;

Ok(())
}
Expand Down Expand Up @@ -101,7 +104,8 @@ mod blocking {
}

// Check and clear flags if they somehow ended up set
self.check_and_clear_error_flags(&self.i2c.isr.read())?;
self.check_and_clear_error_flags(&self.i2c.isr.read())
.map_err(Error::nack_data)?;

Ok(())
}
Expand Down Expand Up @@ -135,7 +139,8 @@ mod blocking {
}

// Check and clear flags if they somehow ended up set
self.check_and_clear_error_flags(&self.i2c.isr.read())?;
self.check_and_clear_error_flags(&self.i2c.isr.read())
.map_err(Error::nack_data)?;

Ok(())
}
Expand Down
15 changes: 10 additions & 5 deletions src/fmpi2c/hal_1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ mod blocking {
// Wait until the transmit buffer is empty and there hasn't been any error condition
while {
let isr = self.i2c.isr.read();
self.check_and_clear_error_flags(&isr)?;
self.check_and_clear_error_flags(&isr)
.map_err(Error::nack_addr)?;
isr.txis().bit_is_clear() && isr.tc().bit_is_clear()
} {}

Expand All @@ -40,7 +41,8 @@ mod blocking {
// Wait until data was sent
while {
let isr = self.i2c.isr.read();
self.check_and_clear_error_flags(&isr)?;
self.check_and_clear_error_flags(&isr)
.map_err(Error::nack_data)?;
isr.tc().bit_is_clear()
} {}

Expand All @@ -66,7 +68,8 @@ mod blocking {
}

// Check and clear flags if they somehow ended up set
self.check_and_clear_error_flags(&self.i2c.isr.read())?;
self.check_and_clear_error_flags(&self.i2c.isr.read())
.map_err(Error::nack_data)?;

Ok(())
}
Expand Down Expand Up @@ -101,7 +104,8 @@ mod blocking {
}

// Check and clear flags if they somehow ended up set
self.check_and_clear_error_flags(&self.i2c.isr.read())?;
self.check_and_clear_error_flags(&self.i2c.isr.read())
.map_err(Error::nack_data)?;

Ok(())
}
Expand Down Expand Up @@ -135,7 +139,8 @@ mod blocking {
}

// Check and clear flags if they somehow ended up set
self.check_and_clear_error_flags(&self.i2c.isr.read())?;
self.check_and_clear_error_flags(&self.i2c.isr.read())
.map_err(Error::nack_data)?;

Ok(())
}
Expand Down
39 changes: 35 additions & 4 deletions src/i2c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,12 @@ where
}

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
#[non_exhaustive]
pub enum Error {
OVERRUN,
NACK,
NACK_ADDR,
NACK_DATA,
TIMEOUT,
// Note: The BUS error type is not currently returned, but is maintained for backwards
// compatibility.
Expand All @@ -119,6 +122,21 @@ pub enum Error {
ARBITRATION,
}

impl Error {
pub(crate) fn nack_addr(self) -> Self {
match self {
Error::NACK => Error::NACK_ADDR,
e => e,
}
}
pub(crate) fn nack_data(self) -> Self {
match self {
Error::NACK => Error::NACK_DATA,
e => e,
}
}
}

pub trait Instance: crate::Sealed + Deref<Target = i2c1::RegisterBlock> + Enable + Reset {}

impl Instance for I2C1 {}
Expand Down Expand Up @@ -302,7 +320,9 @@ where
// Wait until address was sent
loop {
// Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
let sr1 = self.check_and_clear_error_flags()?;
let sr1 = self
.check_and_clear_error_flags()
.map_err(Error::nack_addr)?;

// Wait for the address to be acknowledged
if sr1.addr().bit_is_set() {
Expand All @@ -325,22 +345,33 @@ where
fn send_byte(&self, byte: u8) -> Result<(), Error> {
// Wait until we're ready for sending
// Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
while self.check_and_clear_error_flags()?.tx_e().bit_is_clear() {}
while self
.check_and_clear_error_flags()
.map_err(Error::nack_addr)?
.tx_e()
.bit_is_clear()
{}

// Push out a byte of data
self.i2c.dr.write(|w| unsafe { w.bits(u32::from(byte)) });

// Wait until byte is transferred
// Check for any potential error conditions.
while self.check_and_clear_error_flags()?.btf().bit_is_clear() {}
while self
.check_and_clear_error_flags()
.map_err(Error::nack_data)?
.btf()
.bit_is_clear()
{}

Ok(())
}

fn recv_byte(&self) -> Result<u8, Error> {
loop {
// Check for any potential error conditions.
self.check_and_clear_error_flags()?;
self.check_and_clear_error_flags()
.map_err(Error::nack_data)?;

if self.i2c.sr1.read().rx_ne().bit_is_set() {
break;
Expand Down
3 changes: 2 additions & 1 deletion src/i2c/hal_02.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ mod blocking {

// Wait until address was sent
loop {
self.check_and_clear_error_flags()?;
self.check_and_clear_error_flags()
.map_err(Error::nack_addr)?;
if self.i2c.sr1.read().addr().bit_is_set() {
break;
}
Expand Down
5 changes: 4 additions & 1 deletion src/i2c/hal_1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ impl Error for super::Error {
Self::OVERRUN => ErrorKind::Overrun,
Self::BUS => ErrorKind::Bus,
Self::ARBITRATION => ErrorKind::ArbitrationLoss,
Self::NACK_ADDR => ErrorKind::NoAcknowledge(NoAcknowledgeSource::Address),
Self::NACK_DATA => ErrorKind::NoAcknowledge(NoAcknowledgeSource::Data),
Self::NACK => ErrorKind::NoAcknowledge(NoAcknowledgeSource::Unknown),
Self::CRC | Self::TIMEOUT => ErrorKind::Other,
}
Expand Down Expand Up @@ -129,7 +131,8 @@ mod blocking {

// Wait until address was sent
loop {
self.check_and_clear_error_flags()?;
self.check_and_clear_error_flags()
.map_err(Error::nack_addr)?;
if self.i2c.sr1.read().addr().bit_is_set() {
break;
}
Expand Down

0 comments on commit f5451d3

Please sign in to comment.