diff options
| author | HybridChild <[email protected]> | 2025-07-27 12:25:03 +0200 |
|---|---|---|
| committer | HybridChild <[email protected]> | 2025-08-23 08:50:49 +0200 |
| commit | 593fb963b84741bb05d1cae1dbacafb92b4828c6 (patch) | |
| tree | be0fffbc371ceec9d94ec1d62626bfeb175309e5 | |
| parent | b690a0314f0f2e42137ad4b3e867e056c1d3c14e (diff) | |
stm32/i2c: Add temporary trait for version-specific initialization during v1 rework
| -rw-r--r-- | embassy-stm32/src/i2c/mod.rs | 22 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/v1.rs | 38 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/v2.rs | 4 |
3 files changed, 55 insertions, 9 deletions
diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 58225d937..660b8144a 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs | |||
| @@ -29,6 +29,21 @@ use crate::rcc::{RccInfo, SealedRccPeripheral}; | |||
| 29 | use crate::time::Hertz; | 29 | use crate::time::Hertz; |
| 30 | use crate::{interrupt, peripherals}; | 30 | use crate::{interrupt, peripherals}; |
| 31 | 31 | ||
| 32 | /// Temporary trait for version-specific initialization during I2C v1 async rework. | ||
| 33 | /// | ||
| 34 | /// This trait allows the shared constructor in mod.rs to call version-specific | ||
| 35 | /// initialization while we incrementally migrate v1 async operations to use | ||
| 36 | /// the new event-driven interrupt pattern. Will be removed once the rework | ||
| 37 | /// is complete and both blocking/async modes use unified initialization. | ||
| 38 | pub trait VersionSpecificInit { | ||
| 39 | /// Performs version and mode-specific initialization. | ||
| 40 | /// | ||
| 41 | /// For v1: Sets interrupt pattern flag based on blocking vs async mode. | ||
| 42 | /// For v2: No-op, does nothing. | ||
| 43 | fn version_specific_init(&mut self); | ||
| 44 | } | ||
| 45 | |||
| 46 | |||
| 32 | /// I2C error. | 47 | /// I2C error. |
| 33 | #[derive(Debug, PartialEq, Eq, Copy, Clone)] | 48 | #[derive(Debug, PartialEq, Eq, Copy, Clone)] |
| 34 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 49 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| @@ -192,7 +207,10 @@ impl<'d> I2c<'d, Blocking, Master> { | |||
| 192 | } | 207 | } |
| 193 | } | 208 | } |
| 194 | 209 | ||
| 195 | impl<'d, M: Mode> I2c<'d, M, Master> { | 210 | impl<'d, M: Mode> I2c<'d, M, Master> |
| 211 | where | ||
| 212 | Self: VersionSpecificInit | ||
| 213 | { | ||
| 196 | /// Create a new I2C driver. | 214 | /// Create a new I2C driver. |
| 197 | fn new_inner<T: Instance>( | 215 | fn new_inner<T: Instance>( |
| 198 | _peri: Peri<'d, T>, | 216 | _peri: Peri<'d, T>, |
| @@ -221,7 +239,9 @@ impl<'d, M: Mode> I2c<'d, M, Master> { | |||
| 221 | sda, | 239 | sda, |
| 222 | }, | 240 | }, |
| 223 | }; | 241 | }; |
| 242 | |||
| 224 | this.enable_and_init(config); | 243 | this.enable_and_init(config); |
| 244 | this.version_specific_init(); | ||
| 225 | 245 | ||
| 226 | this | 246 | this |
| 227 | } | 247 | } |
diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index 78abb85ea..eaf787334 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | use core::future::poll_fn; | 7 | use core::future::poll_fn; |
| 8 | use core::task::Poll; | 8 | use core::task::Poll; |
| 9 | use core::sync::atomic::{AtomicBool, Ordering}; | ||
| 9 | 10 | ||
| 10 | use embassy_embedded_hal::SetConfig; | 11 | use embassy_embedded_hal::SetConfig; |
| 11 | use embassy_futures::select::{select, Either}; | 12 | use embassy_futures::select::{select, Either}; |
| @@ -22,12 +23,14 @@ use embassy_sync::waitqueue::AtomicWaker; | |||
| 22 | /// I2C v2 peripheral state | 23 | /// I2C v2 peripheral state |
| 23 | pub(crate) struct State { | 24 | pub(crate) struct State { |
| 24 | pub(crate) waker: AtomicWaker, | 25 | pub(crate) waker: AtomicWaker, |
| 26 | pub use_new_interrupt_pattern: AtomicBool, | ||
| 25 | } | 27 | } |
| 26 | 28 | ||
| 27 | impl State { | 29 | impl State { |
| 28 | pub(crate) const fn new() -> Self { | 30 | pub(crate) const fn new() -> Self { |
| 29 | Self { | 31 | Self { |
| 30 | waker: AtomicWaker::new(), | 32 | waker: AtomicWaker::new(), |
| 33 | use_new_interrupt_pattern: AtomicBool::new(false), | ||
| 31 | } | 34 | } |
| 32 | } | 35 | } |
| 33 | } | 36 | } |
| @@ -44,17 +47,25 @@ impl State { | |||
| 44 | // There's some more details there, and we might have a fix for you. But please let us know if you | 47 | // There's some more details there, and we might have a fix for you. But please let us know if you |
| 45 | // hit a case like this! | 48 | // hit a case like this! |
| 46 | pub unsafe fn on_interrupt<T: Instance>() { | 49 | pub unsafe fn on_interrupt<T: Instance>() { |
| 47 | let regs = T::info().regs; | ||
| 48 | // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of | 50 | // i2c v2 only woke the task on transfer complete interrupts. v1 uses interrupts for a bunch of |
| 49 | // other stuff, so we wake the task on every interrupt. | 51 | // other stuff, so we wake the task on every interrupt. |
| 50 | T::state().waker.wake(); | 52 | |
| 51 | critical_section::with(|_| { | 53 | let regs = T::info().regs; |
| 52 | // Clear event interrupt flag. | 54 | let state = T::state(); |
| 53 | regs.cr2().modify(|w| { | 55 | |
| 54 | w.set_itevten(false); | 56 | if state.use_new_interrupt_pattern.load(Ordering::Relaxed) { |
| 55 | w.set_iterren(false); | 57 | |
| 58 | } else { | ||
| 59 | critical_section::with(|_| { | ||
| 60 | // Clear event interrupt flag. | ||
| 61 | regs.cr2().modify(|w| { | ||
| 62 | w.set_itevten(false); | ||
| 63 | w.set_iterren(false); | ||
| 64 | }); | ||
| 56 | }); | 65 | }); |
| 57 | }); | 66 | } |
| 67 | |||
| 68 | state.waker.wake(); | ||
| 58 | } | 69 | } |
| 59 | 70 | ||
| 60 | impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { | 71 | impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { |
| @@ -716,6 +727,17 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> { | |||
| 716 | } | 727 | } |
| 717 | } | 728 | } |
| 718 | 729 | ||
| 730 | impl<'d> VersionSpecificInit for I2c<'d, Blocking, Master> { | ||
| 731 | fn version_specific_init(&mut self) { | ||
| 732 | self.state.use_new_interrupt_pattern.store(false, Ordering::Relaxed); | ||
| 733 | } | ||
| 734 | } | ||
| 735 | |||
| 736 | impl<'d> VersionSpecificInit for I2c<'d, Async, Master> { | ||
| 737 | fn version_specific_init(&mut self) { | ||
| 738 | self.state.use_new_interrupt_pattern.store(true, Ordering::Relaxed); | ||
| 739 | } | ||
| 740 | } | ||
| 719 | 741 | ||
| 720 | /// Timing configuration for I2C v1 hardware | 742 | /// Timing configuration for I2C v1 hardware |
| 721 | /// | 743 | /// |
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index 72a7d05ab..f23c58c9e 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs | |||
| @@ -107,6 +107,10 @@ pub(crate) unsafe fn on_interrupt<T: Instance>() { | |||
| 107 | }); | 107 | }); |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | impl<'d, M: Mode> VersionSpecificInit for I2c<'d, M, Master> { | ||
| 111 | fn version_specific_init(&mut self) {} | ||
| 112 | } | ||
| 113 | |||
| 110 | impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { | 114 | impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { |
| 111 | pub(crate) fn init(&mut self, config: Config) { | 115 | pub(crate) fn init(&mut self, config: Config) { |
| 112 | self.info.regs.cr1().modify(|reg| { | 116 | self.info.regs.cr1().modify(|reg| { |
