From 3b33cc46915f0b400a2a9dd87cfe51eca9f7e434 Mon Sep 17 00:00:00 2001 From: Andres Vahter Date: Fri, 10 Nov 2023 15:49:31 +0200 Subject: [PATCH 1/3] i2c: expose async api without needing time This exposes I2C async API without needing "time" feature. With "time" feature additional async API with timeouts is exposed. --- embassy-stm32/src/i2c/v2.rs | 207 ++++++++++++++++++++++++++++++------ 1 file changed, 175 insertions(+), 32 deletions(-) diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index fc6dcd6e..7049affe 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -1,21 +1,14 @@ use core::cmp; -#[cfg(feature = "time")] -use core::future::poll_fn; +use core::future::{poll_fn, Future}; use core::marker::PhantomData; -#[cfg(feature = "time")] use core::task::Poll; use embassy_embedded_hal::SetConfig; -#[cfg(feature = "time")] use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; -#[cfg(feature = "time")] -use embassy_time::{Duration, Instant}; -use crate::dma::NoDma; -#[cfg(feature = "time")] -use crate::dma::Transfer; +use crate::dma::{NoDma, Transfer}; use crate::gpio::sealed::AFType; use crate::gpio::Pull; use crate::i2c::{Error, Instance, SclPin, SdaPin}; @@ -24,6 +17,92 @@ use crate::pac::i2c; use crate::time::Hertz; use crate::{interrupt, Peripheral}; +/// # Async I2C Operations with Optional Timeouts +/// +/// This module provides compatibility for async I2C operations with timeout-based APIs, +/// even when the "time" feature is not enabled. In the absence of the "time" feature, +/// operations effectively never time out. +/// +/// ## Usage Scenario +/// This is particularly useful in scenarios such as when using RTIC, where a user might +/// have their own monotonic timer and thus choose not to enable the "time" feature. +/// In such cases, this module allows the use of async I2C APIs without actual timeout +/// handling. +/// +/// ## Functionality +/// - When the "time" feature is disabled, `Duration` and `Instant` types are provided +/// as dummy implementations, and timeout functions do not perform real timing but +/// simply mimic the required interfaces. +/// - When the "time" feature is enabled, `Duration` and `Instant` from the `embassy_time` +/// are used, and timeouts are handled as expected. +#[cfg(not(feature = "time"))] +mod dummy_time { + use core::ops::Sub; + + use super::{Error, Future}; + + #[derive(Copy, Clone)] + pub struct Duration; + + impl Duration { + pub fn dummy_duration() -> Duration { + Duration + } + } + + pub struct Instant; + + impl Instant { + pub fn now() -> Self { + Self + } + + pub fn duration_since(&self, _since: Instant) -> Duration { + Duration + } + } + + impl Sub for Duration { + type Output = Duration; + + fn sub(self, _rhs: Duration) -> Duration { + Duration + } + } + + /// Timeout that never times out. + pub fn timeout_fn(_timeout: Duration) -> impl Fn() -> Result<(), Error> { + move || Ok(()) + } + + /// This is compatible with `embassy_time::with_timeout` however it never times out. + pub async fn with_timeout(_timeout: Duration, fut: F) -> Result { + Ok(fut.await) + } +} + +#[cfg(not(feature = "time"))] +use dummy_time::{timeout_fn, with_timeout, Duration, Instant}; +#[cfg(feature = "time")] +use embassy_time::{Duration, Instant}; + +#[cfg(feature = "time")] +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(feature = "time")] +async fn with_timeout(timeout: Duration, fut: F) -> Result { + embassy_time::with_timeout(timeout, fut).await +} + /// Interrupt handler. pub struct InterruptHandler { _phantom: PhantomData, @@ -437,7 +516,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { result } - #[cfg(feature = "time")] async fn write_dma_internal( &mut self, address: u8, @@ -528,7 +606,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { Ok(()) } - #[cfg(feature = "time")] async fn read_dma_internal( &mut self, address: u8, @@ -616,18 +693,34 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { where TXDMA: crate::i2c::TxDma, { - self.write_timeout(address, write, self.timeout).await + self.write_timeout_internal(address, write, self.timeout).await + } + + #[cfg(not(feature = "time"))] + pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> + where + TXDMA: crate::i2c::TxDma, + { + self.write_timeout_internal(address, write, Duration::dummy_duration()) + .await } #[cfg(feature = "time")] pub async fn write_timeout(&mut self, address: u8, write: &[u8], timeout: Duration) -> Result<(), Error> + where + TXDMA: crate::i2c::TxDma, + { + self.write_timeout_internal(address, write, timeout).await + } + + async fn write_timeout_internal(&mut self, address: u8, write: &[u8], timeout: Duration) -> Result<(), Error> where TXDMA: crate::i2c::TxDma, { if write.is_empty() { self.write_internal(address, write, true, timeout_fn(timeout)) } else { - embassy_time::with_timeout( + with_timeout( timeout, self.write_dma_internal(address, write, true, true, timeout_fn(timeout)), ) @@ -641,11 +734,32 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { where TXDMA: crate::i2c::TxDma, { - self.write_vectored_timeout(address, write, self.timeout).await + self.write_vectored_timeout_internal(address, write, self.timeout).await + } + + #[cfg(not(feature = "time"))] + pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> + where + TXDMA: crate::i2c::TxDma, + { + self.write_vectored_timeout_internal(address, write, Duration::dummy_duration()) + .await } #[cfg(feature = "time")] pub async fn write_vectored_timeout(&mut self, address: u8, write: &[&[u8]], timeout: Duration) -> Result<(), Error> + where + TXDMA: crate::i2c::TxDma, + { + self.write_vectored_timeout_internal(address, write, timeout).await + } + + async fn write_vectored_timeout_internal( + &mut self, + address: u8, + write: &[&[u8]], + timeout: Duration, + ) -> Result<(), Error> where TXDMA: crate::i2c::TxDma, { @@ -660,7 +774,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { let next = iter.next(); let is_last = next.is_none(); - embassy_time::with_timeout( + with_timeout( timeout, self.write_dma_internal(address, c, first, is_last, timeout_fn(timeout)), ) @@ -677,18 +791,34 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { where RXDMA: crate::i2c::RxDma, { - self.read_timeout(address, buffer, self.timeout).await + self.read_timeout_internal(address, buffer, self.timeout).await + } + + #[cfg(not(feature = "time"))] + pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> + where + RXDMA: crate::i2c::RxDma, + { + self.read_timeout_internal(address, buffer, Duration::dummy_duration()) + .await } #[cfg(feature = "time")] pub async fn read_timeout(&mut self, address: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error> + where + RXDMA: crate::i2c::RxDma, + { + self.read_timeout_internal(address, buffer, timeout).await + } + + async fn read_timeout_internal(&mut self, address: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error> where RXDMA: crate::i2c::RxDma, { if buffer.is_empty() { self.read_internal(address, buffer, false, timeout_fn(timeout)) } else { - embassy_time::with_timeout( + with_timeout( timeout, self.read_dma_internal(address, buffer, false, timeout_fn(timeout)), ) @@ -703,7 +833,18 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { TXDMA: super::TxDma, RXDMA: super::RxDma, { - self.write_read_timeout(address, write, read, self.timeout).await + self.write_read_timeout_internal(address, write, read, self.timeout) + .await + } + + #[cfg(not(feature = "time"))] + pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> + where + TXDMA: super::TxDma, + RXDMA: super::RxDma, + { + self.write_read_timeout_internal(address, write, read, Duration::dummy_duration()) + .await } #[cfg(feature = "time")] @@ -714,6 +855,20 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { read: &mut [u8], timeout: Duration, ) -> Result<(), Error> + where + TXDMA: super::TxDma, + RXDMA: super::RxDma, + { + self.write_read_timeout_internal(address, write, read, timeout).await + } + + async fn write_read_timeout_internal( + &mut self, + address: u8, + write: &[u8], + read: &mut [u8], + timeout: Duration, + ) -> Result<(), Error> where TXDMA: super::TxDma, RXDMA: super::RxDma, @@ -723,7 +878,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { if write.is_empty() { self.write_internal(address, write, false, &check_timeout)?; } else { - embassy_time::with_timeout( + with_timeout( timeout, self.write_dma_internal(address, write, true, true, &check_timeout), ) @@ -736,7 +891,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { if read.is_empty() { self.read_internal(address, read, true, &check_timeout)?; } else { - embassy_time::with_timeout( + with_timeout( time_left_until_timeout, self.read_dma_internal(address, read, true, &check_timeout), ) @@ -1201,15 +1356,3 @@ impl<'d, T: Instance> SetConfig for I2c<'d, T> { Ok(()) } } - -#[cfg(feature = "time")] -fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> { - let deadline = Instant::now() + timeout; - move || { - if Instant::now() > deadline { - Err(Error::Timeout) - } else { - Ok(()) - } - } -} From 6c42885d4a072b7fa8662062ff4073063d8bd2ad Mon Sep 17 00:00:00 2001 From: Andres Vahter Date: Sat, 11 Nov 2023 14:05:58 +0200 Subject: [PATCH 2/3] stm32 i2c: remove pub _timeout api --- embassy-stm32/src/i2c/v2.rs | 156 +++--------------------------------- 1 file changed, 13 insertions(+), 143 deletions(-) diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 7049affe..54d2fe6e 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -162,7 +162,6 @@ pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { tx_dma: PeripheralRef<'d, TXDMA>, #[allow(dead_code)] rx_dma: PeripheralRef<'d, RXDMA>, - #[cfg(feature = "time")] timeout: Duration, } @@ -226,6 +225,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { rx_dma, #[cfg(feature = "time")] timeout: config.transaction_timeout, + #[cfg(not(feature = "time"))] + timeout: Duration::dummy_duration(), } } @@ -339,21 +340,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { } fn flush_txdr(&self) { - //if $i2c.isr.read().txis().bit_is_set() { - //$i2c.txdr.write(|w| w.txdata().bits(0)); - //} - if T::regs().isr().read().txis() { T::regs().txdr().write(|w| w.set_txdata(0)); } if !T::regs().isr().read().txe() { T::regs().isr().modify(|w| w.set_txe(true)) } - - // If TXDR is not flagged as empty, write 1 to flush it - //if $i2c.isr.read().txe().is_not_empty() { - //$i2c.isr.write(|w| w.txe().set_bit()); - //} } fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { @@ -687,79 +679,23 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { // ========================= // Async public API - - #[cfg(feature = "time")] pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> - where - TXDMA: crate::i2c::TxDma, - { - self.write_timeout_internal(address, write, self.timeout).await - } - - #[cfg(not(feature = "time"))] - pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> - where - TXDMA: crate::i2c::TxDma, - { - self.write_timeout_internal(address, write, Duration::dummy_duration()) - .await - } - - #[cfg(feature = "time")] - pub async fn write_timeout(&mut self, address: u8, write: &[u8], timeout: Duration) -> Result<(), Error> - where - TXDMA: crate::i2c::TxDma, - { - self.write_timeout_internal(address, write, timeout).await - } - - async fn write_timeout_internal(&mut self, address: u8, write: &[u8], timeout: Duration) -> Result<(), Error> where TXDMA: crate::i2c::TxDma, { if write.is_empty() { - self.write_internal(address, write, true, timeout_fn(timeout)) + self.write_internal(address, write, true, timeout_fn(self.timeout)) } else { with_timeout( - timeout, - self.write_dma_internal(address, write, true, true, timeout_fn(timeout)), + self.timeout, + self.write_dma_internal(address, write, true, true, timeout_fn(self.timeout)), ) .await .unwrap_or(Err(Error::Timeout)) } } - #[cfg(feature = "time")] pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> - where - TXDMA: crate::i2c::TxDma, - { - self.write_vectored_timeout_internal(address, write, self.timeout).await - } - - #[cfg(not(feature = "time"))] - pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> - where - TXDMA: crate::i2c::TxDma, - { - self.write_vectored_timeout_internal(address, write, Duration::dummy_duration()) - .await - } - - #[cfg(feature = "time")] - pub async fn write_vectored_timeout(&mut self, address: u8, write: &[&[u8]], timeout: Duration) -> Result<(), Error> - where - TXDMA: crate::i2c::TxDma, - { - self.write_vectored_timeout_internal(address, write, timeout).await - } - - async fn write_vectored_timeout_internal( - &mut self, - address: u8, - write: &[&[u8]], - timeout: Duration, - ) -> Result<(), Error> where TXDMA: crate::i2c::TxDma, { @@ -775,8 +711,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { let is_last = next.is_none(); with_timeout( - timeout, - self.write_dma_internal(address, c, first, is_last, timeout_fn(timeout)), + self.timeout, + self.write_dma_internal(address, c, first, is_last, timeout_fn(self.timeout)), ) .await .unwrap_or(Err(Error::Timeout))?; @@ -786,107 +722,41 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { Ok(()) } - #[cfg(feature = "time")] pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> - where - RXDMA: crate::i2c::RxDma, - { - self.read_timeout_internal(address, buffer, self.timeout).await - } - - #[cfg(not(feature = "time"))] - pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> - where - RXDMA: crate::i2c::RxDma, - { - self.read_timeout_internal(address, buffer, Duration::dummy_duration()) - .await - } - - #[cfg(feature = "time")] - pub async fn read_timeout(&mut self, address: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error> - where - RXDMA: crate::i2c::RxDma, - { - self.read_timeout_internal(address, buffer, timeout).await - } - - async fn read_timeout_internal(&mut self, address: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error> where RXDMA: crate::i2c::RxDma, { if buffer.is_empty() { - self.read_internal(address, buffer, false, timeout_fn(timeout)) + self.read_internal(address, buffer, false, timeout_fn(self.timeout)) } else { with_timeout( - timeout, - self.read_dma_internal(address, buffer, false, timeout_fn(timeout)), + self.timeout, + self.read_dma_internal(address, buffer, false, timeout_fn(self.timeout)), ) .await .unwrap_or(Err(Error::Timeout)) } } - #[cfg(feature = "time")] pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> - where - TXDMA: super::TxDma, - RXDMA: super::RxDma, - { - self.write_read_timeout_internal(address, write, read, self.timeout) - .await - } - - #[cfg(not(feature = "time"))] - pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> - where - TXDMA: super::TxDma, - RXDMA: super::RxDma, - { - self.write_read_timeout_internal(address, write, read, Duration::dummy_duration()) - .await - } - - #[cfg(feature = "time")] - pub async fn write_read_timeout( - &mut self, - address: u8, - write: &[u8], - read: &mut [u8], - timeout: Duration, - ) -> Result<(), Error> - where - TXDMA: super::TxDma, - RXDMA: super::RxDma, - { - self.write_read_timeout_internal(address, write, read, timeout).await - } - - async fn write_read_timeout_internal( - &mut self, - address: u8, - write: &[u8], - read: &mut [u8], - timeout: Duration, - ) -> Result<(), Error> where TXDMA: super::TxDma, RXDMA: super::RxDma, { let start_instant = Instant::now(); - let check_timeout = timeout_fn(timeout); + let check_timeout = timeout_fn(self.timeout); if write.is_empty() { self.write_internal(address, write, false, &check_timeout)?; } else { with_timeout( - timeout, + self.timeout, self.write_dma_internal(address, write, true, true, &check_timeout), ) .await .unwrap_or(Err(Error::Timeout))?; } - let time_left_until_timeout = timeout - Instant::now().duration_since(start_instant); + 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)?; From 0f2208c0af8b89d91368c04ead9f84df664951e6 Mon Sep 17 00:00:00 2001 From: Andres Vahter Date: Sat, 11 Nov 2023 14:29:24 +0200 Subject: [PATCH 3/3] stm32 i2c: remove mod dummy_time --- embassy-stm32/src/i2c/v2.rs | 167 +++++++++++++++++++----------------- 1 file changed, 87 insertions(+), 80 deletions(-) diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 54d2fe6e..062a6225 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -1,5 +1,5 @@ use core::cmp; -use core::future::{poll_fn, Future}; +use core::future::poll_fn; use core::marker::PhantomData; use core::task::Poll; @@ -7,6 +7,8 @@ use embassy_embedded_hal::SetConfig; use embassy_hal_internal::drop::OnDrop; use embassy_hal_internal::{into_ref, PeripheralRef}; use embassy_sync::waitqueue::AtomicWaker; +#[cfg(feature = "time")] +use embassy_time::{Duration, Instant}; use crate::dma::{NoDma, Transfer}; use crate::gpio::sealed::AFType; @@ -17,75 +19,6 @@ use crate::pac::i2c; use crate::time::Hertz; use crate::{interrupt, Peripheral}; -/// # Async I2C Operations with Optional Timeouts -/// -/// This module provides compatibility for async I2C operations with timeout-based APIs, -/// even when the "time" feature is not enabled. In the absence of the "time" feature, -/// operations effectively never time out. -/// -/// ## Usage Scenario -/// This is particularly useful in scenarios such as when using RTIC, where a user might -/// have their own monotonic timer and thus choose not to enable the "time" feature. -/// In such cases, this module allows the use of async I2C APIs without actual timeout -/// handling. -/// -/// ## Functionality -/// - When the "time" feature is disabled, `Duration` and `Instant` types are provided -/// as dummy implementations, and timeout functions do not perform real timing but -/// simply mimic the required interfaces. -/// - When the "time" feature is enabled, `Duration` and `Instant` from the `embassy_time` -/// are used, and timeouts are handled as expected. -#[cfg(not(feature = "time"))] -mod dummy_time { - use core::ops::Sub; - - use super::{Error, Future}; - - #[derive(Copy, Clone)] - pub struct Duration; - - impl Duration { - pub fn dummy_duration() -> Duration { - Duration - } - } - - pub struct Instant; - - impl Instant { - pub fn now() -> Self { - Self - } - - pub fn duration_since(&self, _since: Instant) -> Duration { - Duration - } - } - - impl Sub for Duration { - type Output = Duration; - - fn sub(self, _rhs: Duration) -> Duration { - Duration - } - } - - /// Timeout that never times out. - pub fn timeout_fn(_timeout: Duration) -> impl Fn() -> Result<(), Error> { - move || Ok(()) - } - - /// This is compatible with `embassy_time::with_timeout` however it never times out. - pub async fn with_timeout(_timeout: Duration, fut: F) -> Result { - Ok(fut.await) - } -} - -#[cfg(not(feature = "time"))] -use dummy_time::{timeout_fn, with_timeout, Duration, Instant}; -#[cfg(feature = "time")] -use embassy_time::{Duration, Instant}; - #[cfg(feature = "time")] fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> { let deadline = Instant::now() + timeout; @@ -98,9 +31,9 @@ fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> { } } -#[cfg(feature = "time")] -async fn with_timeout(timeout: Duration, fut: F) -> Result { - embassy_time::with_timeout(timeout, fut).await +#[cfg(not(feature = "time"))] +pub fn no_timeout_fn() -> impl Fn() -> Result<(), Error> { + move || Ok(()) } /// Interrupt handler. @@ -162,6 +95,7 @@ pub struct I2c<'d, T: Instance, TXDMA = NoDma, RXDMA = NoDma> { tx_dma: PeripheralRef<'d, TXDMA>, #[allow(dead_code)] rx_dma: PeripheralRef<'d, RXDMA>, + #[cfg(feature = "time")] timeout: Duration, } @@ -225,8 +159,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { rx_dma, #[cfg(feature = "time")] timeout: config.transaction_timeout, - #[cfg(not(feature = "time"))] - timeout: Duration::dummy_duration(), } } @@ -679,6 +611,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { // ========================= // Async public API + #[cfg(feature = "time")] pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> where TXDMA: crate::i2c::TxDma, @@ -686,7 +619,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { if write.is_empty() { self.write_internal(address, write, true, timeout_fn(self.timeout)) } else { - with_timeout( + embassy_time::with_timeout( self.timeout, self.write_dma_internal(address, write, true, true, timeout_fn(self.timeout)), ) @@ -695,6 +628,20 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { } } + #[cfg(not(feature = "time"))] + pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> + where + TXDMA: crate::i2c::TxDma, + { + if write.is_empty() { + self.write_internal(address, write, true, no_timeout_fn()) + } else { + self.write_dma_internal(address, write, true, true, no_timeout_fn()) + .await + } + } + + #[cfg(feature = "time")] pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> where TXDMA: crate::i2c::TxDma, @@ -710,7 +657,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { let next = iter.next(); let is_last = next.is_none(); - with_timeout( + embassy_time::with_timeout( self.timeout, self.write_dma_internal(address, c, first, is_last, timeout_fn(self.timeout)), ) @@ -722,6 +669,31 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { Ok(()) } + #[cfg(not(feature = "time"))] + pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> + where + TXDMA: crate::i2c::TxDma, + { + 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> where RXDMA: crate::i2c::RxDma, @@ -729,7 +701,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { if buffer.is_empty() { self.read_internal(address, buffer, false, timeout_fn(self.timeout)) } else { - with_timeout( + embassy_time::with_timeout( self.timeout, self.read_dma_internal(address, buffer, false, timeout_fn(self.timeout)), ) @@ -738,6 +710,19 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { } } + #[cfg(not(feature = "time"))] + pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> + where + RXDMA: crate::i2c::RxDma, + { + 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> where TXDMA: super::TxDma, @@ -748,7 +733,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { if write.is_empty() { self.write_internal(address, write, false, &check_timeout)?; } else { - with_timeout( + embassy_time::with_timeout( self.timeout, self.write_dma_internal(address, write, true, true, &check_timeout), ) @@ -761,7 +746,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { if read.is_empty() { self.read_internal(address, read, true, &check_timeout)?; } else { - with_timeout( + embassy_time::with_timeout( time_left_until_timeout, self.read_dma_internal(address, read, true, &check_timeout), ) @@ -772,6 +757,28 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { 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, + RXDMA: super::RxDma, + { + 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() { + self.read_internal(address, read, true, &no_timeout)?; + } else { + self.read_dma_internal(address, read, true, &no_timeout).await?; + } + + Ok(()) + } + // ========================= // Blocking public API