stm32/i2c: fix failure of subsequent transmissions after NACK

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.
This commit is contained in:
Fabian Wolter 2025-09-02 21:17:47 +02:00
parent 1405b1affa
commit 56f3c7a8c7
No known key found for this signature in database

View File

@ -454,7 +454,8 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
// (START has been ACKed or last byte when // (START has been ACKed or last byte when
// through) // through)
if let Err(err) = self.wait_txis(timeout) { 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(); self.master_stop();
} }
return Err(err); return Err(err);
@ -548,7 +549,9 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
(idx != last_slice_index) || (slice_len > 255), (idx != last_slice_index) || (slice_len > 255),
timeout, timeout,
) { ) {
self.master_stop(); if err != Error::Nack {
self.master_stop();
}
return Err(err); 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), (number != last_chunk_idx) || (idx != last_slice_index),
timeout, timeout,
) { ) {
self.master_stop(); if err != Error::Nack {
self.master_stop();
}
return Err(err); 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 // (START has been ACKed or last byte when
// through) // through)
if let Err(err) = self.wait_txis(timeout) { if let Err(err) = self.wait_txis(timeout) {
self.master_stop(); if err != Error::Nack {
self.master_stop();
}
return Err(err); return Err(err);
} }