aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src
diff options
context:
space:
mode:
authorHybridChild <[email protected]>2025-08-12 06:49:00 +0200
committerHybridChild <[email protected]>2025-08-23 08:53:48 +0200
commit03496864d765590744582c00a1b8f010d5014a0c (patch)
tree3a69668bdfd061d8bb89cb95db9689813684f1a6 /embassy-stm32/src
parentfd7158063d38ece65f6f3f13422b2d744e8a144f (diff)
stm32/i2c_v1: Add handling of zero-length read
Diffstat (limited to 'embassy-stm32/src')
-rw-r--r--embassy-stm32/src/i2c/v1.rs62
1 files changed, 62 insertions, 0 deletions
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs
index 8f4128b45..9b5a524df 100644
--- a/embassy-stm32/src/i2c/v1.rs
+++ b/embassy-stm32/src/i2c/v1.rs
@@ -783,6 +783,13 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
783 /// Returns the total number of bytes transmitted (including padding). 783 /// Returns the total number of bytes transmitted (including padding).
784 pub fn blocking_respond_to_read(&mut self, data: &[u8]) -> Result<usize, Error> { 784 pub fn blocking_respond_to_read(&mut self, data: &[u8]) -> Result<usize, Error> {
785 trace!("I2C slave: responding to read, data_len={}", data.len()); 785 trace!("I2C slave: responding to read, data_len={}", data.len());
786
787 // Check for zero-length read BEFORE any transmission setup
788 if let Some(zero_length_result) = self.detect_zero_length_read(self.timeout())? {
789 trace!("I2C slave: zero-length read detected");
790 return Ok(zero_length_result);
791 }
792
786 let result = self.transmit_to_master(data, self.timeout()); 793 let result = self.transmit_to_master(data, self.timeout());
787 trace!("I2C slave: read response complete, result={:?}", result); 794 trace!("I2C slave: read response complete, result={:?}", result);
788 result 795 result
@@ -891,6 +898,61 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
891 898
892 Ok(bytes_stored) 899 Ok(bytes_stored)
893 } 900 }
901
902 /// Detect zero-length read pattern early
903 ///
904 /// Zero-length reads occur when a master sends START+ADDR+R followed immediately
905 /// by NACK+STOP without wanting any data. This must be detected before attempting
906 /// to transmit any bytes to avoid SDA line issues.
907 fn detect_zero_length_read(&mut self, _timeout: Timeout) -> Result<Option<usize>, Error> {
908 // Quick check for immediate termination signals
909 let sr1 = self.info.regs.sr1().read();
910
911 // Check for immediate NACK (fastest zero-length pattern)
912 if sr1.af() {
913 self.clear_acknowledge_failure();
914 return Ok(Some(0));
915 }
916
917 // Check for immediate STOP (alternative zero-length pattern)
918 if sr1.stopf() {
919 self.clear_stop_flag();
920 return Ok(Some(0));
921 }
922
923 // Give a brief window for master to send termination signals
924 // This handles masters that have slight delays between address ACK and NACK
925 const ZERO_LENGTH_DETECTION_CYCLES: u32 = 100; // ~5-10µs window
926
927 for _ in 0..ZERO_LENGTH_DETECTION_CYCLES {
928 let sr1 = self.info.regs.sr1().read();
929
930 // Immediate NACK indicates zero-length read
931 if sr1.af() {
932 self.clear_acknowledge_failure();
933 return Ok(Some(0));
934 }
935
936 // Immediate STOP indicates zero-length read
937 if sr1.stopf() {
938 self.clear_stop_flag();
939 return Ok(Some(0));
940 }
941
942 // If TXE becomes ready, master is waiting for data - not zero-length
943 if sr1.txe() {
944 return Ok(None); // Proceed with normal transmission
945 }
946
947 // If RESTART detected, handle as zero-length
948 if sr1.addr() {
949 return Ok(Some(0));
950 }
951 }
952
953 // No zero-length pattern detected within the window
954 Ok(None)
955 }
894 956
895 /// Discard excess bytes when buffer is full 957 /// Discard excess bytes when buffer is full
896 fn discard_excess_bytes(&mut self, timeout: Timeout) -> Result<(), Error> { 958 fn discard_excess_bytes(&mut self, timeout: Timeout) -> Result<(), Error> {