diff options
| author | HybridChild <[email protected]> | 2025-08-11 12:04:38 +0200 |
|---|---|---|
| committer | HybridChild <[email protected]> | 2025-08-23 08:53:48 +0200 |
| commit | 4f7febc34eab0dd5822f313854338997f6dbf617 (patch) | |
| tree | 512e6f11a7ee421051a284de1eb99b006a8619b1 | |
| parent | 46c95921f38d1548c9afc84c1c660f690fc49be4 (diff) | |
stm32/i2c_v1: Better handling of slave read and write overflow
| -rw-r--r-- | embassy-stm32/src/i2c/v1.rs | 64 |
1 files changed, 56 insertions, 8 deletions
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 83f01f51c..9022c2f5d 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs | |||
| @@ -618,14 +618,28 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | |||
| 618 | fn blocking_respond_to_read_timeout(&mut self, data: &[u8], timeout: Timeout) -> Result<usize, Error> { | 618 | fn blocking_respond_to_read_timeout(&mut self, data: &[u8], timeout: Timeout) -> Result<usize, Error> { |
| 619 | trace!("i2c v1 slave: respond_to_read_timeout start, data_len={}", data.len()); | 619 | trace!("i2c v1 slave: respond_to_read_timeout start, data_len={}", data.len()); |
| 620 | let mut bytes_sent = 0; | 620 | let mut bytes_sent = 0; |
| 621 | let mut data_exhausted = false; | ||
| 621 | 622 | ||
| 622 | for &byte in data { | 623 | loop { |
| 623 | trace!("i2c v1 slave: sending byte={:#x} ({})", byte, bytes_sent); | 624 | // Determine what byte to send |
| 624 | match self.send_byte_or_nack(byte, timeout)? { | 625 | let byte_to_send = if bytes_sent < data.len() { |
| 626 | // Send real data | ||
| 627 | data[bytes_sent] | ||
| 628 | } else { | ||
| 629 | // Data exhausted - send padding bytes | ||
| 630 | if !data_exhausted { | ||
| 631 | trace!("i2c v1 slave: real data exhausted, sending padding bytes"); | ||
| 632 | data_exhausted = true; | ||
| 633 | } | ||
| 634 | 0x00 // Send zeros as padding (or 0xFF, or last byte repeated) | ||
| 635 | }; | ||
| 636 | |||
| 637 | trace!("i2c v1 slave: sending byte={:#x} ({})", byte_to_send, bytes_sent); | ||
| 638 | match self.send_byte_or_nack(byte_to_send, timeout)? { | ||
| 625 | SlaveSendResult::Acked => { | 639 | SlaveSendResult::Acked => { |
| 626 | bytes_sent += 1; | 640 | bytes_sent += 1; |
| 627 | trace!("i2c v1 slave: byte acked, total_sent={}", bytes_sent); | 641 | trace!("i2c v1 slave: byte acked, total_sent={}", bytes_sent); |
| 628 | // Continue sending | 642 | // Continue sending more bytes |
| 629 | }, | 643 | }, |
| 630 | SlaveSendResult::Nacked => { | 644 | SlaveSendResult::Nacked => { |
| 631 | bytes_sent += 1; // Count the NACKed byte as sent | 645 | bytes_sent += 1; // Count the NACKed byte as sent |
| @@ -644,13 +658,16 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | |||
| 644 | } | 658 | } |
| 645 | 659 | ||
| 646 | trace!("i2c v1 slave: respond_to_read_timeout complete, bytes_sent={}", bytes_sent); | 660 | trace!("i2c v1 slave: respond_to_read_timeout complete, bytes_sent={}", bytes_sent); |
| 647 | Ok(bytes_sent) // Always return success with byte count | 661 | Ok(bytes_sent) // Return total bytes sent (including padding) |
| 648 | } | 662 | } |
| 649 | 663 | ||
| 650 | fn blocking_respond_to_write_timeout(&mut self, buffer: &mut [u8], timeout: Timeout) -> Result<usize, Error> { | 664 | fn blocking_respond_to_write_timeout(&mut self, buffer: &mut [u8], timeout: Timeout) -> Result<usize, Error> { |
| 651 | trace!("i2c v1 slave: respond_to_write_timeout start, buffer_len={}", buffer.len()); | 665 | trace!("i2c v1 slave: respond_to_write_timeout start, buffer_len={}", buffer.len()); |
| 652 | let mut bytes_received = 0; | 666 | let mut bytes_received = 0; |
| 653 | while bytes_received < buffer.len() { | 667 | let buffer_capacity = buffer.len(); |
| 668 | let mut overflow_detected = false; | ||
| 669 | |||
| 670 | while bytes_received < buffer_capacity { | ||
| 654 | match self.recv_byte_or_stop(timeout)? { | 671 | match self.recv_byte_or_stop(timeout)? { |
| 655 | SlaveReceiveResult::Byte(b) => { | 672 | SlaveReceiveResult::Byte(b) => { |
| 656 | trace!("i2c v1 slave: received byte={:#x} ({})", b, bytes_received); | 673 | trace!("i2c v1 slave: received byte={:#x} ({})", b, bytes_received); |
| @@ -667,8 +684,39 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> { | |||
| 667 | }, | 684 | }, |
| 668 | } | 685 | } |
| 669 | } | 686 | } |
| 670 | trace!("i2c v1 slave: respond_to_write_timeout complete, bytes_received={}", bytes_received); | 687 | |
| 671 | Ok(bytes_received) | 688 | // Handle buffer overflow - continue receiving but discard bytes |
| 689 | if bytes_received >= buffer_capacity { | ||
| 690 | loop { | ||
| 691 | match self.recv_byte_or_stop(timeout)? { | ||
| 692 | SlaveReceiveResult::Byte(b) => { | ||
| 693 | if !overflow_detected { | ||
| 694 | trace!("i2c v1 slave: buffer full, discarding excess bytes"); | ||
| 695 | overflow_detected = true; | ||
| 696 | } | ||
| 697 | trace!("i2c v1 slave: discarding overflow byte={:#x}", b); | ||
| 698 | // Byte is discarded but we still ACK it | ||
| 699 | }, | ||
| 700 | SlaveReceiveResult::Stop => { | ||
| 701 | trace!("i2c v1 slave: stop condition detected after overflow"); | ||
| 702 | break; | ||
| 703 | }, | ||
| 704 | SlaveReceiveResult::Restart => { | ||
| 705 | trace!("i2c v1 slave: restart detected after overflow"); | ||
| 706 | break; | ||
| 707 | }, | ||
| 708 | } | ||
| 709 | } | ||
| 710 | } | ||
| 711 | |||
| 712 | if overflow_detected { | ||
| 713 | trace!("i2c v1 slave: transaction complete with overflow - received {} bytes, buffer held {}", | ||
| 714 | bytes_received, buffer_capacity); | ||
| 715 | } else { | ||
| 716 | trace!("i2c v1 slave: respond_to_write_timeout complete, bytes_received={}", bytes_received); | ||
| 717 | } | ||
| 718 | |||
| 719 | Ok(bytes_received.min(buffer_capacity)) // Return stored bytes, not total received | ||
| 672 | } | 720 | } |
| 673 | 721 | ||
| 674 | fn determine_matched_address(&self, sr2: stm32_metapac::i2c::regs::Sr2) -> Result<Address, Error> { | 722 | fn determine_matched_address(&self, sr2: stm32_metapac::i2c::regs::Sr2) -> Result<Address, Error> { |
