aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/i2c/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-stm32/src/i2c/mod.rs')
-rw-r--r--embassy-stm32/src/i2c/mod.rs110
1 files changed, 70 insertions, 40 deletions
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs
index 249bac41c..0aa2d1da9 100644
--- a/embassy-stm32/src/i2c/mod.rs
+++ b/embassy-stm32/src/i2c/mod.rs
@@ -129,7 +129,7 @@ impl<'d> Drop for I2CDropGuard<'d> {
129 x.set_as_disconnected() 129 x.set_as_disconnected()
130 } 130 }
131 131
132 self.info.rcc.disable(); 132 self.info.rcc.disable_without_stop();
133 } 133 }
134} 134}
135 135
@@ -154,8 +154,8 @@ impl<'d> I2c<'d, Async, Master> {
154 scl: Peri<'d, if_afio!(impl SclPin<T, A>)>, 154 scl: Peri<'d, if_afio!(impl SclPin<T, A>)>,
155 sda: Peri<'d, if_afio!(impl SdaPin<T, A>)>, 155 sda: Peri<'d, if_afio!(impl SdaPin<T, A>)>,
156 _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>> 156 _irq: impl interrupt::typelevel::Binding<T::EventInterrupt, EventInterruptHandler<T>>
157 + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>> 157 + interrupt::typelevel::Binding<T::ErrorInterrupt, ErrorInterruptHandler<T>>
158 + 'd, 158 + 'd,
159 tx_dma: Peri<'d, impl TxDma<T>>, 159 tx_dma: Peri<'d, impl TxDma<T>>,
160 rx_dma: Peri<'d, impl RxDma<T>>, 160 rx_dma: Peri<'d, impl RxDma<T>>,
161 config: Config, 161 config: Config,
@@ -219,13 +219,14 @@ impl<'d, M: Mode> I2c<'d, M, Master> {
219 sda, 219 sda,
220 }, 220 },
221 }; 221 };
222
222 this.enable_and_init(config); 223 this.enable_and_init(config);
223 224
224 this 225 this
225 } 226 }
226 227
227 fn enable_and_init(&mut self, config: Config) { 228 fn enable_and_init(&mut self, config: Config) {
228 self.info.rcc.enable_and_reset(); 229 self.info.rcc.enable_and_reset_without_stop();
229 self.init(config); 230 self.init(config);
230 } 231 }
231} 232}
@@ -437,15 +438,15 @@ impl<'d, IM: MasterMode> embedded_hal_async::i2c::I2c for I2c<'d, Async, IM> {
437 438
438/// Frame type in I2C transaction. 439/// Frame type in I2C transaction.
439/// 440///
440/// This tells each method what kind of framing to use, to generate a (repeated) start condition (ST 441/// This tells each method what kind of frame to use, to generate a (repeated) start condition (ST
441/// or SR), and/or a stop condition (SP). For read operations, this also controls whether to send an 442/// or SR), and/or a stop condition (SP). For read operations, this also controls whether to send an
442/// ACK or NACK after the last byte received. 443/// ACK or NACK after the last byte received.
443/// 444///
444/// For write operations, the following options are identical because they differ only in the (N)ACK 445/// For write operations, the following options are identical because they differ only in the (N)ACK
445/// treatment relevant for read operations: 446/// treatment relevant for read operations:
446/// 447///
447/// - `FirstFrame` and `FirstAndNextFrame` 448/// - `FirstFrame` and `FirstAndNextFrame` behave identically for writes
448/// - `NextFrame` and `LastFrameNoStop` 449/// - `NextFrame` and `LastFrameNoStop` behave identically for writes
449/// 450///
450/// Abbreviations used below: 451/// Abbreviations used below:
451/// 452///
@@ -474,7 +475,7 @@ enum FrameOptions {
474 475
475#[allow(dead_code)] 476#[allow(dead_code)]
476impl FrameOptions { 477impl FrameOptions {
477 /// Sends start or repeated start condition before transfer. 478 /// Returns true if a start or repeated start condition should be generated before this operation.
478 fn send_start(self) -> bool { 479 fn send_start(self) -> bool {
479 match self { 480 match self {
480 Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true, 481 Self::FirstAndLastFrame | Self::FirstFrame | Self::FirstAndNextFrame => true,
@@ -482,7 +483,7 @@ impl FrameOptions {
482 } 483 }
483 } 484 }
484 485
485 /// Sends stop condition after transfer. 486 /// Returns true if a stop condition should be generated after this operation.
486 fn send_stop(self) -> bool { 487 fn send_stop(self) -> bool {
487 match self { 488 match self {
488 Self::FirstAndLastFrame | Self::LastFrame => true, 489 Self::FirstAndLastFrame | Self::LastFrame => true,
@@ -490,7 +491,10 @@ impl FrameOptions {
490 } 491 }
491 } 492 }
492 493
493 /// Sends NACK after last byte received, indicating end of read operation. 494 /// Returns true if NACK should be sent after the last byte received in a read operation.
495 ///
496 /// This signals the end of a read sequence and releases the bus for the master's
497 /// next transmission (or stop condition).
494 fn send_nack(self) -> bool { 498 fn send_nack(self) -> bool {
495 match self { 499 match self {
496 Self::FirstAndLastFrame | Self::FirstFrame | Self::LastFrame | Self::LastFrameNoStop => true, 500 Self::FirstAndLastFrame | Self::FirstFrame | Self::LastFrame | Self::LastFrameNoStop => true,
@@ -499,24 +503,44 @@ impl FrameOptions {
499 } 503 }
500} 504}
501 505
502/// Iterates over operations in transaction. 506/// Analyzes I2C transaction operations and assigns appropriate frame to each.
507///
508/// This function processes a sequence of I2C operations and determines the correct
509/// frame configuration for each operation to ensure proper I2C protocol compliance.
510/// It handles the complex logic of:
511///
512/// - Generating start conditions for the first operation of each type (read/write)
513/// - Generating stop conditions for the final operation in the entire transaction
514/// - Managing ACK/NACK behavior for read operations, including merging consecutive reads
515/// - Ensuring proper bus handoff between different operation types
516///
517/// **Transaction Contract Compliance:**
518/// The frame assignments ensure compliance with the embedded-hal I2C transaction contract,
519/// where consecutive operations of the same type are logically merged while maintaining
520/// proper protocol boundaries.
503/// 521///
504/// Returns necessary frame options for each operation to uphold the [transaction contract] and have 522/// **Error Handling:**
505/// the right start/stop/(N)ACK conditions on the wire. 523/// Returns an error if any read operation has an empty buffer, as this would create
524/// an invalid I2C transaction that could halt mid-execution.
525///
526/// # Arguments
527/// * `operations` - Mutable slice of I2C operations from embedded-hal
528///
529/// # Returns
530/// An iterator over (operation, frame) pairs, or an error if the transaction is invalid
506/// 531///
507/// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
508#[allow(dead_code)] 532#[allow(dead_code)]
509fn operation_frames<'a, 'b: 'a>( 533fn operation_frames<'a, 'b: 'a>(
510 operations: &'a mut [embedded_hal_1::i2c::Operation<'b>], 534 operations: &'a mut [embedded_hal_1::i2c::Operation<'b>],
511) -> Result<impl IntoIterator<Item = (&'a mut embedded_hal_1::i2c::Operation<'b>, FrameOptions)>, Error> { 535) -> Result<impl IntoIterator<Item = (&'a mut embedded_hal_1::i2c::Operation<'b>, FrameOptions)>, Error> {
512 use embedded_hal_1::i2c::Operation::{Read, Write}; 536 use embedded_hal_1::i2c::Operation::{Read, Write};
513 537
514 // Check empty read buffer before starting transaction. Otherwise, we would risk halting with an 538 // Validate that no read operations have empty buffers before starting the transaction.
515 // error in the middle of the transaction. 539 // Empty read operations would risk halting with an error mid-transaction.
516 // 540 //
517 // In principle, we could allow empty read frames within consecutive read operations, as long as 541 // Note: We could theoretically allow empty read operations within consecutive read
518 // at least one byte remains in the final (merged) read operation, but that makes the logic more 542 // sequences as long as the final merged read has at least one byte, but this would
519 // complicated and error-prone. 543 // complicate the logic significantly and create error-prone edge cases.
520 if operations.iter().any(|op| match op { 544 if operations.iter().any(|op| match op {
521 Read(read) => read.is_empty(), 545 Read(read) => read.is_empty(),
522 Write(_) => false, 546 Write(_) => false,
@@ -525,46 +549,52 @@ fn operation_frames<'a, 'b: 'a>(
525 } 549 }
526 550
527 let mut operations = operations.iter_mut().peekable(); 551 let mut operations = operations.iter_mut().peekable();
528 552 let mut next_first_operation = true;
529 let mut next_first_frame = true;
530 553
531 Ok(iter::from_fn(move || { 554 Ok(iter::from_fn(move || {
532 let op = operations.next()?; 555 let current_op = operations.next()?;
533 556
534 // Is `op` first frame of its type? 557 // Determine if this is the first operation of its type (read or write)
535 let first_frame = next_first_frame; 558 let is_first_of_type = next_first_operation;
536 let next_op = operations.peek(); 559 let next_op = operations.peek();
537 560
538 // Get appropriate frame options as combination of the following properties: 561 // Compute the appropriate frame based on three key properties:
539 // 562 //
540 // - For each first operation of its type, generate a (repeated) start condition. 563 // 1. **Start Condition**: Generate (repeated) start for first operation of each type
541 // - For the last operation overall in the entire transaction, generate a stop condition. 564 // 2. **Stop Condition**: Generate stop for the final operation in the entire transaction
542 // - For read operations, check the next operation: if it is also a read operation, we merge 565 // 3. **ACK/NACK for Reads**: For read operations, send ACK if more reads follow in the
543 // these and send ACK for all bytes in the current operation; send NACK only for the final 566 // sequence, or NACK for the final read in a sequence (before write or transaction end)
544 // read operation's last byte (before write or end of entire transaction) to indicate last
545 // byte read and release the bus for transmission of the bus master's next byte (or stop).
546 // 567 //
547 // We check the third property unconditionally, i.e. even for write opeartions. This is okay 568 // The third property is checked for all operations since the resulting frame
548 // because the resulting frame options are identical for write operations. 569 // configurations are identical for write operations regardless of ACK/NACK treatment.
549 let frame = match (first_frame, next_op) { 570 let frame = match (is_first_of_type, next_op) {
571 // First operation of type, and it's also the final operation overall
550 (true, None) => FrameOptions::FirstAndLastFrame, 572 (true, None) => FrameOptions::FirstAndLastFrame,
573 // First operation of type, next operation is also a read (continue read sequence)
551 (true, Some(Read(_))) => FrameOptions::FirstAndNextFrame, 574 (true, Some(Read(_))) => FrameOptions::FirstAndNextFrame,
575 // First operation of type, next operation is write (end current sequence)
552 (true, Some(Write(_))) => FrameOptions::FirstFrame, 576 (true, Some(Write(_))) => FrameOptions::FirstFrame,
553 // 577
578 // Continuation operation, and it's the final operation overall
554 (false, None) => FrameOptions::LastFrame, 579 (false, None) => FrameOptions::LastFrame,
580 // Continuation operation, next operation is also a read (continue read sequence)
555 (false, Some(Read(_))) => FrameOptions::NextFrame, 581 (false, Some(Read(_))) => FrameOptions::NextFrame,
582 // Continuation operation, next operation is write (end current sequence, no stop)
556 (false, Some(Write(_))) => FrameOptions::LastFrameNoStop, 583 (false, Some(Write(_))) => FrameOptions::LastFrameNoStop,
557 }; 584 };
558 585
559 // Pre-calculate if `next_op` is the first operation of its type. We do this here and not at 586 // Pre-calculate whether the next operation will be the first of its type.
560 // the beginning of the loop because we hand out `op` as iterator value and cannot access it 587 // This is done here because we consume `current_op` as the iterator value
561 // anymore in the next iteration. 588 // and cannot access it in the next iteration.
562 next_first_frame = match (&op, next_op) { 589 next_first_operation = match (&current_op, next_op) {
590 // No next operation
563 (_, None) => false, 591 (_, None) => false,
592 // Operation type changes: next will be first of its type
564 (Read(_), Some(Write(_))) | (Write(_), Some(Read(_))) => true, 593 (Read(_), Some(Write(_))) | (Write(_), Some(Read(_))) => true,
594 // Operation type continues: next will not be first of its type
565 (Read(_), Some(Read(_))) | (Write(_), Some(Write(_))) => false, 595 (Read(_), Some(Read(_))) | (Write(_), Some(Write(_))) => false,
566 }; 596 };
567 597
568 Some((op, frame)) 598 Some((current_op, frame))
569 })) 599 }))
570} 600}