Skip to content

Commit 375f75b

Browse files
authored
Fix transmission termination in I2C DMA master read.
Set the `last` control bit in I2C when the read length is larger or equal to 2 and when using DMA in master mode.
1 parent 7bbd349 commit 375f75b

File tree

1 file changed

+15
-1
lines changed

1 file changed

+15
-1
lines changed

src/i2c/dma.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -509,8 +509,21 @@ where
509509
// Send address
510510
self.send_address(addr, true)?;
511511

512+
// Note from STM32 RM0090:
513+
// When the number of bytes to be received is equal to or greater than two,
514+
// the DMA controller sends a hardware signal, EOT_1, corresponding to the
515+
// last but one data byte (number_of_bytes – 1). If, in the I2C_CR2 register,
516+
// the LAST bit is set, I2C automatically sends a NACK after the next byte
517+
// following EOT_1. The user can generate a Stop condition in the DMA
518+
// Transfer Complete interrupt routine if enabled.
512519
// On small sized array we need to set ACK=0 before ADDR cleared
513-
if buf_len <= 1 {
520+
if buf_len >= 2 {
521+
self.hal_i2c.i2c.cr2.modify(|_, w| w.last().set_bit());
522+
// When a single byte must be received: the NACK must be programmed during
523+
// EV6 event, i.e. program ACK=0 when ADDR=1, before clearing ADDR flag.
524+
// Then the user can program the STOP condition either after clearing ADDR
525+
// flag, or in the DMA Transfer Complete interrupt routine.
526+
} else {
514527
self.hal_i2c.i2c.cr1.modify(|_, w| w.ack().clear_bit());
515528
}
516529

@@ -570,6 +583,7 @@ where
570583
fn finish_transfer_with_result(&mut self, result: Result<(), Error>) {
571584
self.disable_dma_requests();
572585
self.disable_error_interrupt_generation();
586+
self.hal_i2c.i2c.cr2.modify(|_, w| w.last().clear_bit());
573587

574588
if let Err(Error::I2CError(super::Error::NoAcknowledge(_))) = &result {
575589
self.send_stop();

0 commit comments

Comments
 (0)