diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 3303b9f4b..82e28b3ff 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -162,19 +162,32 @@ pub enum SendStatus { LeftoverBytes(usize), } +struct I2CDropGuard<'d> { + info: &'static Info, + scl: Option>, + sda: Option>, +} +impl<'d> Drop for I2CDropGuard<'d> { + fn drop(&mut self) { + self.scl.as_ref().map(|x| x.set_as_disconnected()); + self.sda.as_ref().map(|x| x.set_as_disconnected()); + + self.info.rcc.disable(); + } +} + /// I2C driver. pub struct I2c<'d, M: Mode, IM: MasterMode> { info: &'static Info, state: &'static State, kernel_clock: Hertz, - scl: Option>, - sda: Option>, tx_dma: Option>, rx_dma: Option>, #[cfg(feature = "time")] timeout: Duration, _phantom: PhantomData, _phantom2: PhantomData, + drop_guard: I2CDropGuard<'d>, } impl<'d> I2c<'d, Async, Master> { @@ -242,14 +255,17 @@ impl<'d, M: Mode> I2c<'d, M, Master> { info: T::info(), state: T::state(), kernel_clock: T::frequency(), - scl, - sda, tx_dma, rx_dma, #[cfg(feature = "time")] timeout: config.timeout, _phantom: PhantomData, _phantom2: PhantomData, + drop_guard: I2CDropGuard { + info: T::info(), + scl, + sda, + }, }; this.enable_and_init(freq, config); @@ -271,15 +287,6 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { } } -impl<'d, M: Mode, IM: MasterMode> Drop for I2c<'d, M, IM> { - fn drop(&mut self) { - self.scl.as_ref().map(|x| x.set_as_disconnected()); - self.sda.as_ref().map(|x| x.set_as_disconnected()); - - self.info.rcc.disable() - } -} - #[derive(Copy, Clone)] struct Timeout { #[cfg(feature = "time")] diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 531358efa..a90bdd551 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -47,6 +47,8 @@ pub(crate) unsafe fn on_interrupt() { critical_section::with(|_| { regs.cr1().modify(|w| { w.set_addrie(false); + w.set_stopie(false); + w.set_tcie(false); // The flag can only be cleared by writting to nbytes, we won't do that here, so disable // the interrupt w.set_tcie(false); @@ -725,14 +727,13 @@ impl<'d, M: Mode> I2c<'d, M, Master> { info: self.info, state: self.state, kernel_clock: self.kernel_clock, - scl: self.scl.take(), - sda: self.sda.take(), tx_dma: self.tx_dma.take(), rx_dma: self.rx_dma.take(), #[cfg(feature = "time")] timeout: self.timeout, _phantom: PhantomData, _phantom2: PhantomData, + drop_guard: self.drop_guard, }; slave.init_slave(slave_addr_config); slave @@ -930,6 +931,8 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { impl<'d> I2c<'d, Async, MultiMaster> { /// Respond to a receive command. + /// + /// Returns the total number of bytes received. pub async fn respond_to_receive(&mut self, buffer: &mut [u8]) -> Result { let timeout = self.timeout(); timeout.with(self.read_dma_internal_slave(buffer, timeout)).await @@ -942,6 +945,8 @@ impl<'d> I2c<'d, Async, MultiMaster> { } // for data reception in slave mode + // + // returns the total number of bytes received async fn read_dma_internal_slave(&mut self, buffer: &mut [u8], timeout: Timeout) -> Result { let total_len = buffer.len(); let mut remaining_len = total_len; @@ -988,7 +993,7 @@ impl<'d> I2c<'d, Async, MultiMaster> { Poll::Pending } else if isr.stopf() { regs.icr().write(|reg| reg.set_stopcf(true)); - let poll = Poll::Ready(Ok(remaining_len)); + let poll = Poll::Ready(Ok(total_len - remaining_len)); poll } else { Poll::Pending