aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHybridChild <[email protected]>2025-08-11 12:04:38 +0200
committerHybridChild <[email protected]>2025-08-23 08:53:48 +0200
commit4f7febc34eab0dd5822f313854338997f6dbf617 (patch)
tree512e6f11a7ee421051a284de1eb99b006a8619b1
parent46c95921f38d1548c9afc84c1c660f690fc49be4 (diff)
stm32/i2c_v1: Better handling of slave read and write overflow
-rw-r--r--embassy-stm32/src/i2c/v1.rs64
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> {