Merge pull request #2304 from embassy-rs/stm32-docs

stm32/i2c: remove _timeout public API, share more code between v1/v2.
This commit is contained in:
Dario Nieuwenhuis 2023-12-18 17:30:08 +00:00 committed by GitHub
commit 3f0920c400
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 268 additions and 511 deletions

View File

@ -1,17 +1,23 @@
#![macro_use] #![macro_use]
use core::marker::PhantomData;
use crate::dma::NoDma;
use crate::interrupt;
#[cfg_attr(i2c_v1, path = "v1.rs")] #[cfg_attr(i2c_v1, path = "v1.rs")]
#[cfg_attr(i2c_v2, path = "v2.rs")] #[cfg_attr(i2c_v2, path = "v2.rs")]
mod _version; mod _version;
pub use _version::*;
use embassy_sync::waitqueue::AtomicWaker;
use crate::peripherals; use core::future::Future;
use core::marker::PhantomData;
use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
use embassy_sync::waitqueue::AtomicWaker;
#[cfg(feature = "time")]
use embassy_time::{Duration, Instant};
use crate::dma::NoDma;
use crate::gpio::sealed::AFType;
use crate::gpio::Pull;
use crate::interrupt::typelevel::Interrupt;
use crate::time::Hertz;
use crate::{interrupt, peripherals};
/// I2C error. /// I2C error.
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
@ -33,6 +39,148 @@ pub enum Error {
ZeroLengthTransfer, ZeroLengthTransfer,
} }
/// I2C config
#[non_exhaustive]
#[derive(Copy, Clone)]
pub struct Config {
/// Enable internal pullup on SDA.
///
/// Using external pullup resistors is recommended for I2C. If you do
/// have external pullups you should not enable this.
pub sda_pullup: bool,
/// Enable internal pullup on SCL.
///
/// Using external pullup resistors is recommended for I2C. If you do
/// have external pullups you should not enable this.
pub scl_pullup: bool,
/// Timeout.
#[cfg(feature = "time")]
pub timeout: embassy_time::Duration,
}
impl Default for Config {
fn default() -> Self {
Self {
sda_pullup: false,
scl_pullup: false,
#[cfg(feature = "time")]
timeout: embassy_time::Duration::from_millis(1000),
}
}
}
/// I2C driver.
pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> {
_peri: PeripheralRef<'d, T>,
#[allow(dead_code)]
tx_dma: PeripheralRef<'d, TXDMA>,
#[allow(dead_code)]
rx_dma: PeripheralRef<'d, RXDMA>,
#[cfg(feature = "time")]
timeout: Duration,
}
impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
/// Create a new I2C driver.
pub fn new(
peri: impl Peripheral<P = T> + 'd,
scl: impl Peripheral<P = impl SclPin<T>> + 'd,
sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>>
+ interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>>
+ 'd,
tx_dma: impl Peripheral<P = TXDMA> + 'd,
rx_dma: impl Peripheral<P = RXDMA> + 'd,
freq: Hertz,
config: Config,
) -> Self {
into_ref!(peri, scl, sda, tx_dma, rx_dma);
T::enable_and_reset();
scl.set_as_af_pull(
scl.af_num(),
AFType::OutputOpenDrain,
match config.scl_pullup {
true => Pull::Up,
false => Pull::None,
},
);
sda.set_as_af_pull(
sda.af_num(),
AFType::OutputOpenDrain,
match config.sda_pullup {
true => Pull::Up,
false => Pull::None,
},
);
unsafe { T::EventInterrupt::enable() };
unsafe { T::ErrorInterrupt::enable() };
let mut this = Self {
_peri: peri,
tx_dma,
rx_dma,
#[cfg(feature = "time")]
timeout: config.timeout,
};
this.init(freq, config);
this
}
fn timeout(&self) -> Timeout {
Timeout {
#[cfg(feature = "time")]
deadline: Instant::now() + self.timeout,
}
}
}
#[derive(Copy, Clone)]
struct Timeout {
#[cfg(feature = "time")]
deadline: Instant,
}
#[allow(dead_code)]
impl Timeout {
#[cfg(not(feature = "time"))]
#[inline]
fn check(self) -> Result<(), Error> {
Ok(())
}
#[cfg(feature = "time")]
#[inline]
fn check(self) -> Result<(), Error> {
if Instant::now() > self.deadline {
Err(Error::Timeout)
} else {
Ok(())
}
}
#[cfg(not(feature = "time"))]
#[inline]
fn with<R>(self, fut: impl Future<Output = Result<R, Error>>) -> impl Future<Output = Result<R, Error>> {
fut
}
#[cfg(feature = "time")]
#[inline]
fn with<R>(self, fut: impl Future<Output = Result<R, Error>>) -> impl Future<Output = Result<R, Error>> {
use futures::FutureExt;
embassy_futures::select::select(embassy_time::Timer::at(self.deadline), fut).map(|r| match r {
embassy_futures::select::Either::First(_) => Err(Error::Timeout),
embassy_futures::select::Either::Second(r) => r,
})
}
}
pub(crate) mod sealed { pub(crate) mod sealed {
use super::*; use super::*;

View File

@ -1,20 +1,14 @@
use core::future::poll_fn; use core::future::poll_fn;
use core::marker::PhantomData;
use core::task::Poll; use core::task::Poll;
use embassy_embedded_hal::SetConfig; use embassy_embedded_hal::SetConfig;
use embassy_futures::select::{select, Either}; use embassy_futures::select::{select, Either};
use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::drop::OnDrop;
use embassy_hal_internal::{into_ref, PeripheralRef};
use super::*; use super::*;
use crate::dma::{NoDma, Transfer}; use crate::dma::Transfer;
use crate::gpio::sealed::AFType;
use crate::gpio::Pull;
use crate::interrupt::typelevel::Interrupt;
use crate::pac::i2c; use crate::pac::i2c;
use crate::time::Hertz; use crate::time::Hertz;
use crate::{interrupt, Peripheral};
pub unsafe fn on_interrupt<T: Instance>() { pub unsafe fn on_interrupt<T: Instance>() {
let regs = T::regs(); let regs = T::regs();
@ -30,55 +24,8 @@ pub unsafe fn on_interrupt<T: Instance>() {
}); });
} }
#[non_exhaustive]
#[derive(Copy, Clone, Default)]
pub struct Config {
pub sda_pullup: bool,
pub scl_pullup: bool,
}
pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> {
phantom: PhantomData<&'d mut T>,
#[allow(dead_code)]
tx_dma: PeripheralRef<'d, TXDMA>,
#[allow(dead_code)]
rx_dma: PeripheralRef<'d, RXDMA>,
}
impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
pub fn new( pub(crate) fn init(&mut self, freq: Hertz, _config: Config) {
_peri: impl Peripheral<P = T> + 'd,
scl: impl Peripheral<P = impl SclPin<T>> + 'd,
sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>>
+ interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>>
+ 'd,
tx_dma: impl Peripheral<P = TXDMA> + 'd,
rx_dma: impl Peripheral<P = RXDMA> + 'd,
freq: Hertz,
config: Config,
) -> Self {
into_ref!(scl, sda, tx_dma, rx_dma);
T::enable_and_reset();
scl.set_as_af_pull(
scl.af_num(),
AFType::OutputOpenDrain,
match config.scl_pullup {
true => Pull::Up,
false => Pull::None,
},
);
sda.set_as_af_pull(
sda.af_num(),
AFType::OutputOpenDrain,
match config.sda_pullup {
true => Pull::Up,
false => Pull::None,
},
);
T::regs().cr1().modify(|reg| { T::regs().cr1().modify(|reg| {
reg.set_pe(false); reg.set_pe(false);
//reg.set_anfoff(false); //reg.set_anfoff(false);
@ -101,15 +48,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
T::regs().cr1().modify(|reg| { T::regs().cr1().modify(|reg| {
reg.set_pe(true); reg.set_pe(true);
}); });
unsafe { T::EventInterrupt::enable() };
unsafe { T::ErrorInterrupt::enable() };
Self {
phantom: PhantomData,
tx_dma,
rx_dma,
}
} }
fn check_and_clear_error_flags() -> Result<i2c::regs::Sr1, Error> { fn check_and_clear_error_flags() -> Result<i2c::regs::Sr1, Error> {
@ -169,12 +107,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
Ok(sr1) Ok(sr1)
} }
fn write_bytes( fn write_bytes(&mut self, addr: u8, bytes: &[u8], timeout: Timeout) -> Result<(), Error> {
&mut self,
addr: u8,
bytes: &[u8],
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
// Send a START condition // Send a START condition
T::regs().cr1().modify(|reg| { T::regs().cr1().modify(|reg| {
@ -183,7 +116,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
// Wait until START condition was generated // Wait until START condition was generated
while !Self::check_and_clear_error_flags()?.start() { while !Self::check_and_clear_error_flags()?.start() {
check_timeout()?; timeout.check()?;
} }
// Also wait until signalled we're master and everything is waiting for us // Also wait until signalled we're master and everything is waiting for us
@ -193,7 +126,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
let sr2 = T::regs().sr2().read(); let sr2 = T::regs().sr2().read();
!sr2.msl() && !sr2.busy() !sr2.msl() && !sr2.busy()
} { } {
check_timeout()?; timeout.check()?;
} }
// Set up current address, we're trying to talk to // Set up current address, we're trying to talk to
@ -203,7 +136,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
// Wait for the address to be acknowledged // Wait for the address to be acknowledged
// Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
while !Self::check_and_clear_error_flags()?.addr() { while !Self::check_and_clear_error_flags()?.addr() {
check_timeout()?; timeout.check()?;
} }
// Clear condition by reading SR2 // Clear condition by reading SR2
@ -211,20 +144,20 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
// Send bytes // Send bytes
for c in bytes { for c in bytes {
self.send_byte(*c, &check_timeout)?; self.send_byte(*c, timeout)?;
} }
// Fallthrough is success // Fallthrough is success
Ok(()) Ok(())
} }
fn send_byte(&self, byte: u8, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { fn send_byte(&self, byte: u8, timeout: Timeout) -> Result<(), Error> {
// Wait until we're ready for sending // Wait until we're ready for sending
while { while {
// Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set. // Check for any I2C errors. If a NACK occurs, the ADDR bit will never be set.
!Self::check_and_clear_error_flags()?.txe() !Self::check_and_clear_error_flags()?.txe()
} { } {
check_timeout()?; timeout.check()?;
} }
// Push out a byte of data // Push out a byte of data
@ -235,32 +168,27 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
// Check for any potential error conditions. // Check for any potential error conditions.
!Self::check_and_clear_error_flags()?.btf() !Self::check_and_clear_error_flags()?.btf()
} { } {
check_timeout()?; timeout.check()?;
} }
Ok(()) Ok(())
} }
fn recv_byte(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<u8, Error> { fn recv_byte(&self, timeout: Timeout) -> Result<u8, Error> {
while { while {
// Check for any potential error conditions. // Check for any potential error conditions.
Self::check_and_clear_error_flags()?; Self::check_and_clear_error_flags()?;
!T::regs().sr1().read().rxne() !T::regs().sr1().read().rxne()
} { } {
check_timeout()?; timeout.check()?;
} }
let value = T::regs().dr().read().dr(); let value = T::regs().dr().read().dr();
Ok(value) Ok(value)
} }
pub fn blocking_read_timeout( fn blocking_read_timeout(&mut self, addr: u8, buffer: &mut [u8], timeout: Timeout) -> Result<(), Error> {
&mut self,
addr: u8,
buffer: &mut [u8],
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
if let Some((last, buffer)) = buffer.split_last_mut() { if let Some((last, buffer)) = buffer.split_last_mut() {
// Send a START condition and set ACK bit // Send a START condition and set ACK bit
T::regs().cr1().modify(|reg| { T::regs().cr1().modify(|reg| {
@ -270,7 +198,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
// Wait until START condition was generated // Wait until START condition was generated
while !Self::check_and_clear_error_flags()?.start() { while !Self::check_and_clear_error_flags()?.start() {
check_timeout()?; timeout.check()?;
} }
// Also wait until signalled we're master and everything is waiting for us // Also wait until signalled we're master and everything is waiting for us
@ -278,7 +206,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
let sr2 = T::regs().sr2().read(); let sr2 = T::regs().sr2().read();
!sr2.msl() && !sr2.busy() !sr2.msl() && !sr2.busy()
} { } {
check_timeout()?; timeout.check()?;
} }
// Set up current address, we're trying to talk to // Set up current address, we're trying to talk to
@ -287,7 +215,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
// Wait until address was sent // Wait until address was sent
// Wait for the address to be acknowledged // Wait for the address to be acknowledged
while !Self::check_and_clear_error_flags()?.addr() { while !Self::check_and_clear_error_flags()?.addr() {
check_timeout()?; timeout.check()?;
} }
// Clear condition by reading SR2 // Clear condition by reading SR2
@ -295,7 +223,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
// Receive bytes into buffer // Receive bytes into buffer
for c in buffer { for c in buffer {
*c = self.recv_byte(&check_timeout)?; *c = self.recv_byte(timeout)?;
} }
// Prepare to send NACK then STOP after next byte // Prepare to send NACK then STOP after next byte
@ -305,11 +233,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
}); });
// Receive last byte // Receive last byte
*last = self.recv_byte(&check_timeout)?; *last = self.recv_byte(timeout)?;
// Wait for the STOP to be sent. // Wait for the STOP to be sent.
while T::regs().cr1().read().stop() { while T::regs().cr1().read().stop() {
check_timeout()?; timeout.check()?;
} }
// Fallthrough is success // Fallthrough is success
@ -320,48 +248,33 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
} }
pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> { pub fn blocking_read(&mut self, addr: u8, read: &mut [u8]) -> Result<(), Error> {
self.blocking_read_timeout(addr, read, || Ok(())) self.blocking_read_timeout(addr, read, self.timeout())
} }
pub fn blocking_write_timeout( pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> {
&mut self, let timeout = self.timeout();
addr: u8,
write: &[u8], self.write_bytes(addr, write, timeout)?;
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
self.write_bytes(addr, write, &check_timeout)?;
// Send a STOP condition // Send a STOP condition
T::regs().cr1().modify(|reg| reg.set_stop(true)); T::regs().cr1().modify(|reg| reg.set_stop(true));
// Wait for STOP condition to transmit. // Wait for STOP condition to transmit.
while T::regs().cr1().read().stop() { while T::regs().cr1().read().stop() {
check_timeout()?; timeout.check()?;
} }
// Fallthrough is success // Fallthrough is success
Ok(()) Ok(())
} }
pub fn blocking_write(&mut self, addr: u8, write: &[u8]) -> Result<(), Error> { pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
self.blocking_write_timeout(addr, write, || Ok(())) let timeout = self.timeout();
}
pub fn blocking_write_read_timeout( self.write_bytes(addr, write, timeout)?;
&mut self, self.blocking_read_timeout(addr, read, timeout)?;
addr: u8,
write: &[u8],
read: &mut [u8],
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
self.write_bytes(addr, write, &check_timeout)?;
self.blocking_read_timeout(addr, read, &check_timeout)?;
Ok(()) Ok(())
} }
pub fn blocking_write_read(&mut self, addr: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
self.blocking_write_read_timeout(addr, write, read, || Ok(()))
}
// Async // Async
#[inline] // pretty sure this should always be inlined #[inline] // pretty sure this should always be inlined

View File

@ -4,37 +4,13 @@ use core::task::Poll;
use embassy_embedded_hal::SetConfig; use embassy_embedded_hal::SetConfig;
use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::drop::OnDrop;
use embassy_hal_internal::{into_ref, PeripheralRef};
#[cfg(feature = "time")]
use embassy_time::{Duration, Instant};
use super::*; use super::*;
use crate::dma::{NoDma, Transfer}; use crate::dma::Transfer;
use crate::gpio::sealed::AFType;
use crate::gpio::Pull;
use crate::interrupt::typelevel::Interrupt;
use crate::pac::i2c; use crate::pac::i2c;
use crate::time::Hertz; use crate::time::Hertz;
use crate::{interrupt, Peripheral};
#[cfg(feature = "time")] pub(crate) unsafe fn on_interrupt<T: Instance>() {
fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> {
let deadline = Instant::now() + timeout;
move || {
if Instant::now() > deadline {
Err(Error::Timeout)
} else {
Ok(())
}
}
}
#[cfg(not(feature = "time"))]
pub fn no_timeout_fn() -> impl Fn() -> Result<(), Error> {
move || Ok(())
}
pub unsafe fn on_interrupt<T: Instance>() {
let regs = T::regs(); let regs = T::regs();
let isr = regs.isr().read(); let isr = regs.isr().read();
@ -48,70 +24,8 @@ pub unsafe fn on_interrupt<T: Instance>() {
}); });
} }
#[non_exhaustive]
#[derive(Copy, Clone)]
pub struct Config {
pub sda_pullup: bool,
pub scl_pullup: bool,
#[cfg(feature = "time")]
pub transaction_timeout: Duration,
}
impl Default for Config {
fn default() -> Self {
Self {
sda_pullup: false,
scl_pullup: false,
#[cfg(feature = "time")]
transaction_timeout: Duration::from_millis(100),
}
}
}
pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> {
_peri: PeripheralRef<'d, T>,
#[allow(dead_code)]
tx_dma: PeripheralRef<'d, TXDMA>,
#[allow(dead_code)]
rx_dma: PeripheralRef<'d, RXDMA>,
#[cfg(feature = "time")]
timeout: Duration,
}
impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
pub fn new( pub(crate) fn init(&mut self, freq: Hertz, _config: Config) {
peri: impl Peripheral<P = T> + 'd,
scl: impl Peripheral<P = impl SclPin<T>> + 'd,
sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
_irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>>
+ interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>>
+ 'd,
tx_dma: impl Peripheral<P = TXDMA> + 'd,
rx_dma: impl Peripheral<P = RXDMA> + 'd,
freq: Hertz,
config: Config,
) -> Self {
into_ref!(peri, scl, sda, tx_dma, rx_dma);
T::enable_and_reset();
scl.set_as_af_pull(
scl.af_num(),
AFType::OutputOpenDrain,
match config.scl_pullup {
true => Pull::Up,
false => Pull::None,
},
);
sda.set_as_af_pull(
sda.af_num(),
AFType::OutputOpenDrain,
match config.sda_pullup {
true => Pull::Up,
false => Pull::None,
},
);
T::regs().cr1().modify(|reg| { T::regs().cr1().modify(|reg| {
reg.set_pe(false); reg.set_pe(false);
reg.set_anfoff(false); reg.set_anfoff(false);
@ -130,17 +44,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
T::regs().cr1().modify(|reg| { T::regs().cr1().modify(|reg| {
reg.set_pe(true); reg.set_pe(true);
}); });
unsafe { T::EventInterrupt::enable() };
unsafe { T::ErrorInterrupt::enable() };
Self {
_peri: peri,
tx_dma,
rx_dma,
#[cfg(feature = "time")]
timeout: config.transaction_timeout,
}
} }
fn master_stop(&mut self) { fn master_stop(&mut self) {
@ -153,7 +56,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
stop: Stop, stop: Stop,
reload: bool, reload: bool,
restart: bool, restart: bool,
check_timeout: impl Fn() -> Result<(), Error>, timeout: Timeout,
) -> Result<(), Error> { ) -> Result<(), Error> {
assert!(length < 256); assert!(length < 256);
@ -162,7 +65,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
// automatically. This could be up to 50% of a bus // automatically. This could be up to 50% of a bus
// cycle (ie. up to 0.5/freq) // cycle (ie. up to 0.5/freq)
while T::regs().cr2().read().start() { while T::regs().cr2().read().start() {
check_timeout()?; timeout.check()?;
} }
} }
@ -189,20 +92,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
Ok(()) Ok(())
} }
fn master_write( fn master_write(address: u8, length: usize, stop: Stop, reload: bool, timeout: Timeout) -> Result<(), Error> {
address: u8,
length: usize,
stop: Stop,
reload: bool,
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
assert!(length < 256); assert!(length < 256);
// Wait for any previous address sequence to end // Wait for any previous address sequence to end
// automatically. This could be up to 50% of a bus // automatically. This could be up to 50% of a bus
// cycle (ie. up to 0.5/freq) // cycle (ie. up to 0.5/freq)
while T::regs().cr2().read().start() { while T::regs().cr2().read().start() {
check_timeout()?; timeout.check()?;
} }
let reload = if reload { let reload = if reload {
@ -227,15 +124,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
Ok(()) Ok(())
} }
fn master_continue( fn master_continue(length: usize, reload: bool, timeout: Timeout) -> Result<(), Error> {
length: usize,
reload: bool,
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
assert!(length < 256 && length > 0); assert!(length < 256 && length > 0);
while !T::regs().isr().read().tcr() { while !T::regs().isr().read().tcr() {
check_timeout()?; timeout.check()?;
} }
let reload = if reload { let reload = if reload {
@ -261,7 +154,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
} }
} }
fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { fn wait_txe(&self, timeout: Timeout) -> Result<(), Error> {
loop { loop {
let isr = T::regs().isr().read(); let isr = T::regs().isr().read();
if isr.txe() { if isr.txe() {
@ -278,11 +171,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
return Err(Error::Nack); return Err(Error::Nack);
} }
check_timeout()?; timeout.check()?;
} }
} }
fn wait_rxne(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { fn wait_rxne(&self, timeout: Timeout) -> Result<(), Error> {
loop { loop {
let isr = T::regs().isr().read(); let isr = T::regs().isr().read();
if isr.rxne() { if isr.rxne() {
@ -299,11 +192,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
return Err(Error::Nack); return Err(Error::Nack);
} }
check_timeout()?; timeout.check()?;
} }
} }
fn wait_tc(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { fn wait_tc(&self, timeout: Timeout) -> Result<(), Error> {
loop { loop {
let isr = T::regs().isr().read(); let isr = T::regs().isr().read();
if isr.tc() { if isr.tc() {
@ -320,17 +213,11 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
return Err(Error::Nack); return Err(Error::Nack);
} }
check_timeout()?; timeout.check()?;
} }
} }
fn read_internal( fn read_internal(&mut self, address: u8, read: &mut [u8], restart: bool, timeout: Timeout) -> Result<(), Error> {
&mut self,
address: u8,
read: &mut [u8],
restart: bool,
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
let completed_chunks = read.len() / 255; let completed_chunks = read.len() / 255;
let total_chunks = if completed_chunks * 255 == read.len() { let total_chunks = if completed_chunks * 255 == read.len() {
completed_chunks completed_chunks
@ -345,17 +232,17 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
Stop::Automatic, Stop::Automatic,
last_chunk_idx != 0, last_chunk_idx != 0,
restart, restart,
&check_timeout, timeout,
)?; )?;
for (number, chunk) in read.chunks_mut(255).enumerate() { for (number, chunk) in read.chunks_mut(255).enumerate() {
if number != 0 { if number != 0 {
Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?; Self::master_continue(chunk.len(), number != last_chunk_idx, timeout)?;
} }
for byte in chunk { for byte in chunk {
// Wait until we have received something // Wait until we have received something
self.wait_rxne(&check_timeout)?; self.wait_rxne(timeout)?;
*byte = T::regs().rxdr().read().rxdata(); *byte = T::regs().rxdr().read().rxdata();
} }
@ -363,13 +250,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
Ok(()) Ok(())
} }
fn write_internal( fn write_internal(&mut self, address: u8, write: &[u8], send_stop: bool, timeout: Timeout) -> Result<(), Error> {
&mut self,
address: u8,
write: &[u8],
send_stop: bool,
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
let completed_chunks = write.len() / 255; let completed_chunks = write.len() / 255;
let total_chunks = if completed_chunks * 255 == write.len() { let total_chunks = if completed_chunks * 255 == write.len() {
completed_chunks completed_chunks
@ -386,7 +267,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
write.len().min(255), write.len().min(255),
Stop::Software, Stop::Software,
last_chunk_idx != 0, last_chunk_idx != 0,
&check_timeout, timeout,
) { ) {
if send_stop { if send_stop {
self.master_stop(); self.master_stop();
@ -396,14 +277,14 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
for (number, chunk) in write.chunks(255).enumerate() { for (number, chunk) in write.chunks(255).enumerate() {
if number != 0 { if number != 0 {
Self::master_continue(chunk.len(), number != last_chunk_idx, &check_timeout)?; Self::master_continue(chunk.len(), number != last_chunk_idx, timeout)?;
} }
for byte in chunk { for byte in chunk {
// Wait until we are allowed to send data // Wait until we are allowed to send data
// (START has been ACKed or last byte when // (START has been ACKed or last byte when
// through) // through)
if let Err(err) = self.wait_txe(&check_timeout) { if let Err(err) = self.wait_txe(timeout) {
if send_stop { if send_stop {
self.master_stop(); self.master_stop();
} }
@ -414,7 +295,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
} }
} }
// Wait until the write finishes // Wait until the write finishes
let result = self.wait_tc(&check_timeout); let result = self.wait_tc(timeout);
if send_stop { if send_stop {
self.master_stop(); self.master_stop();
} }
@ -427,7 +308,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
write: &[u8], write: &[u8],
first_slice: bool, first_slice: bool,
last_slice: bool, last_slice: bool,
check_timeout: impl Fn() -> Result<(), Error>, timeout: Timeout,
) -> Result<(), Error> ) -> Result<(), Error>
where where
TXDMA: crate::i2c::TxDma<T>, TXDMA: crate::i2c::TxDma<T>,
@ -473,10 +354,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
total_len.min(255), total_len.min(255),
Stop::Software, Stop::Software,
(total_len > 255) || !last_slice, (total_len > 255) || !last_slice,
&check_timeout, timeout,
)?; )?;
} else { } else {
Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, &check_timeout)?; Self::master_continue(total_len.min(255), (total_len > 255) || !last_slice, timeout)?;
T::regs().cr1().modify(|w| w.set_tcie(true)); T::regs().cr1().modify(|w| w.set_tcie(true));
} }
} else if !(isr.tcr() || isr.tc()) { } else if !(isr.tcr() || isr.tc()) {
@ -487,7 +368,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
} else { } else {
let last_piece = (remaining_len <= 255) && last_slice; let last_piece = (remaining_len <= 255) && last_slice;
if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) { if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, timeout) {
return Poll::Ready(Err(e)); return Poll::Ready(Err(e));
} }
T::regs().cr1().modify(|w| w.set_tcie(true)); T::regs().cr1().modify(|w| w.set_tcie(true));
@ -502,7 +383,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
if last_slice { if last_slice {
// This should be done already // This should be done already
self.wait_tc(&check_timeout)?; self.wait_tc(timeout)?;
self.master_stop(); self.master_stop();
} }
@ -516,7 +397,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
address: u8, address: u8,
buffer: &mut [u8], buffer: &mut [u8],
restart: bool, restart: bool,
check_timeout: impl Fn() -> Result<(), Error>, timeout: Timeout,
) -> Result<(), Error> ) -> Result<(), Error>
where where
RXDMA: crate::i2c::RxDma<T>, RXDMA: crate::i2c::RxDma<T>,
@ -558,7 +439,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
Stop::Software, Stop::Software,
total_len > 255, total_len > 255,
restart, restart,
&check_timeout, timeout,
)?; )?;
} else if !(isr.tcr() || isr.tc()) { } else if !(isr.tcr() || isr.tc()) {
// poll_fn was woken without an interrupt present // poll_fn was woken without an interrupt present
@ -568,7 +449,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
} else { } else {
let last_piece = remaining_len <= 255; let last_piece = remaining_len <= 255;
if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, &check_timeout) { if let Err(e) = Self::master_continue(remaining_len.min(255), !last_piece, timeout) {
return Poll::Ready(Err(e)); return Poll::Ready(Err(e));
} }
T::regs().cr1().modify(|w| w.set_tcie(true)); T::regs().cr1().modify(|w| w.set_tcie(true));
@ -582,7 +463,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
dma_transfer.await; dma_transfer.await;
// This should be done already // This should be done already
self.wait_tc(&check_timeout)?; self.wait_tc(timeout)?;
self.master_stop(); self.master_stop();
drop(on_drop); drop(on_drop);
@ -592,41 +473,31 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
// ========================= // =========================
// Async public API // Async public API
#[cfg(feature = "time")]
pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error>
where
TXDMA: crate::i2c::TxDma<T>,
{
if write.is_empty() {
self.write_internal(address, write, true, timeout_fn(self.timeout))
} else {
embassy_time::with_timeout(
self.timeout,
self.write_dma_internal(address, write, true, true, timeout_fn(self.timeout)),
)
.await
.unwrap_or(Err(Error::Timeout))
}
}
#[cfg(not(feature = "time"))] /// Write.
pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error>
where where
TXDMA: crate::i2c::TxDma<T>, TXDMA: crate::i2c::TxDma<T>,
{ {
let timeout = self.timeout();
if write.is_empty() { if write.is_empty() {
self.write_internal(address, write, true, no_timeout_fn()) self.write_internal(address, write, true, timeout)
} else { } else {
self.write_dma_internal(address, write, true, true, no_timeout_fn()) timeout
.with(self.write_dma_internal(address, write, true, true, timeout))
.await .await
} }
} }
#[cfg(feature = "time")] /// Write multiple buffers.
///
/// The buffers are concatenated in a single write transaction.
pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error>
where where
TXDMA: crate::i2c::TxDma<T>, TXDMA: crate::i2c::TxDma<T>,
{ {
let timeout = self.timeout();
if write.is_empty() { if write.is_empty() {
return Err(Error::ZeroLengthTransfer); return Err(Error::ZeroLengthTransfer);
} }
@ -638,123 +509,49 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
let next = iter.next(); let next = iter.next();
let is_last = next.is_none(); let is_last = next.is_none();
embassy_time::with_timeout( let fut = self.write_dma_internal(address, c, first, is_last, timeout);
self.timeout, timeout.with(fut).await?;
self.write_dma_internal(address, c, first, is_last, timeout_fn(self.timeout)),
)
.await
.unwrap_or(Err(Error::Timeout))?;
first = false; first = false;
current = next; current = next;
} }
Ok(()) Ok(())
} }
#[cfg(not(feature = "time"))] /// Read.
pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error>
where
TXDMA: crate::i2c::TxDma<T>,
{
if write.is_empty() {
return Err(Error::ZeroLengthTransfer);
}
let mut iter = write.iter();
let mut first = true;
let mut current = iter.next();
while let Some(c) = current {
let next = iter.next();
let is_last = next.is_none();
self.write_dma_internal(address, c, first, is_last, no_timeout_fn())
.await?;
first = false;
current = next;
}
Ok(())
}
#[cfg(feature = "time")]
pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error>
where where
RXDMA: crate::i2c::RxDma<T>, RXDMA: crate::i2c::RxDma<T>,
{ {
let timeout = self.timeout();
if buffer.is_empty() { if buffer.is_empty() {
self.read_internal(address, buffer, false, timeout_fn(self.timeout)) self.read_internal(address, buffer, false, timeout)
} else { } else {
embassy_time::with_timeout( let fut = self.read_dma_internal(address, buffer, false, timeout);
self.timeout, timeout.with(fut).await
self.read_dma_internal(address, buffer, false, timeout_fn(self.timeout)),
)
.await
.unwrap_or(Err(Error::Timeout))
} }
} }
#[cfg(not(feature = "time"))] /// Write, restart, read.
pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error>
where
RXDMA: crate::i2c::RxDma<T>,
{
if buffer.is_empty() {
self.read_internal(address, buffer, false, no_timeout_fn())
} else {
self.read_dma_internal(address, buffer, false, no_timeout_fn()).await
}
}
#[cfg(feature = "time")]
pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error>
where where
TXDMA: super::TxDma<T>, TXDMA: super::TxDma<T>,
RXDMA: super::RxDma<T>, RXDMA: super::RxDma<T>,
{ {
let start_instant = Instant::now(); let timeout = self.timeout();
let check_timeout = timeout_fn(self.timeout);
if write.is_empty() { if write.is_empty() {
self.write_internal(address, write, false, &check_timeout)?; self.write_internal(address, write, false, timeout)?;
} else { } else {
embassy_time::with_timeout( let fut = self.write_dma_internal(address, write, true, true, timeout);
self.timeout, timeout.with(fut).await?;
self.write_dma_internal(address, write, true, true, &check_timeout),
)
.await
.unwrap_or(Err(Error::Timeout))?;
}
let time_left_until_timeout = self.timeout - Instant::now().duration_since(start_instant);
if read.is_empty() {
self.read_internal(address, read, true, &check_timeout)?;
} else {
embassy_time::with_timeout(
time_left_until_timeout,
self.read_dma_internal(address, read, true, &check_timeout),
)
.await
.unwrap_or(Err(Error::Timeout))?;
}
Ok(())
}
#[cfg(not(feature = "time"))]
pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error>
where
TXDMA: super::TxDma<T>,
RXDMA: super::RxDma<T>,
{
let no_timeout = no_timeout_fn();
if write.is_empty() {
self.write_internal(address, write, false, &no_timeout)?;
} else {
self.write_dma_internal(address, write, true, true, &no_timeout).await?;
} }
if read.is_empty() { if read.is_empty() {
self.read_internal(address, read, true, &no_timeout)?; self.read_internal(address, read, true, timeout)?;
} else { } else {
self.read_dma_internal(address, read, true, &no_timeout).await?; let fut = self.read_dma_internal(address, read, true, timeout);
timeout.with(fut).await?;
} }
Ok(()) Ok(())
@ -763,105 +560,35 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
// ========================= // =========================
// Blocking public API // Blocking public API
#[cfg(feature = "time")] /// Blocking read.
pub fn blocking_read_timeout(&mut self, address: u8, read: &mut [u8], timeout: Duration) -> Result<(), Error> {
self.read_internal(address, read, false, timeout_fn(timeout))
// Automatic Stop
}
#[cfg(not(feature = "time"))]
pub fn blocking_read_timeout(
&mut self,
address: u8,
read: &mut [u8],
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
self.read_internal(address, read, false, check_timeout)
// Automatic Stop
}
#[cfg(feature = "time")]
pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> {
self.blocking_read_timeout(address, read, self.timeout) self.read_internal(address, read, false, self.timeout())
}
#[cfg(not(feature = "time"))]
pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> {
self.blocking_read_timeout(address, read, || Ok(()))
}
#[cfg(feature = "time")]
pub fn blocking_write_timeout(&mut self, address: u8, write: &[u8], timeout: Duration) -> Result<(), Error> {
self.write_internal(address, write, true, timeout_fn(timeout))
}
#[cfg(not(feature = "time"))]
pub fn blocking_write_timeout(
&mut self,
address: u8,
write: &[u8],
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
self.write_internal(address, write, true, check_timeout)
}
#[cfg(feature = "time")]
pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
self.blocking_write_timeout(address, write, self.timeout)
}
#[cfg(not(feature = "time"))]
pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
self.blocking_write_timeout(address, write, || Ok(()))
}
#[cfg(feature = "time")]
pub fn blocking_write_read_timeout(
&mut self,
address: u8,
write: &[u8],
read: &mut [u8],
timeout: Duration,
) -> Result<(), Error> {
let check_timeout = timeout_fn(timeout);
self.write_internal(address, write, false, &check_timeout)?;
self.read_internal(address, read, true, &check_timeout)
// Automatic Stop // Automatic Stop
} }
#[cfg(not(feature = "time"))] /// Blocking write.
pub fn blocking_write_read_timeout( pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
&mut self, self.write_internal(address, write, true, self.timeout())
address: u8, }
write: &[u8],
read: &mut [u8], /// Blocking write, restart, read.
check_timeout: impl Fn() -> Result<(), Error>, pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
) -> Result<(), Error> { let timeout = self.timeout();
self.write_internal(address, write, false, &check_timeout)?; self.write_internal(address, write, false, timeout)?;
self.read_internal(address, read, true, &check_timeout) self.read_internal(address, read, true, timeout)
// Automatic Stop // Automatic Stop
} }
#[cfg(feature = "time")] /// Blocking write multiple buffers.
pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { ///
self.blocking_write_read_timeout(address, write, read, self.timeout) /// The buffers are concatenated in a single write transaction.
} pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> {
#[cfg(not(feature = "time"))]
pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
self.blocking_write_read_timeout(address, write, read, || Ok(()))
}
fn blocking_write_vectored_with_timeout(
&mut self,
address: u8,
write: &[&[u8]],
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
if write.is_empty() { if write.is_empty() {
return Err(Error::ZeroLengthTransfer); return Err(Error::ZeroLengthTransfer);
} }
let timeout = self.timeout();
let first_length = write[0].len(); let first_length = write[0].len();
let last_slice_index = write.len() - 1; let last_slice_index = write.len() - 1;
@ -870,7 +597,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
first_length.min(255), first_length.min(255),
Stop::Software, Stop::Software,
(first_length > 255) || (last_slice_index != 0), (first_length > 255) || (last_slice_index != 0),
&check_timeout, timeout,
) { ) {
self.master_stop(); self.master_stop();
return Err(err); return Err(err);
@ -890,7 +617,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
if let Err(err) = Self::master_continue( if let Err(err) = Self::master_continue(
slice_len.min(255), slice_len.min(255),
(idx != last_slice_index) || (slice_len > 255), (idx != last_slice_index) || (slice_len > 255),
&check_timeout, timeout,
) { ) {
self.master_stop(); self.master_stop();
return Err(err); return Err(err);
@ -902,7 +629,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
if let Err(err) = Self::master_continue( if let Err(err) = Self::master_continue(
chunk.len(), chunk.len(),
(number != last_chunk_idx) || (idx != last_slice_index), (number != last_chunk_idx) || (idx != last_slice_index),
&check_timeout, timeout,
) { ) {
self.master_stop(); self.master_stop();
return Err(err); return Err(err);
@ -913,7 +640,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
// Wait until we are allowed to send data // Wait until we are allowed to send data
// (START has been ACKed or last byte when // (START has been ACKed or last byte when
// through) // through)
if let Err(err) = self.wait_txe(&check_timeout) { if let Err(err) = self.wait_txe(timeout) {
self.master_stop(); self.master_stop();
return Err(err); return Err(err);
} }
@ -925,41 +652,10 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
} }
} }
// Wait until the write finishes // Wait until the write finishes
let result = self.wait_tc(&check_timeout); let result = self.wait_tc(timeout);
self.master_stop(); self.master_stop();
result result
} }
#[cfg(feature = "time")]
pub fn blocking_write_vectored_timeout(
&mut self,
address: u8,
write: &[&[u8]],
timeout: Duration,
) -> Result<(), Error> {
let check_timeout = timeout_fn(timeout);
self.blocking_write_vectored_with_timeout(address, write, check_timeout)
}
#[cfg(not(feature = "time"))]
pub fn blocking_write_vectored_timeout(
&mut self,
address: u8,
write: &[&[u8]],
check_timeout: impl Fn() -> Result<(), Error>,
) -> Result<(), Error> {
self.blocking_write_vectored_with_timeout(address, write, check_timeout)
}
#[cfg(feature = "time")]
pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> {
self.blocking_write_vectored_timeout(address, write, self.timeout)
}
#[cfg(not(feature = "time"))]
pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> {
self.blocking_write_vectored_timeout(address, write, || Ok(()))
}
} }
impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> { impl<'d, T: Instance, TXDMA, RXDMA> Drop for I2c<'d, T, TXDMA, RXDMA> {