Skip to content

Commit 9ac41de

Browse files
committed
Add macro for double register read with reasoning
1 parent 806cbb6 commit 9ac41de

File tree

3 files changed

+25
-8
lines changed

3 files changed

+25
-8
lines changed

src/i2c.rs

+3-8
Original file line numberDiff line numberDiff line change
@@ -459,8 +459,7 @@ impl<I2C: Instance> I2c<I2C> {
459459
/// Reset the peripheral
460460
pub fn reset(&mut self) {
461461
self.i2c.cr1().modify(|_, w| w.pe().disabled());
462-
let _ = self.i2c.cr1().read();
463-
let _ = self.i2c.cr1().read(); // Delay 2 peripheral clocks
462+
interrupt_clear_clock_sync_delay!(self.i2c.cr1());
464463
while self.i2c.cr1().read().pe().is_enabled() {}
465464
self.i2c.cr1().modify(|_, w| w.pe().enabled());
466465
}
@@ -477,8 +476,6 @@ impl<I2C: Instance> I2c<I2C> {
477476
Event::NotAcknowledge => w.nackie().enabled(),
478477
Event::AddressMatch => w.addrie().enabled(),
479478
});
480-
let _ = self.i2c.cr1().read();
481-
let _ = self.i2c.cr1().read(); // Delay 2 peripheral clocks
482479
}
483480

484481
/// Stop listening for interrupt `event`
@@ -493,8 +490,7 @@ impl<I2C: Instance> I2c<I2C> {
493490
Event::NotAcknowledge => w.nackie().disabled(),
494491
Event::AddressMatch => w.addrie().disabled(),
495492
});
496-
let _ = self.i2c.cr1().read();
497-
let _ = self.i2c.cr1().read(); // Delay 2 peripheral clocks
493+
interrupt_clear_clock_sync_delay!(self.i2c.cr1());
498494
}
499495

500496
/// Clears interrupt flag for `event`
@@ -506,8 +502,7 @@ impl<I2C: Instance> I2c<I2C> {
506502
Event::NotAcknowledge => w.nackcf().clear(),
507503
_ => w,
508504
});
509-
let _ = self.i2c.isr().read();
510-
let _ = self.i2c.isr().read(); // Delay 2 peripheral clocks
505+
interrupt_clear_clock_sync_delay!(self.i2c.cr1());
511506
}
512507

513508
/// Check if the specified `event`` occurred. If an error occurred, this

src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ pub use crate::stm32::interrupt;
4040
#[cfg(feature = "device-selected")]
4141
pub mod prelude;
4242

43+
#[cfg(feature = "device-selected")]
44+
#[macro_use]
45+
mod macros;
46+
4347
#[cfg(feature = "device-selected")]
4448
pub mod pwr;
4549

src/macros.rs

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/// This macro is used to insert a double read of a peripheral register to give the peripheral
2+
/// enough time to process a write to a register to clear an interrupt. This prevents an interrupt
3+
/// from firing immediately a second time after an ISR exits. It's necessary due to delayed
4+
/// synchronization between a peripheral and the CPU due to the different clocks of the
5+
/// peripheral and CPU. The register that is passed in should not have produce undesireable side
6+
/// effects when read.
7+
///
8+
/// See ARM Application Note 321 Section 4.9
9+
/// Also see discussion in the stm32h7xx-hal PRs [`#191`][191] and [`#195`][195].
10+
///
11+
/// [191]: https://github.com/stm32-rs/stm32h7xx-hal/pull/191
12+
/// [195]: https://github.com/stm32-rs/stm32h7xx-hal/pull/195
13+
macro_rules! interrupt_clear_clock_sync_delay {
14+
($status_reg:expr) => {
15+
let _ = $status_reg.read();
16+
let _ = $status_reg.read();
17+
};
18+
}

0 commit comments

Comments
 (0)