diff options
| author | HybridChild <[email protected]> | 2025-08-12 06:49:00 +0200 |
|---|---|---|
| committer | HybridChild <[email protected]> | 2025-08-23 08:53:48 +0200 |
| commit | 03496864d765590744582c00a1b8f010d5014a0c (patch) | |
| tree | 3a69668bdfd061d8bb89cb95db9689813684f1a6 /embassy-stm32/src | |
| parent | fd7158063d38ece65f6f3f13422b2d744e8a144f (diff) | |
stm32/i2c_v1: Add handling of zero-length read
Diffstat (limited to 'embassy-stm32/src')
| -rw-r--r-- | embassy-stm32/src/i2c/v1.rs | 62 |
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> { |
