use core::mem::ManuallyDrop;
use core::ops::Deref;
use core::ptr;
use embedded_hal::i2c::{ErrorKind, ErrorType, NoAcknowledgeSource, Operation};
use crate::gpio::{Alternate, OpenDrain, Pin};
use crate::pac;
use crate::rcu::{Enable, Rcu, Reset};
use crate::time::Hertz;
const CLKC_MIN_STANDARD: u32 = 4;
const CLKC_MIN_FAST: u32 = 1;
const MIN_PCLK1_STANDARD_HZ: u32 = 2_000_000;
const MIN_PCLK1_FAST_HZ: u32 = 8_000_000;
const MIN_PCLK1_FAST_PLUS_HZ: u32 = 24_000_000;
const RISE_TIME_STANDARD_NS: u32 = 1000;
const RISE_TIME_FAST_NS: u32 = 300;
const RISE_TIME_FAST_PLUS_NS: u32 = 120;
pub trait Instance: Deref<Target = pac::i2c0::RegisterBlock> + Enable + Reset {}
impl Instance for pac::I2c0 {}
impl Instance for pac::I2c1 {}
pub trait SdaPin<I2C> {}
pub trait SclPin<I2C> {}
macro_rules! i2c_pins {
( $( $I2C:ty:
SDA: [ $($(#[$sda_cfg:meta])? $sda_p:literal $sda_n:literal : $sda_af:literal),* $(,)? ]
SCL: [ $($(#[$scl_cfg:meta])? $scl_p:literal $scl_n:literal : $scl_af:literal),* $(,)? ]
),* $(,)? ) => {
$(
$($(#[$sda_cfg])? impl SdaPin<$I2C> for Pin<$sda_p, $sda_n, Alternate<$sda_af, OpenDrain>> {})*
$($(#[$scl_cfg])? impl SclPin<$I2C> for Pin<$scl_p, $scl_n, Alternate<$scl_af, OpenDrain>> {})*
)*
};
}
i2c_pins!(
pac::I2c0:
SDA: ['A' 10 : 4, #[cfg(pads_ge_24)] 'B' 7 : 1, #[cfg(pads_ge_48)] 'B' 9 : 1, 'F' 0 : 1]
SCL: ['A' 9 : 4, #[cfg(pads_ge_24)] 'B' 6 : 1, #[cfg(pads_ge_qfn32)] 'B' 8 : 1, 'F' 1 : 1],
);
#[cfg(chip_x4)]
i2c_pins!(
pac::I2c0:
SDA: [#[cfg(pads_ge_48)] 'B' 11 : 1, #[cfg(pads_ge_48)] 'F' 7 : 0]
SCL: [#[cfg(pads_ge_48)] 'B' 10 : 1, #[cfg(pads_ge_48)] 'F' 6 : 0],
);
#[cfg(chip_x8)]
i2c_pins!(
pac::I2c1:
SDA: ['A' 1 : 4, #[cfg(pads_ge_lqfp32)] 'A' 12 : 5, #[cfg(pads_ge_48)] 'B' 11 : 1, #[cfg(pads_ge_48)] 'B' 14 : 5, #[cfg(pads_ge_48)] 'F' 7 : 0]
SCL: ['A' 0 : 4, #[cfg(pads_ge_lqfp32)] 'A' 11 : 5, #[cfg(pads_ge_48)] 'B' 10 : 1, #[cfg(pads_ge_48)] 'B' 13 : 5, #[cfg(pads_ge_48)] 'F' 6 : 0]
);
fn apply_config<I2C: Instance>(i2c: &I2C, mode: I2cMode, pclk1: Hertz) {
let pclk1 = pclk1.to_Hz();
let pclk1_mhz = pclk1 / 1_000_000;
let risetime = |t_rise_ns: u32| (pclk1_mhz * t_rise_ns / 1_000 + 1) as u8;
i2c.ctl0().modify(|_, w| w.i2cen().disabled());
i2c.ctl1()
.modify(|_, w| unsafe { w.i2cclk().bits(pclk1_mhz as u8) });
match mode {
I2cMode::Standard { frequency } => {
assert!(
pclk1 >= MIN_PCLK1_STANDARD_HZ,
"I2C standard mode needs pclk1 of at least 2 MHz"
);
let clkc = pclk1 / (2 * frequency.to_Hz());
assert!(
clkc >= CLKC_MIN_STANDARD,
"I2C frequency too high for this pclk1"
);
i2c.rt()
.write(|w| w.risetime().bits(risetime(RISE_TIME_STANDARD_NS)));
i2c.ckcfg()
.write(|w| w.fast().standard().clkc().bits(clkc as u16));
}
I2cMode::Fast {
frequency,
duty_cycle,
} => {
assert!(
pclk1 >= MIN_PCLK1_FAST_HZ,
"I2C fast mode needs pclk1 of at least 8 MHz"
);
i2c.rt()
.write(|w| w.risetime().bits(risetime(RISE_TIME_FAST_NS)));
write_fast_ckcfg(i2c, pclk1, frequency, duty_cycle);
}
I2cMode::FastPlus {
frequency,
duty_cycle,
} => {
assert!(
pclk1 >= MIN_PCLK1_FAST_PLUS_HZ,
"I2C fast mode plus needs pclk1 of at least 24 MHz"
);
i2c.rt()
.write(|w| w.risetime().bits(risetime(RISE_TIME_FAST_PLUS_NS)));
write_fast_ckcfg(i2c, pclk1, frequency, duty_cycle);
i2c.fmpcfg().write(|w| w.fmpen().set_bit());
}
}
i2c.ctl0().modify(|_, w| w.i2cen().enabled());
}
fn write_fast_ckcfg<I2C: Instance>(i2c: &I2C, pclk1: u32, frequency: Hertz, duty_cycle: DutyCycle) {
let parts = match duty_cycle {
DutyCycle::Ratio2to1 => 3,
DutyCycle::Ratio16to9 => 25,
};
let clkc = pclk1 / (parts * frequency.to_Hz());
assert!(
clkc >= CLKC_MIN_FAST,
"I2C frequency too high for this pclk1"
);
i2c.ckcfg().write(|w| {
let w = match duty_cycle {
DutyCycle::Ratio2to1 => w.dtcy().duty2(),
DutyCycle::Ratio16to9 => w.dtcy().duty16_9(),
};
w.fast().fast().clkc().bits(clkc as u16)
});
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[allow(missing_docs)]
pub enum DutyCycle {
Ratio2to1,
Ratio16to9,
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum I2cMode {
Standard {
frequency: Hertz,
},
Fast {
frequency: Hertz,
duty_cycle: DutyCycle,
},
FastPlus {
frequency: Hertz,
duty_cycle: DutyCycle,
},
}
impl I2cMode {
pub const fn standard(frequency: Hertz) -> Self {
Self::Standard { frequency }
}
pub const fn fast(frequency: Hertz, duty_cycle: DutyCycle) -> Self {
Self::Fast {
frequency,
duty_cycle,
}
}
pub const fn fast_plus(frequency: Hertz, duty_cycle: DutyCycle) -> Self {
Self::FastPlus {
frequency,
duty_cycle,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum Error {
Bus,
ArbitrationLoss,
Overrun,
NoAcknowledge(NoAcknowledgeSource),
Pec,
SmbusTimeout,
SmbusAlert,
}
impl embedded_hal::i2c::Error for Error {
fn kind(&self) -> ErrorKind {
match self {
Self::Bus => ErrorKind::Bus,
Self::ArbitrationLoss => ErrorKind::ArbitrationLoss,
Self::Overrun => ErrorKind::Overrun,
Self::NoAcknowledge(source) => ErrorKind::NoAcknowledge(*source),
Self::Pec | Self::SmbusTimeout | Self::SmbusAlert => ErrorKind::Other,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Event {
Protocol,
Byte,
Error,
}
pub struct I2c<I2CX, SDA, SCL> {
i2c: I2CX,
sda_pin: SDA,
scl_pin: SCL,
}
impl<I2CX, SDA, SCL> I2c<I2CX, SDA, SCL>
where
I2CX: Instance,
SDA: SdaPin<I2CX>,
SCL: SclPin<I2CX>,
{
pub fn new(rcu: &mut Rcu, i2c: I2CX, sda_pin: SDA, scl_pin: SCL, mode: I2cMode) -> Self {
let pclk1 = rcu.clocks().pclk1();
I2CX::enable(rcu);
I2CX::reset(rcu);
apply_config(&i2c, mode, pclk1);
Self {
i2c,
sda_pin,
scl_pin,
}
}
pub fn release(mut self, rcu: &mut Rcu) -> (I2CX, SDA, SCL) {
while self.i2c.ctl0().read().stop().bit_is_set() {}
self.unlisten(Event::Protocol);
self.unlisten(Event::Byte);
self.unlisten(Event::Error);
self.i2c.ctl0().modify(|_, w| w.i2cen().disabled());
I2CX::disable(rcu);
(self.i2c, self.sda_pin, self.scl_pin)
}
}
impl<I2CX, SDA, SCL> I2c<I2CX, SDA, SCL>
where
I2CX: Instance,
{
pub fn is_busy(&self) -> bool {
self.i2c.stat1().read().i2cbsy().is_busy()
}
pub fn sbsend(&self) -> bool {
self.i2c.stat0().read().sbsend().bit_is_set()
}
pub fn addsend(&self) -> bool {
self.i2c.stat0().read().addsend().bit_is_set()
}
pub fn tbe(&self) -> bool {
self.i2c.stat0().read().tbe().bit_is_set()
}
pub fn btc(&self) -> bool {
self.i2c.stat0().read().btc().bit_is_set()
}
pub fn rbne(&self) -> bool {
self.i2c.stat0().read().rbne().bit_is_set()
}
pub fn wait_idle(&self) {
while self.is_busy() {}
}
pub fn write_start(&mut self) {
self.i2c.ctl0().modify(|_, w| w.start().start());
}
pub fn write_addr(&mut self, address: u8, read: bool) {
assert!(address <= 0x7F, "I2C address must be 7-bit");
self.i2c
.data()
.write(|w| w.trb().bits(address << 1 | read as u8));
}
pub fn write_byte(&mut self, byte: u8) {
self.i2c.data().write(|w| w.trb().bits(byte));
}
pub fn read_byte(&mut self) -> u8 {
self.i2c.data().read().trb().bits()
}
pub fn write_stop(&mut self) {
self.i2c.ctl0().modify(|_, w| w.stop().stop());
}
pub fn clear_addsend(&mut self) {
self.i2c.stat0().read();
self.i2c.stat1().read();
}
pub fn set_acken(&mut self, ack: bool) {
self.i2c.ctl0().modify(|_, w| w.acken().bit(ack));
}
pub fn set_poap(&mut self, next: bool) {
self.i2c.ctl0().modify(|_, w| w.poap().bit(next));
}
fn start(&mut self, address: u8, read: bool) -> Result<(), Error> {
self.write_start();
while self.i2c.stat0().read().sbsend().is_no_start() {
if let Some(err) = self.take_error_from(NoAcknowledgeSource::Unknown) {
self.write_stop();
return Err(err);
}
}
self.write_addr(address, read);
while self.i2c.stat0().read().addsend().is_not_match() {
if let Some(err) = self.take_error_from(NoAcknowledgeSource::Address) {
self.write_stop();
return Err(err);
}
}
Ok(())
}
fn wait_rbne(&mut self) -> Result<(), Error> {
while self.i2c.stat0().read().rbne().is_empty() {
if let Some(err) = self.take_error_from(NoAcknowledgeSource::Data) {
self.write_stop();
return Err(err);
}
}
Ok(())
}
fn wait_btc(&mut self) -> Result<(), Error> {
while self.i2c.stat0().read().btc().is_not_finished() {
if let Some(err) = self.take_error_from(NoAcknowledgeSource::Data) {
self.write_stop();
return Err(err);
}
}
Ok(())
}
fn take_error_from(&mut self, source: NoAcknowledgeSource) -> Option<Error> {
let stat = self.i2c.stat0().read();
if stat.berr().is_error() {
self.i2c.stat0().modify(|_, w| w.berr().no_error());
Some(Error::Bus)
} else if stat.lostarb().is_lost() {
self.i2c.stat0().modify(|_, w| w.lostarb().no_lost());
Some(Error::ArbitrationLoss)
} else if stat.aerr().is_error() {
self.i2c.stat0().modify(|_, w| w.aerr().no_error());
Some(Error::NoAcknowledge(source))
} else if stat.ouerr().is_overrun() {
self.i2c.stat0().modify(|_, w| w.ouerr().no_overrun());
Some(Error::Overrun)
} else if stat.pecerr().is_error() {
self.i2c.stat0().modify(|_, w| w.pecerr().no_error());
Some(Error::Pec)
} else if stat.smbto().is_timeout() {
self.i2c.stat0().modify(|_, w| w.smbto().no_timeout());
Some(Error::SmbusTimeout)
} else if stat.smbalt().is_alert() {
self.i2c.stat0().modify(|_, w| w.smbalt().no_alert());
Some(Error::SmbusAlert)
} else {
None
}
}
pub fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> {
assert!(address <= 0x7F, "I2C address must be 7-bit");
self.wait_idle();
self.write_phase(address, bytes)?;
self.write_stop();
Ok(())
}
fn write_phase(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> {
self.start(address, false)?;
self.clear_addsend();
self.write_bytes(bytes)?;
if !bytes.is_empty() {
self.wait_btc()?;
}
Ok(())
}
fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), Error> {
for byte in bytes {
while self.i2c.stat0().read().tbe().is_not_empty() {
if let Some(err) = self.take_error_from(NoAcknowledgeSource::Data) {
self.write_stop();
return Err(err);
}
}
self.i2c.data().write(|w| w.trb().bits(*byte));
}
Ok(())
}
pub fn read(&mut self, address: u8, bytes: &mut [u8]) -> Result<(), Error> {
assert!(address <= 0x7F, "I2C address must be 7-bit");
if bytes.is_empty() {
return Ok(());
}
self.wait_idle();
self.read_phase(address, bytes)
}
fn read_phase(&mut self, address: u8, bytes: &mut [u8]) -> Result<(), Error> {
let n = bytes.len();
self.read_slots(address, n, bytes.iter_mut())
}
fn read_slots<'a>(
&mut self,
address: u8,
n: usize,
mut slots: impl Iterator<Item = &'a mut u8>,
) -> Result<(), Error> {
match n {
0 => Ok(()),
1 => {
self.start(address, true)?;
self.i2c.ctl0().modify(|_, w| w.acken().nak());
self.clear_addsend();
self.write_stop();
self.wait_rbne()?;
if let Some(slot) = slots.next() {
*slot = self.read_byte();
}
Ok(())
}
2 => {
self.i2c.ctl0().modify(|_, w| w.poap().next());
let result = self.read_two(address, slots);
self.i2c.ctl0().modify(|_, w| w.poap().current());
result
}
_ => {
self.i2c.ctl0().modify(|_, w| w.acken().ack());
self.start(address, true)?;
self.clear_addsend();
for _ in 0..n - 3 {
self.wait_rbne()?;
if let Some(slot) = slots.next() {
*slot = self.read_byte();
}
}
self.wait_btc()?;
self.i2c.ctl0().modify(|_, w| w.acken().nak());
if let Some(slot) = slots.next() {
*slot = self.read_byte();
}
self.wait_btc()?;
self.write_stop();
for slot in slots {
*slot = self.read_byte();
}
Ok(())
}
}
}
fn read_two<'a>(
&mut self,
address: u8,
slots: impl Iterator<Item = &'a mut u8>,
) -> Result<(), Error> {
self.start(address, true)?;
self.i2c.ctl0().modify(|_, w| w.acken().nak());
self.clear_addsend();
self.wait_btc()?;
self.write_stop();
for slot in slots {
*slot = self.read_byte();
}
Ok(())
}
pub fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
assert!(address <= 0x7F, "I2C address must be 7-bit");
self.wait_idle();
self.write_phase(address, write)?;
if read.is_empty() {
self.write_stop();
return Ok(());
}
self.read_phase(address, read)
}
pub fn take_error(&mut self) -> Option<Error> {
self.take_error_from(NoAcknowledgeSource::Unknown)
}
pub fn listen(&mut self, event: Event) {
match event {
Event::Protocol => self.i2c.ctl1().modify(|_, w| w.evie().enabled()),
Event::Byte => self
.i2c
.ctl1()
.modify(|_, w| w.evie().enabled().bufie().enabled()),
Event::Error => self.i2c.ctl1().modify(|_, w| w.errie().enabled()),
}
}
pub fn unlisten(&mut self, event: Event) {
match event {
Event::Protocol => self
.i2c
.ctl1()
.modify(|_, w| w.evie().disabled().bufie().disabled()),
Event::Byte => self.i2c.ctl1().modify(|_, w| w.bufie().disabled()),
Event::Error => self.i2c.ctl1().modify(|_, w| w.errie().disabled()),
}
}
pub fn is_listening(&self, event: Event) -> bool {
let ctl1 = self.i2c.ctl1().read();
match event {
Event::Protocol => ctl1.evie().is_enabled(),
Event::Byte => ctl1.evie().is_enabled() && ctl1.bufie().is_enabled(),
Event::Error => ctl1.errie().is_enabled(),
}
}
pub fn start_write(mut self, address: u8, buf: &'static [u8]) -> WriteTransfer<I2CX, SDA, SCL> {
assert!(address <= 0x7F, "I2C address must be 7-bit");
self.wait_idle();
self.listen(Event::Error);
self.listen(Event::Byte);
self.write_start();
WriteTransfer {
i2c: self,
address: address << 1,
buf,
pos: 0,
state: WriteState::Sbsend,
}
}
pub fn start_read(
mut self,
address: u8,
buf: &'static mut [u8],
) -> ReadTransfer<I2CX, SDA, SCL> {
assert!(address <= 0x7F, "I2C address must be 7-bit");
if buf.is_empty() {
return ReadTransfer {
i2c: self,
address: address << 1 | 1,
buf,
pos: 0,
state: ReadState::Done(Ok(())),
};
}
self.wait_idle();
self.set_acken(buf.len() > 2);
self.set_poap(buf.len() == 2);
self.listen(Event::Error);
self.listen(Event::Byte);
self.write_start();
ReadTransfer {
i2c: self,
address: address << 1 | 1,
buf,
pos: 0,
state: ReadState::Sbsend,
}
}
}
#[derive(Clone, Copy)]
enum WriteState {
Sbsend,
Addsend,
Sending,
Btc,
Done(Result<(), Error>),
}
#[must_use = "dropping the transfer aborts it"]
pub struct WriteTransfer<I2CX, SDA, SCL>
where
I2CX: Instance,
{
i2c: I2c<I2CX, SDA, SCL>,
address: u8,
buf: &'static [u8],
pos: usize,
state: WriteState,
}
impl<I2CX, SDA, SCL> WriteTransfer<I2CX, SDA, SCL>
where
I2CX: Instance,
{
pub fn on_interrupt(&mut self) {
if self.is_done() {
return;
}
if let Some(err) = self.i2c.take_error() {
self.i2c.write_stop();
self.finish(Err(err));
return;
}
match self.state {
WriteState::Sbsend if self.i2c.sbsend() => {
self.i2c.write_byte(self.address);
self.state = WriteState::Addsend;
}
WriteState::Addsend if self.i2c.addsend() => {
self.i2c.clear_addsend();
if self.buf.is_empty() {
self.i2c.write_stop();
self.finish(Ok(()));
} else {
self.state = WriteState::Sending;
}
}
WriteState::Sending if self.i2c.tbe() => {
self.i2c.write_byte(self.buf[self.pos]);
self.pos += 1;
if self.pos == self.buf.len() {
self.i2c.unlisten(Event::Byte);
self.state = WriteState::Btc;
}
}
WriteState::Btc if self.i2c.btc() => {
self.i2c.write_stop();
self.finish(Ok(()));
}
_ => {}
}
}
pub fn is_done(&self) -> bool {
matches!(self.state, WriteState::Done(_))
}
#[allow(clippy::type_complexity)]
pub fn release(
self,
) -> (
I2c<I2CX, SDA, SCL>,
&'static [u8],
Option<Result<(), Error>>,
) {
let mut this = ManuallyDrop::new(self);
let outcome = if let WriteState::Done(result) = this.state {
Some(result)
} else {
this.abort();
None
};
let i2c = unsafe { ptr::read(&raw const this.i2c) };
(i2c, this.buf, outcome)
}
fn finish(&mut self, result: Result<(), Error>) {
self.i2c.unlisten(Event::Protocol);
self.i2c.unlisten(Event::Error);
self.state = WriteState::Done(result);
}
fn abort(&mut self) {
self.i2c.write_stop();
self.finish(Ok(()));
}
}
impl<I2CX, SDA, SCL> Drop for WriteTransfer<I2CX, SDA, SCL>
where
I2CX: Instance,
{
fn drop(&mut self) {
if !self.is_done() {
self.abort();
}
}
}
#[derive(Clone, Copy)]
enum ReadState {
Sbsend,
Addsend,
Receiving,
Penultimate,
Tail,
Single,
Done(Result<(), Error>),
}
#[must_use = "dropping the transfer aborts it"]
pub struct ReadTransfer<I2CX, SDA, SCL>
where
I2CX: Instance,
{
i2c: I2c<I2CX, SDA, SCL>,
address: u8,
buf: &'static mut [u8],
pos: usize,
state: ReadState,
}
impl<I2CX, SDA, SCL> ReadTransfer<I2CX, SDA, SCL>
where
I2CX: Instance,
{
pub fn on_interrupt(&mut self) {
if self.is_done() {
return;
}
if let Some(err) = self.i2c.take_error() {
self.i2c.write_stop();
self.finish(Err(err));
return;
}
match self.state {
ReadState::Sbsend if self.i2c.sbsend() => {
self.i2c.write_byte(self.address);
self.state = ReadState::Addsend;
}
ReadState::Addsend if self.i2c.addsend() => {
self.state = match self.buf.len() {
1 => {
self.i2c.set_acken(false);
self.i2c.clear_addsend();
self.i2c.write_stop();
ReadState::Single
}
2 => {
self.i2c.set_acken(false);
self.i2c.clear_addsend();
self.i2c.unlisten(Event::Byte);
ReadState::Tail
}
3 => {
self.i2c.clear_addsend();
self.i2c.unlisten(Event::Byte);
ReadState::Penultimate
}
_ => {
self.i2c.clear_addsend();
ReadState::Receiving
}
};
}
ReadState::Single if self.i2c.rbne() => {
self.buf[0] = self.i2c.read_byte();
self.pos = 1;
self.finish(Ok(()));
}
ReadState::Receiving if self.i2c.rbne() => {
self.buf[self.pos] = self.i2c.read_byte();
self.pos += 1;
if self.pos == self.buf.len() - 3 {
self.i2c.unlisten(Event::Byte);
self.state = ReadState::Penultimate;
}
}
ReadState::Penultimate if self.i2c.btc() => {
self.i2c.set_acken(false);
self.buf[self.pos] = self.i2c.read_byte();
self.pos += 1;
self.state = ReadState::Tail;
}
ReadState::Tail if self.i2c.btc() => {
self.i2c.write_stop();
while self.pos < self.buf.len() {
self.buf[self.pos] = self.i2c.read_byte();
self.pos += 1;
}
self.finish(Ok(()));
}
_ => {}
}
}
pub fn is_done(&self) -> bool {
matches!(self.state, ReadState::Done(_))
}
#[allow(clippy::type_complexity)]
pub fn release(
self,
) -> (
I2c<I2CX, SDA, SCL>,
&'static mut [u8],
Option<Result<(), Error>>,
) {
let mut this = ManuallyDrop::new(self);
let outcome = if let ReadState::Done(result) = this.state {
Some(result)
} else {
this.abort();
None
};
let (i2c, buf) = unsafe {
(
ptr::read(&raw const this.i2c),
ptr::read(&raw const this.buf),
)
};
(i2c, buf, outcome)
}
fn finish(&mut self, result: Result<(), Error>) {
self.i2c.set_poap(false);
self.i2c.unlisten(Event::Protocol);
self.i2c.unlisten(Event::Error);
self.state = ReadState::Done(result);
}
fn abort(&mut self) {
self.i2c.write_stop();
self.finish(Ok(()));
}
}
impl<I2CX, SDA, SCL> Drop for ReadTransfer<I2CX, SDA, SCL>
where
I2CX: Instance,
{
fn drop(&mut self) {
if !self.is_done() {
self.abort();
}
}
}
impl<I2CX, SDA, SCL> ErrorType for I2c<I2CX, SDA, SCL>
where
I2CX: Instance,
{
type Error = Error;
}
fn same_direction(a: &Operation<'_>, b: &Operation<'_>) -> bool {
matches!(
(a, b),
(Operation::Read(_), Operation::Read(_)) | (Operation::Write(_), Operation::Write(_))
)
}
impl<I2CX, SDA, SCL> embedded_hal::i2c::I2c for I2c<I2CX, SDA, SCL>
where
I2CX: Instance,
{
fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
assert!(address <= 0x7F, "I2C address must be 7-bit");
if operations.is_empty() {
return Ok(());
}
let phases = operations.chunk_by(same_direction).count();
self.wait_idle();
for (i, phase) in operations.chunk_by_mut(same_direction).enumerate() {
let last = i + 1 == phases;
match phase.first() {
Some(Operation::Write(_)) => {
self.start(address, false)?;
self.clear_addsend();
let mut sent = false;
for op in phase.iter() {
if let Operation::Write(bytes) = op {
self.write_bytes(bytes)?;
sent |= !bytes.is_empty();
}
}
if sent {
self.wait_btc()?;
}
if last {
self.write_stop();
}
}
Some(Operation::Read(_)) => {
assert!(last, "I2C read must be the last operation of a transaction");
let n = phase
.iter()
.map(|op| match op {
Operation::Read(buf) => buf.len(),
Operation::Write(_) => 0,
})
.sum();
let slots = phase
.iter_mut()
.filter_map(|op| match op {
Operation::Read(buf) => Some(buf),
Operation::Write(_) => None,
})
.flat_map(|buf| buf.iter_mut());
self.read_slots(address, n, slots)?;
}
None => {}
}
}
Ok(())
}
fn read(&mut self, address: u8, bytes: &mut [u8]) -> Result<(), Error> {
self.read(address, bytes)
}
fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Error> {
self.write(address, bytes)
}
fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Error> {
self.write_read(address, bytes, buffer)
}
}