diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 8bd930e790..9aadb5f4d9 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased - ReleaseDate +- change: stm32/i2c_v1: Remove Mode and Duty wrapper enums, use PAC types directly +- change: stm32/i2c_v1: Rename FrameOptions enum to PositionInTransaction - fix: flash erase on dual-bank STM32Gxxx - feat: Add support for STM32N657X0 - feat: timer: Add 32-bit timer support to SimplePwm waveform_up method following waveform pattern ([#4717](https://github.com/embassy-rs/embassy/pull/4717)) diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index ee60c3f444..5640c9d530 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -436,103 +436,110 @@ impl<'d, IM: MasterMode> embedded_hal_async::i2c::I2c for I2c<'d, Async, IM> { } } -/// Frame type in I2C transaction. +/// I2C operation position property (only used by I2C v1). /// -/// This tells each method what kind of frame to use, to generate a (repeated) start condition (ST -/// or SR), and/or a stop condition (SP). For read operations, this also controls whether to send an -/// ACK or NACK after the last byte received. +/// Specifies the position property of a read/write operation within an I2C transaction. This +/// determines the appropriate protocol framing behavior when implementing the embedded-hal I2C +/// [transaction contract] where consecutive operations of the same type (read-read or write-write) +/// are logically merged. /// -/// For write operations, the following options are identical because they differ only in the (N)ACK -/// treatment relevant for read operations: +/// [transaction contract]: embedded_hal_1::i2c::I2c::transaction /// -/// - `FirstFrame` and `FirstAndNextFrame` behave identically for writes -/// - `NextFrame` and `LastFrameNoStop` behave identically for writes +/// **Framing behavior for I2C transaction contract**: /// -/// Abbreviations used below: +/// - **START (ST)**: Generated before the first operation in the transaction. +/// - **Repeated START (SR)**: When switching from write to read or vice versa, a repeated start is issued. +/// - **STOP (SP)**: Generated only after the final operation in the entire transaction. +/// - **ACK/NACK**: For reads, ACK indicates more data is expected, NACK signals the end of +/// a read sequence. For writes, ACK/NACK is controlled by the slave and not relevant here. /// -/// - `ST` = start condition -/// - `SR` = repeated start condition -/// - `SP` = stop condition -/// - `ACK`/`NACK` = last byte in read operation +/// ## Examples +/// +/// ```ignore +/// // Transaction: Write(3 bytes) → Read(2 bytes) +/// // Write ops are merged, read ops are merged +/// Write[0] => FirstWithMore // START + addr + data, ACK (irrelevant for write) +/// Write[1] => Middle // data continues, ACK (irrelevant for write) +/// Write[2] => LastBeforeSwitch // last write, NACK (irrelevant), no STOP yet +/// Read[0] => FirstWithMore // Repeated START + addr, ACK expected (not last read) +/// Read[1] => Final // last overall, NACK + STOP +/// +/// // Transaction: Read(1 byte) only +/// Read[0] => FirstAndLast // START + addr + data + NACK + STOP +/// ``` #[derive(Copy, Clone)] #[allow(dead_code)] -enum FrameOptions { - /// `[ST/SR]+[NACK]+[SP]` First frame (of this type) in transaction and also last frame overall. - FirstAndLastFrame, - /// `[ST/SR]+[NACK]` First frame of this type in transaction, last frame in a read operation but - /// not the last frame overall. - FirstFrame, - /// `[ST/SR]+[ACK]` First frame of this type in transaction, neither last frame overall nor last - /// frame in a read operation. - FirstAndNextFrame, - /// `[ACK]` Middle frame in a read operation (neither first nor last). - NextFrame, - /// `[NACK]+[SP]` Last frame overall in this transaction but not the first frame. - LastFrame, - /// `[NACK]` Last frame in a read operation but not last frame overall in this transaction. - LastFrameNoStop, +enum PositionInTransaction { + /// Single operation of its type and also the final operation in the transaction. + FirstAndFinal, + + /// Single operation of its type, but not the final operation in the transaction. + FirstThenSwitch, + + /// First operation of its type in a sequence of multiple operations of the same type. + FirstWithMore, + + /// Neither first nor last operation of its type in a sequence of the same type. + Middle, + + /// Last operation of its type in a sequence of the same type, but not the final operation in the transaction. + LastBeforeSwitch, + + /// Final operation in the transaction, but not the first of its type in a sequence of the same type. + Final, } #[allow(dead_code)] -impl FrameOptions { - /// Returns true if a start or repeated start condition should be generated before this operation. +impl PositionInTransaction { + /// Returns true if a Start or Repeated Start condition should be generated before this operation. fn send_start(self) -> bool { match self { - Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true, - Self::NextFrame | Self::LastFrame | Self::LastFrameNoStop => false, + Self::FirstAndFinal | Self::FirstThenSwitch | Self::FirstWithMore => true, + Self::Middle | Self::Final | Self::LastBeforeSwitch => false, } } - /// Returns true if a stop condition should be generated after this operation. + /// Returns true if a Stop condition should be generated after this operation. fn send_stop(self) -> bool { match self { - Self::FirstAndLastFrame | Self::LastFrame => true, - Self::FirstFrame | Self::FirstAndNextFrame | Self::NextFrame | Self::LastFrameNoStop => false, + Self::FirstAndFinal | Self::Final => true, + Self::FirstThenSwitch | Self::FirstWithMore | Self::Middle | Self::LastBeforeSwitch => false, } } - /// Returns true if NACK should be sent after the last byte received in a read operation. + /// Returns true if NACK should be sent after this (read) operation. /// /// This signals the end of a read sequence and releases the bus for the master's /// next transmission (or stop condition). fn send_nack(self) -> bool { match self { - Self::FirstAndLastFrame | Self::FirstFrame | Self::LastFrame | Self::LastFrameNoStop => true, - Self::FirstAndNextFrame | Self::NextFrame => false, + Self::FirstAndFinal | Self::FirstThenSwitch | Self::Final | Self::LastBeforeSwitch => true, + Self::FirstWithMore | Self::Middle => false, } } } -/// Analyzes I2C transaction operations and assigns appropriate frame to each. -/// -/// This function processes a sequence of I2C operations and determines the correct -/// frame configuration for each operation to ensure proper I2C protocol compliance. -/// It handles the complex logic of: -/// -/// - Generating start conditions for the first operation of each type (read/write) -/// - Generating stop conditions for the final operation in the entire transaction -/// - Managing ACK/NACK behavior for read operations, including merging consecutive reads -/// - Ensuring proper bus handoff between different operation types -/// -/// **Transaction Contract Compliance:** -/// The frame assignments ensure compliance with the embedded-hal I2C transaction contract, -/// where consecutive operations of the same type are logically merged while maintaining -/// proper protocol boundaries. -/// -/// **Error Handling:** -/// Returns an error if any read operation has an empty buffer, as this would create -/// an invalid I2C transaction that could halt mid-execution. +/// Analyzes a sequence of embedded-hal I2C operations and assigns the appropriate +/// [`PositionInTransaction`] for each. /// /// # Arguments -/// * `operations` - Mutable slice of I2C operations from embedded-hal +/// * `operations` - Mutable slice of embedded-hal I2C operations /// /// # Returns -/// An iterator over (operation, frame) pairs, or an error if the transaction is invalid +/// An iterator yielding `(operation, position_in_transaction)` pairs, or an error if the +/// transaction is invalid. +/// +/// # Errors +/// Returns [`Error::Overrun`] if any read operation has an empty buffer, which would +/// create an invalid transaction that could halt mid-execution. +/// +/// # See Also +/// See [`PositionInTransaction`] for detailed protocol semantics, position variants, and examples. /// #[allow(dead_code)] -fn operation_frames<'a, 'b: 'a>( +fn assign_position_in_transaction<'a, 'b: 'a>( operations: &'a mut [embedded_hal_1::i2c::Operation<'b>], -) -> Result, FrameOptions)>, Error> { +) -> Result, PositionInTransaction)>, Error> { use embedded_hal_1::i2c::Operation::{Read, Write}; // Validate that no read operations have empty buffers before starting the transaction. @@ -554,47 +561,32 @@ fn operation_frames<'a, 'b: 'a>( Ok(iter::from_fn(move || { let current_op = operations.next()?; - // Determine if this is the first operation of its type (read or write) let is_first_of_type = next_first_operation; let next_op = operations.peek(); - // Compute the appropriate frame based on three key properties: - // - // 1. **Start Condition**: Generate (repeated) start for first operation of each type - // 2. **Stop Condition**: Generate stop for the final operation in the entire transaction - // 3. **ACK/NACK for Reads**: For read operations, send ACK if more reads follow in the - // sequence, or NACK for the final read in a sequence (before write or transaction end) - // - // The third property is checked for all operations since the resulting frame - // configurations are identical for write operations regardless of ACK/NACK treatment. - let frame = match (is_first_of_type, next_op) { - // First operation of type, and it's also the final operation overall - (true, None) => FrameOptions::FirstAndLastFrame, - // First operation of type, next operation is also a read (continue read sequence) - (true, Some(Read(_))) => FrameOptions::FirstAndNextFrame, - // First operation of type, next operation is write (end current sequence) - (true, Some(Write(_))) => FrameOptions::FirstFrame, - - // Continuation operation, and it's the final operation overall - (false, None) => FrameOptions::LastFrame, - // Continuation operation, next operation is also a read (continue read sequence) - (false, Some(Read(_))) => FrameOptions::NextFrame, - // Continuation operation, next operation is write (end current sequence, no stop) - (false, Some(Write(_))) => FrameOptions::LastFrameNoStop, + // Note: Some position variants are equivalent for write operations since ACK/NACK only applies to read operations. + let position_in_transaction = match (is_first_of_type, next_op) { + // First of type, last overall + (true, None) => PositionInTransaction::FirstAndFinal, + // First of type, more of same type follow + (true, Some(Read(_))) => PositionInTransaction::FirstWithMore, + // First of type, switching type next + (true, Some(Write(_))) => PositionInTransaction::FirstThenSwitch, + // Continuation, last overall + (false, None) => PositionInTransaction::Final, + // Continuation, more of same type follow + (false, Some(Read(_))) => PositionInTransaction::Middle, + // Continuation, switching type next + (false, Some(Write(_))) => PositionInTransaction::LastBeforeSwitch, }; - // Pre-calculate whether the next operation will be the first of its type. - // This is done here because we consume `current_op` as the iterator value - // and cannot access it in the next iteration. + // Pre-calculate for next iteration since current_op is consumed after this. next_first_operation = match (¤t_op, next_op) { - // No next operation (_, None) => false, - // Operation type changes: next will be first of its type (Read(_), Some(Write(_))) | (Write(_), Some(Read(_))) => true, - // Operation type continues: next will not be first of its type (Read(_), Some(Read(_))) | (Write(_), Some(Write(_))) => false, }; - Some((current_op, frame)) + Some((current_op, position_in_transaction)) })) } diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 128a58db78..e95268506c 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -14,7 +14,7 @@ use embedded_hal_1::i2c::Operation; use mode::Master; use super::*; -use crate::mode::Mode as PeriMode; +use crate::mode::Mode; use crate::pac::i2c; // /!\ /!\ @@ -43,7 +43,7 @@ pub unsafe fn on_interrupt() { }); } -impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> { +impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { pub(crate) fn init(&mut self, config: Config) { self.info.regs.cr1().modify(|reg| { reg.set_pe(false); @@ -82,8 +82,8 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> { reg.set_freq(timings.freq); }); self.info.regs.ccr().modify(|reg| { - reg.set_f_s(timings.mode.f_s()); - reg.set_duty(timings.duty.duty()); + reg.set_f_s(timings.f_s); + reg.set_duty(timings.duty); reg.set_ccr(timings.ccr); }); self.info.regs.trise().modify(|reg| { @@ -153,16 +153,15 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> { Ok(sr1) } - fn write_bytes( + fn blocking_write_with_framing( &mut self, address: u8, write_buffer: &[u8], timeout: Timeout, - frame: FrameOptions, + position: PositionInTransaction, ) -> Result<(), Error> { - if frame.send_start() { + if position.send_start() { // Send a START condition - self.info.regs.cr1().modify(|reg| { reg.set_start(true); }); @@ -196,7 +195,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> { self.send_byte(*c, timeout)?; } - if frame.send_stop() { + if position.send_stop() { // Send a STOP condition self.info.regs.cr1().modify(|reg| reg.set_stop(true)); } @@ -242,18 +241,18 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> { Ok(value) } - fn blocking_read_timeout( + fn blocking_read_with_framing( &mut self, address: u8, read_buffer: &mut [u8], timeout: Timeout, - frame: FrameOptions, + position: PositionInTransaction, ) -> Result<(), Error> { let Some((last_byte, read_buffer)) = read_buffer.split_last_mut() else { return Err(Error::Overrun); }; - if frame.send_start() { + if position.send_start() { // Send a START condition and set ACK bit self.info.regs.cr1().modify(|reg| { reg.set_start(true); @@ -290,10 +289,10 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> { // Prepare to send NACK then STOP after next byte self.info.regs.cr1().modify(|reg| { - if frame.send_nack() { + if position.send_nack() { reg.set_ack(false); } - if frame.send_stop() { + if position.send_stop() { reg.set_stop(true); } }); @@ -307,12 +306,22 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> { /// Blocking read. pub fn blocking_read(&mut self, address: u8, read_buffer: &mut [u8]) -> Result<(), Error> { - self.blocking_read_timeout(address, read_buffer, self.timeout(), FrameOptions::FirstAndLastFrame) + self.blocking_read_with_framing( + address, + read_buffer, + self.timeout(), + PositionInTransaction::FirstAndFinal, + ) } /// Blocking write. pub fn blocking_write(&mut self, address: u8, write_buffer: &[u8]) -> Result<(), Error> { - self.write_bytes(address, write_buffer, self.timeout(), FrameOptions::FirstAndLastFrame)?; + self.blocking_write_with_framing( + address, + write_buffer, + self.timeout(), + PositionInTransaction::FirstAndFinal, + )?; // Fallthrough is success Ok(()) @@ -333,8 +342,8 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> { let timeout = self.timeout(); - self.write_bytes(address, write_buffer, timeout, FrameOptions::FirstFrame)?; - self.blocking_read_timeout(address, read_buffer, timeout, FrameOptions::FirstAndLastFrame)?; + self.blocking_write_with_framing(address, write_buffer, timeout, PositionInTransaction::FirstThenSwitch)?; + self.blocking_read_with_framing(address, read_buffer, timeout, PositionInTransaction::FirstAndFinal)?; Ok(()) } @@ -347,10 +356,14 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> { pub fn blocking_transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { let timeout = self.timeout(); - for (op, frame) in operation_frames(operations)? { + for (op, position) in assign_position_in_transaction(operations)? { match op { - Operation::Read(read_buffer) => self.blocking_read_timeout(address, read_buffer, timeout, frame)?, - Operation::Write(write_buffer) => self.write_bytes(address, write_buffer, timeout, frame)?, + Operation::Read(read_buffer) => { + self.blocking_read_with_framing(address, read_buffer, timeout, position)? + } + Operation::Write(write_buffer) => { + self.blocking_write_with_framing(address, write_buffer, timeout, position)? + } } } @@ -380,7 +393,12 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> { } impl<'d, IM: MasterMode> I2c<'d, Async, IM> { - async fn write_frame(&mut self, address: u8, write_buffer: &[u8], frame: FrameOptions) -> Result<(), Error> { + async fn write_with_framing( + &mut self, + address: u8, + write_buffer: &[u8], + position: PositionInTransaction, + ) -> Result<(), Error> { self.info.regs.cr2().modify(|w| { // Note: Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is used for // reception. @@ -402,7 +420,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { }) }); - if frame.send_start() { + if position.send_start() { // Send a START condition self.info.regs.cr1().modify(|reg| { reg.set_start(true); @@ -493,7 +511,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { w.set_dmaen(false); }); - if frame.send_stop() { + if position.send_stop() { // The I2C transfer itself will take longer than the DMA transfer, so wait for that to finish too. // 18.3.8 “Master transmitter: In the interrupt routine after the EOT interrupt, disable DMA @@ -529,7 +547,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { /// Write. pub async fn write(&mut self, address: u8, write_buffer: &[u8]) -> Result<(), Error> { - self.write_frame(address, write_buffer, FrameOptions::FirstAndLastFrame) + self.write_with_framing(address, write_buffer, PositionInTransaction::FirstAndFinal) .await?; Ok(()) @@ -537,13 +555,18 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { /// Read. pub async fn read(&mut self, address: u8, read_buffer: &mut [u8]) -> Result<(), Error> { - self.read_frame(address, read_buffer, FrameOptions::FirstAndLastFrame) + self.read_with_framing(address, read_buffer, PositionInTransaction::FirstAndFinal) .await?; Ok(()) } - async fn read_frame(&mut self, address: u8, read_buffer: &mut [u8], frame: FrameOptions) -> Result<(), Error> { + async fn read_with_framing( + &mut self, + address: u8, + read_buffer: &mut [u8], + position: PositionInTransaction, + ) -> Result<(), Error> { if read_buffer.is_empty() { return Err(Error::Overrun); } @@ -561,7 +584,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { // If, in the I2C_CR2 register, the LAST bit is set, I2C automatically sends a NACK // after the next byte following EOT_1. The user can generate a Stop condition in // the DMA Transfer Complete interrupt routine if enabled. - w.set_last(frame.send_nack() && !single_byte); + w.set_last(position.send_nack() && !single_byte); }); // Sentinel to disable transfer when an error occurs or future is canceled. @@ -574,7 +597,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { }) }); - if frame.send_start() { + if position.send_start() { // Send a START condition and set ACK bit self.info.regs.cr1().modify(|reg| { reg.set_start(true); @@ -629,7 +652,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { // 18.3.8: When a single byte must be received: the NACK must be programmed during EV6 // event, i.e. program ACK=0 when ADDR=1, before clearing ADDR flag. - if frame.send_nack() && single_byte { + if position.send_nack() && single_byte { self.info.regs.cr1().modify(|w| { w.set_ack(false); }); @@ -640,7 +663,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { } else { // Before starting reception of single byte (but without START condition, i.e. in case // of merged operations), program NACK to emit at end of this byte. - if frame.send_nack() && single_byte { + if position.send_nack() && single_byte { self.info.regs.cr1().modify(|w| { w.set_ack(false); }); @@ -650,7 +673,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { // 18.3.8: When a single byte must be received: [snip] Then the user can program the STOP // condition either after clearing ADDR flag, or in the DMA Transfer Complete interrupt // routine. - if frame.send_stop() && single_byte { + if position.send_stop() && single_byte { self.info.regs.cr1().modify(|w| { w.set_stop(true); }); @@ -687,7 +710,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { w.set_dmaen(false); }); - if frame.send_stop() && !single_byte { + if position.send_stop() && !single_byte { self.info.regs.cr1().modify(|w| { w.set_stop(true); }); @@ -707,9 +730,9 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { return Err(Error::Overrun); } - self.write_frame(address, write_buffer, FrameOptions::FirstFrame) + self.write_with_framing(address, write_buffer, PositionInTransaction::FirstThenSwitch) .await?; - self.read_frame(address, read_buffer, FrameOptions::FirstAndLastFrame) + self.read_with_framing(address, read_buffer, PositionInTransaction::FirstAndFinal) .await } @@ -719,10 +742,10 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { /// /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction pub async fn transaction(&mut self, address: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { - for (op, frame) in operation_frames(operations)? { + for (op, position) in assign_position_in_transaction(operations)? { match op { - Operation::Read(read_buffer) => self.read_frame(address, read_buffer, frame).await?, - Operation::Write(write_buffer) => self.write_frame(address, write_buffer, frame).await?, + Operation::Read(read_buffer) => self.read_with_framing(address, read_buffer, position).await?, + Operation::Write(write_buffer) => self.write_with_framing(address, write_buffer, position).await?, } } @@ -730,34 +753,6 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { } } -enum Mode { - Fast, - Standard, -} - -impl Mode { - fn f_s(&self) -> i2c::vals::FS { - match self { - Mode::Fast => i2c::vals::FS::FAST, - Mode::Standard => i2c::vals::FS::STANDARD, - } - } -} - -enum Duty { - Duty2_1, - Duty16_9, -} - -impl Duty { - fn duty(&self) -> i2c::vals::Duty { - match self { - Duty::Duty2_1 => i2c::vals::Duty::DUTY2_1, - Duty::Duty16_9 => i2c::vals::Duty::DUTY16_9, - } - } -} - /// Result of attempting to send a byte in slave transmitter mode #[derive(Debug, PartialEq)] enum TransmitResult { @@ -794,7 +789,7 @@ enum SlaveTermination { Nack, } -impl<'d, M: PeriMode> I2c<'d, M, Master> { +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 { @@ -815,7 +810,7 @@ impl<'d, M: PeriMode> I2c<'d, M, Master> { } // Address configuration methods -impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> { +impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { /// Initialize slave mode with address configuration pub(crate) fn init_slave(&mut self, config: SlaveAddrConfig) { trace!("I2C slave: initializing with config={:?}", config); @@ -906,7 +901,7 @@ impl<'d, M: PeriMode, IM: MasterMode> I2c<'d, M, IM> { } } -impl<'d, M: PeriMode> I2c<'d, M, MultiMaster> { +impl<'d, M: Mode> I2c<'d, M, MultiMaster> { /// Listen for incoming I2C address match and return the command type /// /// This method blocks until the slave address is matched by a master. @@ -1703,11 +1698,11 @@ impl<'d> I2c<'d, Async, MultiMaster> { /// peripherals, which use three separate registers (CR2.FREQ, CCR, TRISE) instead of /// the unified TIMINGR register found in v2 hardware. struct Timings { - freq: u8, // APB frequency in MHz for CR2.FREQ register - mode: Mode, // Standard or Fast mode selection - trise: u8, // Rise time compensation value - ccr: u16, // Clock control register value - duty: Duty, // Fast mode duty cycle selection + freq: u8, // APB frequency in MHz for CR2.FREQ register + f_s: i2c::vals::FS, // Standard or Fast mode selection + trise: u8, // Rise time compensation value + ccr: u16, // Clock control register value + duty: i2c::vals::Duty, // Fast mode duty cycle selection } impl Timings { @@ -1727,25 +1722,25 @@ impl Timings { let mut ccr; let duty; - let mode; + let f_s; // I2C clock control calculation if frequency <= 100_000 { - duty = Duty::Duty2_1; - mode = Mode::Standard; + duty = i2c::vals::Duty::DUTY2_1; + f_s = i2c::vals::FS::STANDARD; ccr = { let ccr = clock / (frequency * 2); if ccr < 4 { 4 } else { ccr } }; } else { const DUTYCYCLE: u8 = 0; - mode = Mode::Fast; + f_s = i2c::vals::FS::FAST; if DUTYCYCLE == 0 { - duty = Duty::Duty2_1; + duty = i2c::vals::Duty::DUTY2_1; ccr = clock / (frequency * 3); ccr = if ccr < 1 { 1 } else { ccr }; } else { - duty = Duty::Duty16_9; + duty = i2c::vals::Duty::DUTY16_9; ccr = clock / (frequency * 25); ccr = if ccr < 1 { 1 } else { ccr }; } @@ -1753,15 +1748,15 @@ impl Timings { Self { freq: freq as u8, + f_s, trise: trise as u8, ccr: ccr as u16, duty, - mode, } } } -impl<'d, M: PeriMode> SetConfig for I2c<'d, M, Master> { +impl<'d, M: Mode> SetConfig for I2c<'d, M, Master> { type Config = Hertz; type ConfigError = (); fn set_config(&mut self, config: &Self::Config) -> Result<(), ()> { @@ -1770,8 +1765,8 @@ impl<'d, M: PeriMode> SetConfig for I2c<'d, M, Master> { reg.set_freq(timings.freq); }); self.info.regs.ccr().modify(|reg| { - reg.set_f_s(timings.mode.f_s()); - reg.set_duty(timings.duty.duty()); + reg.set_f_s(timings.f_s); + reg.set_duty(timings.duty); reg.set_ccr(timings.ccr); }); self.info.regs.trise().modify(|reg| {