From 56f3c7a8c72356d9e21d5ef13e60d869ffd8cdf2 Mon Sep 17 00:00:00 2001 From: Fabian Wolter Date: Tue, 2 Sep 2025 21:17:47 +0200 Subject: [PATCH] stm32/i2c: fix failure of subsequent transmissions after NACK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a slave responds with a NACK in blocking I²C master mode, all subsequent transmissions send only the address followed immediately by a STOP. This happens because the current implementation sets I2C_CR2.STOP = 1 whenever any error (including a NACK) occurs. As a result, the STOP bit is already set when the next transmission starts. According to the reference manual: "If a NACK is received: […] a STOP condition is automatically sent […]" This bug was not triggered until #4454 was merged. --- embassy-stm32/src/i2c/v2.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 3b09f1b34..6b20a601b 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs @@ -454,7 +454,8 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { // (START has been ACKed or last byte when // through) if let Err(err) = self.wait_txis(timeout) { - if send_stop { + if send_stop && err != Error::Nack { + // STOP is sent automatically if a NACK was received self.master_stop(); } return Err(err); @@ -548,7 +549,9 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { (idx != last_slice_index) || (slice_len > 255), timeout, ) { - self.master_stop(); + if err != Error::Nack { + self.master_stop(); + } return Err(err); } } @@ -561,7 +564,9 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { (number != last_chunk_idx) || (idx != last_slice_index), timeout, ) { - self.master_stop(); + if err != Error::Nack { + self.master_stop(); + } return Err(err); } } @@ -571,7 +576,9 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { // (START has been ACKed or last byte when // through) if let Err(err) = self.wait_txis(timeout) { - self.master_stop(); + if err != Error::Nack { + self.master_stop(); + } return Err(err); }