use core::cmp; use core::future::poll_fn; use core::task::Poll; use config::{Address, OA2, OwnAddresses}; use embassy_embedded_hal::SetConfig; use embassy_hal_internal::drop::OnDrop; use embedded_hal_1::i2c::Operation; use mode::{Master, MultiMaster}; use stm32_metapac::i2c::vals::{Addmode, Oamsk}; use super::*; use crate::pac::i2c; impl From for Oamsk { fn from(value: AddrMask) -> Self { match value { AddrMask::NOMASK => Oamsk::NO_MASK, AddrMask::MASK1 => Oamsk::MASK1, AddrMask::MASK2 => Oamsk::MASK2, AddrMask::MASK3 => Oamsk::MASK3, AddrMask::MASK4 => Oamsk::MASK4, AddrMask::MASK5 => Oamsk::MASK5, AddrMask::MASK6 => Oamsk::MASK6, AddrMask::MASK7 => Oamsk::MASK7, } } } impl Address { pub(super) fn add_mode(&self) -> stm32_metapac::i2c::vals::Addmode { match self { Address::SevenBit(_) => stm32_metapac::i2c::vals::Addmode::BIT7, Address::TenBit(_) => stm32_metapac::i2c::vals::Addmode::BIT10, } } } enum ReceiveResult { DataAvailable, StopReceived, NewStart, } fn debug_print_interrupts(isr: stm32_metapac::i2c::regs::Isr) { if isr.tcr() { trace!("interrupt: tcr"); } if isr.tc() { trace!("interrupt: tc"); } if isr.addr() { trace!("interrupt: addr"); } if isr.stopf() { trace!("interrupt: stopf"); } if isr.nackf() { trace!("interrupt: nackf"); } if isr.berr() { trace!("interrupt: berr"); } if isr.arlo() { trace!("interrupt: arlo"); } if isr.ovr() { trace!("interrupt: ovr"); } } pub(crate) unsafe fn on_interrupt() { // restore the clocks to their last configured state as // much is lost in STOP modes #[cfg(all(feature = "low-power", stm32wlex))] crate::low_power::Executor::on_wakeup_irq_or_event(); let regs = T::info().regs; let isr = regs.isr().read(); if isr.tcr() || isr.tc() || isr.addr() || isr.stopf() || isr.nackf() || isr.berr() || isr.arlo() || isr.ovr() { debug_print_interrupts(isr); T::state().waker.wake(); } critical_section::with(|_| { regs.cr1().modify(|w| { w.set_addrie(false); w.set_stopie(false); // The flag can only be cleared by writting to nbytes, we won't do that here w.set_tcie(false); // Error flags are to be read in the routines, so we also don't clear them here w.set_nackie(false); w.set_errie(false); }); }); } impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { #[inline] fn to_reload(reload: bool) -> i2c::vals::Reload { if reload { i2c::vals::Reload::NOT_COMPLETED } else { i2c::vals::Reload::COMPLETED } } /// Calculate total bytes in a group of operations #[inline] fn total_operation_bytes(operations: &[Operation<'_>]) -> usize { operations .iter() .map(|op| match op { Operation::Write(buf) => buf.len(), Operation::Read(buf) => buf.len(), }) .sum() } pub(crate) fn init(&mut self, config: Config) { self.info.regs.cr1().modify(|reg| { reg.set_pe(false); reg.set_anfoff(false); }); let timings = Timings::new(self.kernel_clock, config.frequency.into()); self.info.regs.timingr().write(|reg| { reg.set_presc(timings.prescale); reg.set_scll(timings.scll); reg.set_sclh(timings.sclh); reg.set_sdadel(timings.sdadel); reg.set_scldel(timings.scldel); }); self.info.regs.cr1().modify(|reg| { reg.set_pe(true); }); } fn master_stop(&mut self) { self.info.regs.cr2().write(|w| w.set_stop(true)); } fn master_read( info: &'static Info, address: Address, length: usize, stop: Stop, reload: bool, restart: bool, timeout: Timeout, ) -> Result<(), Error> { assert!(length < 256); if !restart { // Wait for any previous address sequence to end // automatically. This could be up to 50% of a bus // cycle (ie. up to 0.5/freq) while info.regs.cr2().read().start() { timeout.check()?; } } // Set START and prepare to receive bytes into // `buffer`. The START bit can be set even if the bus // is BUSY or I2C is in slave mode. info.regs.cr2().modify(|w| { w.set_sadd(address.addr() << 1); w.set_add10(address.add_mode()); w.set_dir(i2c::vals::Dir::READ); w.set_nbytes(length as u8); w.set_start(true); w.set_autoend(stop.autoend()); w.set_reload(Self::to_reload(reload)); }); Ok(()) } fn master_write( info: &'static Info, address: Address, length: usize, stop: Stop, reload: bool, restart: bool, timeout: Timeout, ) -> Result<(), Error> { assert!(length < 256); if !restart { // Wait for any previous address sequence to end // automatically. This could be up to 50% of a bus // cycle (ie. up to 0.5/freq) while info.regs.cr2().read().start() { timeout.check()?; } // Wait for the bus to be free while info.regs.isr().read().busy() { timeout.check()?; } } // Set START and prepare to send `bytes`. The // START bit can be set even if the bus is BUSY or // I2C is in slave mode. info.regs.cr2().modify(|w| { w.set_sadd(address.addr() << 1); w.set_add10(address.add_mode()); w.set_dir(i2c::vals::Dir::WRITE); w.set_nbytes(length as u8); w.set_start(true); w.set_autoend(stop.autoend()); w.set_reload(Self::to_reload(reload)); }); Ok(()) } fn reload( info: &'static Info, length: usize, will_reload: bool, stop: Stop, timeout: Timeout, ) -> Result<(), Error> { assert!(length < 256 && length > 0); // Wait for either TCR (Transfer Complete Reload) or TC (Transfer Complete) // TCR occurs when RELOAD=1, TC occurs when RELOAD=0 // Both indicate the peripheral is ready for the next transfer loop { let isr = info.regs.isr().read(); if isr.tcr() || isr.tc() { break; } timeout.check()?; } info.regs.cr2().modify(|w| { w.set_nbytes(length as u8); w.set_reload(Self::to_reload(will_reload)); w.set_autoend(stop.autoend()); }); Ok(()) } fn flush_txdr(&self) { if self.info.regs.isr().read().txis() { trace!("Flush TXDATA with zeroes"); self.info.regs.txdr().modify(|w| w.set_txdata(0)); } if !self.info.regs.isr().read().txe() { trace!("Flush TXDR"); self.info.regs.isr().modify(|w| w.set_txe(true)) } } fn error_occurred(&self, isr: &i2c::regs::Isr, timeout: Timeout) -> Result<(), Error> { if isr.nackf() { trace!("NACK triggered."); self.info.regs.icr().modify(|reg| reg.set_nackcf(true)); // NACK should be followed by STOP if let Ok(()) = self.wait_stop(timeout) { trace!("Got STOP after NACK, clearing flag."); self.info.regs.icr().modify(|reg| reg.set_stopcf(true)); } self.flush_txdr(); return Err(Error::Nack); } else if isr.berr() { trace!("BERR triggered."); self.info.regs.icr().modify(|reg| reg.set_berrcf(true)); self.flush_txdr(); return Err(Error::Bus); } else if isr.arlo() { trace!("ARLO triggered."); self.info.regs.icr().modify(|reg| reg.set_arlocf(true)); self.flush_txdr(); return Err(Error::Arbitration); } else if isr.ovr() { trace!("OVR triggered."); self.info.regs.icr().modify(|reg| reg.set_ovrcf(true)); return Err(Error::Overrun); } return Ok(()); } fn wait_txis(&self, timeout: Timeout) -> Result<(), Error> { let mut first_loop = true; loop { let isr = self.info.regs.isr().read(); self.error_occurred(&isr, timeout)?; if isr.txis() { trace!("TXIS"); return Ok(()); } { if first_loop { trace!("Waiting for TXIS..."); first_loop = false; } } timeout.check()?; } } fn wait_stop_or_err(&self, timeout: Timeout) -> Result<(), Error> { loop { let isr = self.info.regs.isr().read(); self.error_occurred(&isr, timeout)?; if isr.stopf() { trace!("STOP triggered."); self.info.regs.icr().modify(|reg| reg.set_stopcf(true)); return Ok(()); } timeout.check()?; } } fn wait_stop(&self, timeout: Timeout) -> Result<(), Error> { loop { let isr = self.info.regs.isr().read(); if isr.stopf() { trace!("STOP triggered."); self.info.regs.icr().modify(|reg| reg.set_stopcf(true)); return Ok(()); } timeout.check()?; } } fn wait_af(&self, timeout: Timeout) -> Result<(), Error> { loop { let isr = self.info.regs.isr().read(); if isr.nackf() { trace!("AF triggered."); self.info.regs.icr().modify(|reg| reg.set_nackcf(true)); return Ok(()); } timeout.check()?; } } fn wait_rxne(&self, timeout: Timeout) -> Result { let mut first_loop = true; loop { let isr = self.info.regs.isr().read(); self.error_occurred(&isr, timeout)?; if isr.stopf() { trace!("STOP when waiting for RXNE."); if self.info.regs.isr().read().rxne() { trace!("Data received with STOP."); return Ok(ReceiveResult::DataAvailable); } trace!("STOP triggered without data."); return Ok(ReceiveResult::StopReceived); } else if isr.rxne() { trace!("RXNE."); return Ok(ReceiveResult::DataAvailable); } else if isr.addr() { // Another addr event received, which means START was sent again // which happens when accessing memory registers (common i2c interface design) // e.g. master sends: START, write 1 byte (register index), START, read N bytes (until NACK) // Possible to receive this flag at the same time as rxne, so check rxne first trace!("START when waiting for RXNE. Ending receive loop."); // Return without clearing ADDR so `listen` can catch it return Ok(ReceiveResult::NewStart); } { if first_loop { trace!("Waiting for RXNE..."); first_loop = false; } } timeout.check()?; } } fn wait_tc(&self, timeout: Timeout) -> Result<(), Error> { loop { let isr = self.info.regs.isr().read(); self.error_occurred(&isr, timeout)?; // Wait for either TC or TCR - both indicate transfer completion // TCR occurs when RELOAD=1, TC occurs when RELOAD=0 if isr.tc() || isr.tcr() { return Ok(()); } timeout.check()?; } } fn read_internal( &mut self, address: Address, read: &mut [u8], restart: bool, timeout: Timeout, ) -> Result<(), Error> { let completed_chunks = read.len() / 255; let total_chunks = if completed_chunks * 255 == read.len() { completed_chunks } else { completed_chunks + 1 }; let last_chunk_idx = total_chunks.saturating_sub(1); Self::master_read( self.info, address, read.len().min(255), Stop::Automatic, last_chunk_idx != 0, // reload restart, timeout, )?; for (number, chunk) in read.chunks_mut(255).enumerate() { if number != 0 { Self::reload( self.info, chunk.len(), number != last_chunk_idx, Stop::Automatic, timeout, )?; } for byte in chunk { // Wait until we have received something self.wait_rxne(timeout)?; *byte = self.info.regs.rxdr().read().rxdata(); } } self.wait_stop(timeout)?; Ok(()) } fn write_internal( &mut self, address: Address, write: &[u8], send_stop: bool, timeout: Timeout, ) -> Result<(), Error> { let completed_chunks = write.len() / 255; let total_chunks = if completed_chunks * 255 == write.len() { completed_chunks } else { completed_chunks + 1 }; let last_chunk_idx = total_chunks.saturating_sub(1); // I2C start // // ST SAD+W if let Err(err) = Self::master_write( self.info, address, write.len().min(255), Stop::Software, last_chunk_idx != 0, false, // restart timeout, ) { if send_stop { self.master_stop(); } return Err(err); } for (number, chunk) in write.chunks(255).enumerate() { if number != 0 { Self::reload( self.info, chunk.len(), number != last_chunk_idx, Stop::Software, timeout, )?; } for byte in chunk { // Wait until we are allowed to send data // (START has been ACKed or last byte when // through) if let Err(err) = self.wait_txis(timeout) { if send_stop && err != Error::Nack { // STOP is sent automatically if a NACK was received self.master_stop(); } return Err(err); } self.info.regs.txdr().write(|w| w.set_txdata(*byte)); } } // Wait until the write finishes self.wait_tc(timeout)?; if send_stop { self.master_stop(); self.wait_stop(timeout)?; } Ok(()) } // ========================= // Blocking public API /// Blocking read. pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { self.read_internal(address.into(), read, false, self.timeout()) // Automatic Stop } /// Blocking write. pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { self.write_internal(address.into(), write, true, self.timeout()) } /// Blocking write, restart, read. pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { let timeout = self.timeout(); self.write_internal(address.into(), write, false, timeout)?; self.read_internal(address.into(), read, true, timeout) // Automatic Stop } /// Blocking transaction with operations. /// /// Consecutive operations of same type are merged. See [transaction contract] for details. /// /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { if operations.is_empty() { return Err(Error::ZeroLengthTransfer); } let address = addr.into(); let timeout = self.timeout(); // Group consecutive operations of the same type let mut op_idx = 0; let mut is_first_group = true; while op_idx < operations.len() { // Determine the type of current group and find all consecutive operations of same type let is_read = matches!(operations[op_idx], Operation::Read(_)); let group_start = op_idx; // Find end of this group (consecutive operations of same type) while op_idx < operations.len() && matches!(operations[op_idx], Operation::Read(_)) == is_read { op_idx += 1; } let group_end = op_idx; let is_last_group = op_idx >= operations.len(); // Execute this group of operations if is_read { self.execute_read_group( address, &mut operations[group_start..group_end], is_first_group, is_last_group, timeout, )?; } else { self.execute_write_group( address, &operations[group_start..group_end], is_first_group, is_last_group, timeout, )?; } is_first_group = false; } Ok(()) } fn execute_write_group( &mut self, address: Address, operations: &[Operation<'_>], is_first_group: bool, is_last_group: bool, timeout: Timeout, ) -> Result<(), Error> { // Calculate total bytes across all operations in this group let total_bytes = Self::total_operation_bytes(operations); if total_bytes == 0 { // Handle empty write group - just send address if is_first_group { Self::master_write(self.info, address, 0, Stop::Software, false, !is_first_group, timeout)?; } if is_last_group { self.master_stop(); } return Ok(()); } let mut total_remaining = total_bytes; let mut first_chunk = true; for operation in operations { if let Operation::Write(buffer) = operation { for chunk in buffer.chunks(255) { let chunk_len = chunk.len(); total_remaining -= chunk_len; let is_last_chunk = total_remaining == 0; let will_reload = !is_last_chunk; if first_chunk { // First chunk: initiate transfer // If not first group, use RESTART instead of START Self::master_write( self.info, address, chunk_len, Stop::Software, will_reload, !is_first_group, timeout, )?; first_chunk = false; } else { // Subsequent chunks: use reload // Always use Software stop for writes Self::reload(self.info, chunk_len, will_reload, Stop::Software, timeout)?; } // Send data bytes for byte in chunk { self.wait_txis(timeout)?; self.info.regs.txdr().write(|w| w.set_txdata(*byte)); } } } } // Wait for transfer to complete if is_last_group { self.wait_tc(timeout)?; self.master_stop(); self.wait_stop(timeout)?; } else { // Wait for TC before next group (enables RESTART) self.wait_tc(timeout)?; } Ok(()) } fn execute_read_group( &mut self, address: Address, operations: &mut [Operation<'_>], is_first_group: bool, is_last_group: bool, timeout: Timeout, ) -> Result<(), Error> { // Calculate total bytes across all operations in this group let total_bytes = Self::total_operation_bytes(operations); if total_bytes == 0 { // Handle empty read group if is_first_group { Self::master_read( self.info, address, 0, if is_last_group { Stop::Automatic } else { Stop::Software }, false, // reload !is_first_group, timeout, )?; } if is_last_group { self.wait_stop(timeout)?; } return Ok(()); } let mut total_remaining = total_bytes; let mut first_chunk = true; for operation in operations { if let Operation::Read(buffer) = operation { for chunk in buffer.chunks_mut(255) { let chunk_len = chunk.len(); total_remaining -= chunk_len; let is_last_chunk = total_remaining == 0; let will_reload = !is_last_chunk; if first_chunk { // First chunk: initiate transfer let stop = if is_last_group && is_last_chunk { Stop::Automatic } else { Stop::Software }; Self::master_read( self.info, address, chunk_len, stop, will_reload, !is_first_group, // restart if not first group timeout, )?; first_chunk = false; } else { // Subsequent chunks: use reload let stop = if is_last_group && is_last_chunk { Stop::Automatic } else { Stop::Software }; Self::reload(self.info, chunk_len, will_reload, stop, timeout)?; } // Receive data bytes for byte in chunk { self.wait_rxne(timeout)?; *byte = self.info.regs.rxdr().read().rxdata(); } } } } // Wait for transfer to complete if is_last_group { self.wait_stop(timeout)?; } // For non-last read groups, don't wait for TC - the peripheral may hold SCL low // in Software AUTOEND mode until the next START is issued. Just proceed directly // to the next group which will issue RESTART and release the clock. Ok(()) } /// Blocking write multiple buffers. /// /// The buffers are concatenated in a single write transaction. pub fn blocking_write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> { if write.is_empty() { return Err(Error::ZeroLengthTransfer); } let timeout = self.timeout(); let first_length = write[0].len(); let last_slice_index = write.len() - 1; if let Err(err) = Self::master_write( self.info, address.into(), first_length.min(255), Stop::Software, (first_length > 255) || (last_slice_index != 0), false, // restart timeout, ) { self.master_stop(); return Err(err); } for (idx, slice) in write.iter().enumerate() { let slice_len = slice.len(); let completed_chunks = slice_len / 255; let total_chunks = if completed_chunks * 255 == slice_len { completed_chunks } else { completed_chunks + 1 }; let last_chunk_idx = total_chunks.saturating_sub(1); if idx != 0 { if let Err(err) = Self::reload( self.info, slice_len.min(255), (idx != last_slice_index) || (slice_len > 255), Stop::Software, timeout, ) { if err != Error::Nack { self.master_stop(); } return Err(err); } } for (number, chunk) in slice.chunks(255).enumerate() { if number != 0 { if let Err(err) = Self::reload( self.info, chunk.len(), (number != last_chunk_idx) || (idx != last_slice_index), Stop::Software, timeout, ) { if err != Error::Nack { self.master_stop(); } return Err(err); } } for byte in chunk { // Wait until we are allowed to send data // (START has been ACKed or last byte when // through) if let Err(err) = self.wait_txis(timeout) { if err != Error::Nack { self.master_stop(); } return Err(err); } // Put byte on the wire //self.i2c.txdr.write(|w| w.txdata().bits(*byte)); self.info.regs.txdr().write(|w| w.set_txdata(*byte)); } } } // Wait until the write finishes self.wait_tc(timeout)?; self.master_stop(); self.wait_stop(timeout)?; Ok(()) } } impl<'d, IM: MasterMode> I2c<'d, Async, IM> { async fn write_dma_internal( &mut self, address: Address, write: &[u8], first_slice: bool, last_slice: bool, send_stop: bool, restart: bool, timeout: Timeout, ) -> Result<(), Error> { let total_len = write.len(); let dma_transfer = unsafe { let regs = self.info.regs; regs.cr1().modify(|w| { w.set_txdmaen(true); if first_slice { w.set_tcie(true); } w.set_nackie(true); w.set_errie(true); }); let dst = regs.txdr().as_ptr() as *mut u8; self.tx_dma.as_mut().unwrap().write(write, dst, Default::default()) }; let mut remaining_len = total_len; let on_drop = OnDrop::new(|| { let regs = self.info.regs; let isr = regs.isr().read(); regs.cr1().modify(|w| { if last_slice || isr.nackf() || isr.arlo() || isr.berr() || isr.ovr() { w.set_txdmaen(false); } w.set_tcie(false); w.set_nackie(false); w.set_errie(false); }); regs.icr().write(|w| { w.set_nackcf(true); w.set_berrcf(true); w.set_arlocf(true); w.set_ovrcf(true); }); }); poll_fn(|cx| { self.state.waker.register(cx.waker()); let isr = self.info.regs.isr().read(); if isr.nackf() { return Poll::Ready(Err(Error::Nack)); } if isr.arlo() { return Poll::Ready(Err(Error::Arbitration)); } if isr.berr() { return Poll::Ready(Err(Error::Bus)); } if isr.ovr() { return Poll::Ready(Err(Error::Overrun)); } if remaining_len == total_len { if first_slice { Self::master_write( self.info, address, total_len.min(255), Stop::Software, (total_len > 255) || !last_slice, restart, timeout, )?; } else { Self::reload( self.info, total_len.min(255), (total_len > 255) || !last_slice, Stop::Software, timeout, )?; self.info.regs.cr1().modify(|w| w.set_tcie(true)); } } else if !(isr.tcr() || isr.tc()) { // poll_fn was woken without an interrupt present return Poll::Pending; } else if remaining_len == 0 { return Poll::Ready(Ok(())); } else { if let Err(e) = Self::reload( self.info, remaining_len.min(255), (remaining_len > 255) || !last_slice, Stop::Software, timeout, ) { return Poll::Ready(Err(e)); } self.info.regs.cr1().modify(|w| w.set_tcie(true)); } remaining_len = remaining_len.saturating_sub(255); Poll::Pending }) .await?; dma_transfer.await; // Always wait for TC after DMA completes - needed for consecutive buffers self.wait_tc(timeout)?; if last_slice & send_stop { self.master_stop(); } drop(on_drop); Ok(()) } async fn read_dma_internal( &mut self, address: Address, buffer: &mut [u8], restart: bool, timeout: Timeout, ) -> Result<(), Error> { let total_len = buffer.len(); let dma_transfer = unsafe { let regs = self.info.regs; regs.cr1().modify(|w| { w.set_rxdmaen(true); w.set_tcie(true); w.set_nackie(true); w.set_errie(true); }); let src = regs.rxdr().as_ptr() as *mut u8; self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default()) }; let mut remaining_len = total_len; let on_drop = OnDrop::new(|| { let regs = self.info.regs; regs.cr1().modify(|w| { w.set_rxdmaen(false); w.set_tcie(false); w.set_nackie(false); w.set_errie(false); }); regs.icr().write(|w| { w.set_nackcf(true); w.set_berrcf(true); w.set_arlocf(true); w.set_ovrcf(true); }); }); poll_fn(|cx| { self.state.waker.register(cx.waker()); let isr = self.info.regs.isr().read(); if isr.nackf() { return Poll::Ready(Err(Error::Nack)); } if isr.arlo() { return Poll::Ready(Err(Error::Arbitration)); } if isr.berr() { return Poll::Ready(Err(Error::Bus)); } if isr.ovr() { return Poll::Ready(Err(Error::Overrun)); } if remaining_len == total_len { Self::master_read( self.info, address, total_len.min(255), Stop::Automatic, total_len > 255, // reload restart, timeout, )?; if total_len <= 255 { return Poll::Ready(Ok(())); } } else if isr.tcr() { // Transfer Complete Reload - need to set up next chunk let last_piece = remaining_len <= 255; if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, Stop::Automatic, timeout) { return Poll::Ready(Err(e)); } // Return here if we are on last chunk, // end of transfer will be awaited with the DMA below if last_piece { return Poll::Ready(Ok(())); } self.info.regs.cr1().modify(|w| w.set_tcie(true)); } else { // poll_fn was woken without TCR interrupt return Poll::Pending; } remaining_len = remaining_len.saturating_sub(255); Poll::Pending }) .await?; dma_transfer.await; drop(on_drop); Ok(()) } // ========================= // Async public API /// Write. pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { let _scoped_block_stop = self.info.rcc.block_stop(); let timeout = self.timeout(); if write.is_empty() { self.write_internal(address.into(), write, true, timeout) } else { timeout .with(self.write_dma_internal(address.into(), write, true, true, true, false, timeout)) .await } } /// Write multiple buffers. /// /// The buffers are concatenated in a single write transaction. pub async fn write_vectored(&mut self, address: Address, write: &[&[u8]]) -> Result<(), Error> { let _scoped_block_stop = self.info.rcc.block_stop(); let timeout = self.timeout(); 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(); let fut = self.write_dma_internal( address, c, first, // first_slice is_last, // last_slice is_last, // send_stop (only on last buffer) false, // restart (false for all - they're one continuous write) timeout, ); timeout.with(fut).await?; first = false; current = next; } Ok(()) } /// Read. pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { let _scoped_block_stop = self.info.rcc.block_stop(); let timeout = self.timeout(); if buffer.is_empty() { self.read_internal(address.into(), buffer, false, timeout) } else { let fut = self.read_dma_internal(address.into(), buffer, false, timeout); timeout.with(fut).await } } /// Write, restart, read. pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { let _scoped_block_stop = self.info.rcc.block_stop(); let timeout = self.timeout(); if write.is_empty() { self.write_internal(address.into(), write, false, timeout)?; } else { let fut = self.write_dma_internal(address.into(), write, true, true, false, false, timeout); timeout.with(fut).await?; } if read.is_empty() { self.read_internal(address.into(), read, true, timeout)?; } else { let fut = self.read_dma_internal(address.into(), read, true, timeout); timeout.with(fut).await?; } Ok(()) } /// Transaction with operations. /// /// Consecutive operations of same type are merged. See [transaction contract] for details. /// /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { let _scoped_block_stop = self.info.rcc.block_stop(); if operations.is_empty() { return Err(Error::ZeroLengthTransfer); } let address = addr.into(); let timeout = self.timeout(); // Group consecutive operations of the same type let mut op_idx = 0; let mut is_first_group = true; while op_idx < operations.len() { // Determine the type of current group and find all consecutive operations of same type let is_read = matches!(operations[op_idx], Operation::Read(_)); let group_start = op_idx; // Find end of this group (consecutive operations of same type) while op_idx < operations.len() && matches!(operations[op_idx], Operation::Read(_)) == is_read { op_idx += 1; } let group_end = op_idx; let is_last_group = op_idx >= operations.len(); // Execute this group of operations if is_read { self.execute_read_group_async( address, &mut operations[group_start..group_end], is_first_group, is_last_group, timeout, ) .await?; } else { self.execute_write_group_async( address, &operations[group_start..group_end], is_first_group, is_last_group, timeout, ) .await?; } is_first_group = false; } Ok(()) } async fn execute_write_group_async( &mut self, address: Address, operations: &[Operation<'_>], is_first_group: bool, is_last_group: bool, timeout: Timeout, ) -> Result<(), Error> { // Calculate total bytes across all operations in this group let total_bytes = Self::total_operation_bytes(operations); if total_bytes == 0 { // Handle empty write group using blocking call if is_first_group { Self::master_write(self.info, address, 0, Stop::Software, false, !is_first_group, timeout)?; } if is_last_group { self.master_stop(); } return Ok(()); } // Collect all write buffers let mut write_buffers: heapless::Vec<&[u8], 16> = heapless::Vec::new(); for operation in operations { if let Operation::Write(buffer) = operation { if !buffer.is_empty() { let _ = write_buffers.push(buffer); } } } if write_buffers.is_empty() { return Ok(()); } // Send each buffer using DMA let num_buffers = write_buffers.len(); for (idx, buffer) in write_buffers.iter().enumerate() { let is_first_buffer = idx == 0; let is_last_buffer = idx == num_buffers - 1; let fut = self.write_dma_internal( address, buffer, is_first_buffer, // first_slice is_last_buffer, // last_slice is_last_buffer && is_last_group, // send_stop is_first_buffer && !is_first_group, // restart (only for first buffer if not first group) timeout, ); timeout.with(fut).await?; } Ok(()) } async fn execute_read_group_async( &mut self, address: Address, operations: &mut [Operation<'_>], is_first_group: bool, is_last_group: bool, timeout: Timeout, ) -> Result<(), Error> { // Calculate total bytes across all operations in this group let total_bytes = Self::total_operation_bytes(operations); if total_bytes == 0 { // Handle empty read group using blocking call if is_first_group { Self::master_read( self.info, address, 0, if is_last_group { Stop::Automatic } else { Stop::Software }, false, // reload !is_first_group, timeout, )?; } if is_last_group { self.wait_stop(timeout)?; } return Ok(()); } // Use DMA for read operations - need to handle multiple buffers let restart = !is_first_group; let mut total_remaining = total_bytes; let mut is_first_in_group = true; for operation in operations { if let Operation::Read(buffer) = operation { if buffer.is_empty() { // Skip empty buffers continue; } let buf_len = buffer.len(); total_remaining -= buf_len; let is_last_in_group = total_remaining == 0; // Perform DMA read if is_first_in_group { // First buffer: use read_dma_internal which handles restart properly // Only use Automatic stop if this is the last buffer in the last group let stop_mode = if is_last_group && is_last_in_group { Stop::Automatic } else { Stop::Software }; // We need a custom DMA read that respects our stop mode self.read_dma_group_internal(address, buffer, restart, stop_mode, timeout) .await?; is_first_in_group = false; } else { // Subsequent buffers: need to reload and continue let stop_mode = if is_last_group && is_last_in_group { Stop::Automatic } else { Stop::Software }; self.read_dma_group_internal( address, buffer, false, // no restart for subsequent buffers in same group stop_mode, timeout, ) .await?; } } } // Wait for transfer to complete if is_last_group { self.wait_stop(timeout)?; } Ok(()) } /// Internal DMA read helper for transaction groups async fn read_dma_group_internal( &mut self, address: Address, buffer: &mut [u8], restart: bool, stop_mode: Stop, timeout: Timeout, ) -> Result<(), Error> { let total_len = buffer.len(); let dma_transfer = unsafe { let regs = self.info.regs; regs.cr1().modify(|w| { w.set_rxdmaen(true); w.set_tcie(true); w.set_nackie(true); w.set_errie(true); }); let src = regs.rxdr().as_ptr() as *mut u8; self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default()) }; let mut remaining_len = total_len; let on_drop = OnDrop::new(|| { let regs = self.info.regs; regs.cr1().modify(|w| { w.set_rxdmaen(false); w.set_tcie(false); w.set_nackie(false); w.set_errie(false); }); regs.icr().write(|w| { w.set_nackcf(true); w.set_berrcf(true); w.set_arlocf(true); w.set_ovrcf(true); }); }); poll_fn(|cx| { self.state.waker.register(cx.waker()); let isr = self.info.regs.isr().read(); if isr.nackf() { return Poll::Ready(Err(Error::Nack)); } if isr.arlo() { return Poll::Ready(Err(Error::Arbitration)); } if isr.berr() { return Poll::Ready(Err(Error::Bus)); } if isr.ovr() { return Poll::Ready(Err(Error::Overrun)); } if remaining_len == total_len { Self::master_read( self.info, address, total_len.min(255), stop_mode, total_len > 255, // reload restart, timeout, )?; if total_len <= 255 { return Poll::Ready(Ok(())); } } else if isr.tcr() { // Transfer Complete Reload - need to set up next chunk let last_piece = remaining_len <= 255; if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, stop_mode, timeout) { return Poll::Ready(Err(e)); } // Return here if we are on last chunk, // end of transfer will be awaited with the DMA below if last_piece { return Poll::Ready(Ok(())); } self.info.regs.cr1().modify(|w| w.set_tcie(true)); } else { // poll_fn was woken without TCR interrupt return Poll::Pending; } remaining_len = remaining_len.saturating_sub(255); Poll::Pending }) .await?; dma_transfer.await; drop(on_drop); Ok(()) } } impl<'d, M: Mode> I2c<'d, M, Master> { /// Configure the I2C driver for slave operations, allowing for the driver to be used as a slave and a master (multimaster) pub fn into_slave_multimaster(mut self, slave_addr_config: SlaveAddrConfig) -> I2c<'d, M, MultiMaster> { let mut slave = I2c { info: self.info, state: self.state, kernel_clock: self.kernel_clock, 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 } } impl<'d, M: Mode> I2c<'d, M, MultiMaster> { pub(crate) fn init_slave(&mut self, config: SlaveAddrConfig) { self.info.regs.cr1().modify(|reg| { reg.set_pe(false); }); self.info.regs.cr1().modify(|reg| { reg.set_nostretch(false); reg.set_gcen(config.general_call); reg.set_sbc(true); reg.set_pe(true); }); self.reconfigure_addresses(config.addr); } /// Configure the slave address. pub fn reconfigure_addresses(&mut self, addresses: OwnAddresses) { match addresses { OwnAddresses::OA1(oa1) => self.configure_oa1(oa1), OwnAddresses::OA2(oa2) => self.configure_oa2(oa2), OwnAddresses::Both { oa1, oa2 } => { self.configure_oa1(oa1); self.configure_oa2(oa2); } } } fn configure_oa1(&mut self, oa1: Address) { match oa1 { Address::SevenBit(addr) => self.info.regs.oar1().write(|reg| { reg.set_oa1en(false); reg.set_oa1((addr << 1) as u16); reg.set_oa1mode(Addmode::BIT7); reg.set_oa1en(true); }), Address::TenBit(addr) => self.info.regs.oar1().write(|reg| { reg.set_oa1en(false); reg.set_oa1(addr); reg.set_oa1mode(Addmode::BIT10); reg.set_oa1en(true); }), } } fn configure_oa2(&mut self, oa2: OA2) { self.info.regs.oar2().write(|reg| { reg.set_oa2en(false); reg.set_oa2msk(oa2.mask.into()); reg.set_oa2(oa2.addr << 1); reg.set_oa2en(true); }); } fn determine_matched_address(&self) -> Result { let matched = self.info.regs.isr().read().addcode(); if matched >> 3 == 0b11110 { // is 10-bit address and we need to get the other 8 bits from the rxdr // we do this by doing a blocking read of 1 byte let mut buffer = [0]; self.slave_read_internal(&mut buffer, self.timeout())?; Ok(Address::TenBit((matched as u16) << 6 | buffer[0] as u16)) } else { Ok(Address::SevenBit(matched)) } } } impl<'d, M: Mode> I2c<'d, M, MultiMaster> { /// # Safety /// This function will clear the address flag which will stop the clock stretching. /// This should only be done after the dma transfer has been set up. fn slave_start(info: &'static Info, length: usize, reload: bool) { assert!(length < 256); let reload = if reload { i2c::vals::Reload::NOT_COMPLETED } else { i2c::vals::Reload::COMPLETED }; info.regs.cr2().modify(|w| { w.set_nbytes(length as u8); w.set_reload(reload); }); // clear the address flag, will stop the clock stretching. // this should only be done after the dma transfer has been set up. info.regs.icr().modify(|reg| reg.set_addrcf(true)); trace!("ADDRCF cleared (ADDR interrupt enabled, clock stretching ended)"); } // A blocking read operation fn slave_read_internal(&self, read: &mut [u8], timeout: Timeout) -> Result { let completed_chunks = read.len() / 255; let total_chunks = if completed_chunks * 255 == read.len() { completed_chunks } else { completed_chunks + 1 }; let last_chunk_idx = total_chunks.saturating_sub(1); let total_len = read.len(); let mut remaining_len = total_len; for (number, chunk) in read.chunks_mut(255).enumerate() { trace!( "--- Slave RX transmission start - chunk: {}, expected (max) size: {}", number, chunk.len() ); if number == 0 { Self::slave_start(self.info, chunk.len(), number != last_chunk_idx); } else { Self::reload( self.info, chunk.len(), number != last_chunk_idx, Stop::Software, timeout, )?; } let mut index = 0; for byte in chunk { // Wait until we have received something match self.wait_rxne(timeout) { Ok(ReceiveResult::StopReceived) => {} Ok(ReceiveResult::NewStart) => { trace!("--- Slave RX transmission end (early)"); return Ok(total_len - remaining_len); // Return N bytes read } Ok(ReceiveResult::DataAvailable) => { *byte = self.info.regs.rxdr().read().rxdata(); remaining_len = remaining_len.saturating_sub(1); { trace!("Slave RX data {}: {:#04x}", index, byte); index = index + 1; } } Err(e) => return Err(e), }; } } self.wait_stop_or_err(timeout)?; trace!("--- Slave RX transmission end"); Ok(total_len - remaining_len) // Return N bytes read } // A blocking write operation fn slave_write_internal(&mut self, write: &[u8], timeout: Timeout) -> Result<(), Error> { let completed_chunks = write.len() / 255; let total_chunks = if completed_chunks * 255 == write.len() { completed_chunks } else { completed_chunks + 1 }; let last_chunk_idx = total_chunks.saturating_sub(1); for (number, chunk) in write.chunks(255).enumerate() { trace!( "--- Slave TX transmission start - chunk: {}, size: {}", number, chunk.len() ); if number == 0 { Self::slave_start(self.info, chunk.len(), number != last_chunk_idx); } else { Self::reload( self.info, chunk.len(), number != last_chunk_idx, Stop::Software, timeout, )?; } let mut index = 0; for byte in chunk { // Wait until we are allowed to send data // (START has been ACKed or last byte when through) self.wait_txis(timeout)?; { trace!("Slave TX data {}: {:#04x}", index, byte); index = index + 1; } self.info.regs.txdr().write(|w| w.set_txdata(*byte)); } } self.wait_af(timeout)?; self.flush_txdr(); self.wait_stop_or_err(timeout)?; trace!("--- Slave TX transmission end"); Ok(()) } /// Listen for incoming I2C messages. /// /// This method blocks until the slave address is matched by a master. pub fn blocking_listen(&mut self) -> Result { let timeout = self.timeout(); self.info.regs.cr1().modify(|reg| { reg.set_addrie(true); trace!("Enable ADDRIE"); }); loop { let isr = self.info.regs.isr().read(); if isr.addr() { break; } timeout.check()?; } trace!("ADDR triggered (address match)"); // we do not clear the address flag here as it will be cleared by the dma read/write // if we clear it here the clock stretching will stop and the master will read in data before the slave is ready to send it self.slave_command() } /// Determine the received slave command. fn slave_command(&self) -> Result { let isr = self.info.regs.isr().read(); match isr.dir() { i2c::vals::Dir::WRITE => { trace!("DIR: write"); Ok(SlaveCommand { kind: SlaveCommandKind::Write, address: self.determine_matched_address()?, }) } i2c::vals::Dir::READ => { trace!("DIR: read"); Ok(SlaveCommand { kind: SlaveCommandKind::Read, address: self.determine_matched_address()?, }) } } } /// Respond to a write command. /// /// Returns total number of bytes received. pub fn blocking_respond_to_write(&self, read: &mut [u8]) -> Result { let timeout = self.timeout(); self.slave_read_internal(read, timeout) } /// Respond to a read command. pub fn blocking_respond_to_read(&mut self, write: &[u8]) -> Result<(), Error> { let timeout = self.timeout(); self.slave_write_internal(write, timeout) } } impl<'d> I2c<'d, Async, MultiMaster> { /// Listen for incoming I2C messages. /// /// The listen method is an asynchronous method but it does not require DMA to be asynchronous. pub async fn listen(&mut self) -> Result { let _scoped_block_stop = self.info.rcc.block_stop(); let state = self.state; self.info.regs.cr1().modify(|reg| { reg.set_addrie(true); trace!("Enable ADDRIE"); }); poll_fn(|cx| { state.waker.register(cx.waker()); let isr = self.info.regs.isr().read(); if !isr.addr() { Poll::Pending } else { trace!("ADDR triggered (address match)"); // we do not clear the address flag here as it will be cleared by the dma read/write // if we clear it here the clock stretching will stop and the master will read in data before the slave is ready to send it Poll::Ready(self.slave_command()) } }) .await } /// Respond to a write command. /// /// Returns the total number of bytes received. pub async fn respond_to_write(&mut self, buffer: &mut [u8]) -> Result { let _scoped_block_stop = self.info.rcc.block_stop(); let timeout = self.timeout(); timeout.with(self.read_dma_internal_slave(buffer, timeout)).await } /// Respond to a read request from an I2C master. pub async fn respond_to_read(&mut self, write: &[u8]) -> Result { let _scoped_block_stop = self.info.rcc.block_stop(); let timeout = self.timeout(); timeout.with(self.write_dma_internal_slave(write, timeout)).await } // 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; let regs = self.info.regs; let mut dma_transfer = unsafe { regs.cr1().modify(|w| { w.set_rxdmaen(true); w.set_stopie(true); w.set_tcie(true); }); let src = regs.rxdr().as_ptr() as *mut u8; self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default()) }; let state = self.state; let on_drop = OnDrop::new(|| { regs.cr1().modify(|w| { w.set_rxdmaen(false); w.set_stopie(false); w.set_tcie(false); }); }); let total_received = poll_fn(|cx| { state.waker.register(cx.waker()); let isr = regs.isr().read(); if remaining_len == total_len { Self::slave_start(self.info, total_len.min(255), total_len > 255); remaining_len = remaining_len.saturating_sub(255); Poll::Pending } else if isr.tcr() { let is_last_slice = remaining_len <= 255; if let Err(e) = Self::reload( self.info, remaining_len.min(255), !is_last_slice, Stop::Software, timeout, ) { return Poll::Ready(Err(e)); } remaining_len = remaining_len.saturating_sub(255); regs.cr1().modify(|w| w.set_tcie(true)); Poll::Pending } else if isr.stopf() { remaining_len = remaining_len.saturating_add(dma_transfer.get_remaining_transfers() as usize); regs.icr().write(|reg| reg.set_stopcf(true)); let poll = Poll::Ready(Ok(total_len - remaining_len)); poll } else { Poll::Pending } }) .await?; dma_transfer.request_pause(); dma_transfer.await; drop(on_drop); Ok(total_received) } async fn write_dma_internal_slave(&mut self, buffer: &[u8], timeout: Timeout) -> Result { let total_len = buffer.len(); let mut remaining_len = total_len; let mut dma_transfer = unsafe { let regs = self.info.regs; regs.cr1().modify(|w| { w.set_txdmaen(true); w.set_stopie(true); w.set_tcie(true); }); let dst = regs.txdr().as_ptr() as *mut u8; self.tx_dma.as_mut().unwrap().write(buffer, dst, Default::default()) }; let on_drop = OnDrop::new(|| { let regs = self.info.regs; regs.cr1().modify(|w| { w.set_txdmaen(false); w.set_stopie(false); w.set_tcie(false); }); regs.isr().write(|w| w.set_txe(true)); }); let state = self.state; let size = poll_fn(|cx| { state.waker.register(cx.waker()); let isr = self.info.regs.isr().read(); if remaining_len == total_len { Self::slave_start(self.info, total_len.min(255), total_len > 255); remaining_len = remaining_len.saturating_sub(255); Poll::Pending } else if isr.tcr() { let is_last_slice = remaining_len <= 255; if let Err(e) = Self::reload( self.info, remaining_len.min(255), !is_last_slice, Stop::Software, timeout, ) { return Poll::Ready(Err(e)); } remaining_len = remaining_len.saturating_sub(255); self.info.regs.cr1().modify(|w| w.set_tcie(true)); Poll::Pending } else if isr.stopf() { let mut leftover_bytes = dma_transfer.get_remaining_transfers(); if !self.info.regs.isr().read().txe() { leftover_bytes = leftover_bytes.saturating_add(1); } remaining_len = remaining_len.saturating_add(leftover_bytes as usize); self.info.regs.icr().write(|reg| reg.set_stopcf(true)); if remaining_len > 0 { dma_transfer.request_pause(); Poll::Ready(Ok(SendStatus::LeftoverBytes(remaining_len as usize))) } else { Poll::Ready(Ok(SendStatus::Done)) } } else { Poll::Pending } }) .await?; dma_transfer.request_pause(); dma_transfer.await; drop(on_drop); Ok(size) } } /// I2C Stop Configuration /// /// Peripheral options for generating the STOP condition #[derive(Copy, Clone, PartialEq)] enum Stop { /// Software end mode: Must write register to generate STOP condition Software, /// Automatic end mode: A STOP condition is automatically generated once the /// configured number of bytes have been transferred Automatic, } impl Stop { fn autoend(&self) -> i2c::vals::Autoend { match self { Stop::Software => i2c::vals::Autoend::SOFTWARE, Stop::Automatic => i2c::vals::Autoend::AUTOMATIC, } } } struct Timings { prescale: u8, scll: u8, sclh: u8, sdadel: u8, scldel: u8, } impl Timings { fn new(i2cclk: Hertz, frequency: Hertz) -> Self { let i2cclk = i2cclk.0; let frequency = frequency.0; // Refer to RM0433 Rev 7 Figure 539 for setup and hold timing: // // t_I2CCLK = 1 / PCLK1 // t_PRESC = (PRESC + 1) * t_I2CCLK // t_SCLL = (SCLL + 1) * t_PRESC // t_SCLH = (SCLH + 1) * t_PRESC // // t_SYNC1 + t_SYNC2 > 4 * t_I2CCLK // t_SCL ~= t_SYNC1 + t_SYNC2 + t_SCLL + t_SCLH let ratio = i2cclk / frequency; // For the standard-mode configuration method, we must have a ratio of 4 // or higher assert!(ratio >= 4, "The I2C PCLK must be at least 4 times the bus frequency!"); let (presc_reg, scll, sclh, sdadel, scldel) = if frequency > 100_000 { // Fast-mode (Fm) or Fast-mode Plus (Fm+) // here we pick SCLL + 1 = 2 * (SCLH + 1) // Prescaler, 384 ticks for sclh/scll. Round up then subtract 1 let presc_reg = ((ratio - 1) / 384) as u8; // ratio < 1200 by pclk 120MHz max., therefore presc < 16 // Actual precale value selected let presc = (presc_reg + 1) as u32; let sclh = ((ratio / presc) - 3) / 3; let scll = (2 * (sclh + 1)) - 1; let (sdadel, scldel) = if frequency > 400_000 { // Fast-mode Plus (Fm+) assert!(i2cclk >= 17_000_000); // See table in datsheet let sdadel = i2cclk / 8_000_000 / presc; let scldel = i2cclk / 4_000_000 / presc - 1; (sdadel, scldel) } else { // Fast-mode (Fm) assert!(i2cclk >= 8_000_000); // See table in datsheet let sdadel = i2cclk / 4_000_000 / presc; let scldel = i2cclk / 2_000_000 / presc - 1; (sdadel, scldel) }; (presc_reg, scll as u8, sclh as u8, sdadel as u8, scldel as u8) } else { // Standard-mode (Sm) // here we pick SCLL = SCLH assert!(i2cclk >= 2_000_000); // See table in datsheet // Prescaler, 512 ticks for sclh/scll. Round up then // subtract 1 let presc = (ratio - 1) / 512; let presc_reg = cmp::min(presc, 15) as u8; // Actual prescale value selected let presc = (presc_reg + 1) as u32; let sclh = ((ratio / presc) - 2) / 2; let scll = sclh; // Speed check assert!(sclh < 256, "The I2C PCLK is too fast for this bus frequency!"); let sdadel = i2cclk / 2_000_000 / presc; let scldel = i2cclk / 500_000 / presc - 1; (presc_reg, scll as u8, sclh as u8, sdadel as u8, scldel as u8) }; // Sanity check assert!(presc_reg < 16); // Keep values within reasonable limits for fast per_ck let sdadel = cmp::max(sdadel, 2); let scldel = cmp::max(scldel, 4); //(presc_reg, scll, sclh, sdadel, scldel) Self { prescale: presc_reg, scll, sclh, sdadel, scldel, } } } impl<'d, M: Mode> SetConfig for I2c<'d, M, Master> { type Config = Hertz; type ConfigError = (); fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { self.info.regs.cr1().modify(|reg| { reg.set_pe(false); }); let timings = Timings::new(self.kernel_clock, *config); self.info.regs.timingr().write(|reg| { reg.set_presc(timings.prescale); reg.set_scll(timings.scll); reg.set_sclh(timings.sclh); reg.set_sdadel(timings.sdadel); reg.set_scldel(timings.scldel); }); self.info.regs.cr1().modify(|reg| { reg.set_pe(true); }); Ok(()) } } impl<'d, M: Mode> SetConfig for I2c<'d, M, MultiMaster> { type Config = (Hertz, SlaveAddrConfig); type ConfigError = (); fn set_config(&mut self, (config, addr_config): &Self::Config) -> Result<(), ()> { let timings = Timings::new(self.kernel_clock, *config); self.info.regs.timingr().write(|reg| { reg.set_presc(timings.prescale); reg.set_scll(timings.scll); reg.set_sclh(timings.sclh); reg.set_sdadel(timings.sdadel); reg.set_scldel(timings.scldel); }); self.init_slave(*addr_config); Ok(()) } }