From e6988a3acd8abacb33d6cc2f57f1ad576b1d8687 Mon Sep 17 00:00:00 2001 From: Iooon Date: Sat, 4 Oct 2025 17:03:51 +0200 Subject: mspm0-i2c-target: split i2c controller and i2c target configs --- embassy-mspm0/src/i2c.rs | 8 ---- embassy-mspm0/src/i2c_target.rs | 94 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 84 insertions(+), 18 deletions(-) (limited to 'embassy-mspm0') diff --git a/embassy-mspm0/src/i2c.rs b/embassy-mspm0/src/i2c.rs index 0aefd19de..fb871f85d 100644 --- a/embassy-mspm0/src/i2c.rs +++ b/embassy-mspm0/src/i2c.rs @@ -164,12 +164,6 @@ pub struct Config { /// Set the pull configuration for the SCL pin. pub bus_speed: BusSpeed, - - /// 7-bit Target Address - pub target_addr: u8, - - /// Control if the target should ack to and report general calls. - pub general_call: bool, } impl Default for Config { @@ -182,8 +176,6 @@ impl Default for Config { sda_pull: Pull::None, scl_pull: Pull::None, bus_speed: BusSpeed::Standard, - target_addr: 0x48, - general_call: false, } } } diff --git a/embassy-mspm0/src/i2c_target.rs b/embassy-mspm0/src/i2c_target.rs index 7183280bd..86be91415 100644 --- a/embassy-mspm0/src/i2c_target.rs +++ b/embassy-mspm0/src/i2c_target.rs @@ -8,16 +8,36 @@ use core::marker::PhantomData; use core::sync::atomic::Ordering; use core::task::Poll; +use embassy_embedded_hal::SetConfig; use mspm0_metapac::i2c::vals::CpuIntIidxStat; use crate::gpio::{AnyPin, SealedPin}; -use crate::interrupt; use crate::interrupt::InterruptExt; use crate::mode::{Async, Blocking, Mode}; use crate::pac::{self, i2c::vals}; -use crate::Peri; +use crate::{i2c, i2c_target, interrupt, Peri}; // Re-use I2c controller types -use crate::i2c::{ClockSel, Config, ConfigError, Info, Instance, InterruptHandler, SclPin, SdaPin, State}; +use crate::i2c::{ClockSel, ConfigError, Info, Instance, InterruptHandler, SclPin, SdaPin, State}; + +#[non_exhaustive] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +/// Config +pub struct Config { + /// 7-bit Target Address + pub target_addr: u8, + + /// Control if the target should ack to and report general calls. + pub general_call: bool, +} + +impl Default for Config { + fn default() -> Self { + Self { + target_addr: 0x48, + general_call: false, + } + } +} /// I2C error #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -75,24 +95,71 @@ pub struct I2cTarget<'d, M: Mode> { state: &'static State, scl: Option>, sda: Option>, - config: Config, + config: i2c::Config, + target_config: i2c_target::Config, _phantom: PhantomData, } +impl<'d> SetConfig for I2cTarget<'d, Async> { + type Config = (i2c::Config, i2c_target::Config); + type ConfigError = ConfigError; + + fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { + self.info.interrupt.disable(); + + if let Some(ref sda) = self.sda { + sda.update_pf(config.0.sda_pf()); + } + + if let Some(ref scl) = self.scl { + scl.update_pf(config.0.scl_pf()); + } + + self.config = config.0.clone(); + self.target_config = config.1.clone(); + + self.reset() + } +} + +impl<'d> SetConfig for I2cTarget<'d, Blocking> { + type Config = (i2c::Config, i2c_target::Config); + type ConfigError = ConfigError; + + fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { + if let Some(ref sda) = self.sda { + sda.update_pf(config.0.sda_pf()); + } + + if let Some(ref scl) = self.scl { + scl.update_pf(config.0.scl_pf()); + } + + self.config = config.0.clone(); + self.target_config = config.1.clone(); + + self.reset() + } +} + impl<'d> I2cTarget<'d, Async> { /// Create a new asynchronous I2C target driver using interrupts + /// The `config` reuses the i2c controller config to setup the clock while `target_config` + /// configures i2c target specific parameters. pub fn new( peri: Peri<'d, T>, scl: Peri<'d, impl SclPin>, sda: Peri<'d, impl SdaPin>, _irq: impl interrupt::typelevel::Binding> + 'd, - config: Config, + config: i2c::Config, + target_config: i2c_target::Config, ) -> Result { let mut this = Self::new_inner( peri, new_pin!(scl, config.scl_pf()), new_pin!(sda, config.sda_pf()), config, + target_config, ); this.reset()?; Ok(this) @@ -110,17 +177,21 @@ impl<'d> I2cTarget<'d, Async> { impl<'d> I2cTarget<'d, Blocking> { /// Create a new blocking I2C target driver. + /// The `config` reuses the i2c controller config to setup the clock while `target_config` + /// configures i2c target specific parameters. pub fn new_blocking( peri: Peri<'d, T>, scl: Peri<'d, impl SclPin>, sda: Peri<'d, impl SdaPin>, - config: Config, + config: i2c::Config, + target_config: i2c_target::Config, ) -> Result { let mut this = Self::new_inner( peri, new_pin!(scl, config.scl_pf()), new_pin!(sda, config.sda_pf()), config, + target_config, ); this.reset()?; Ok(this) @@ -140,7 +211,8 @@ impl<'d, M: Mode> I2cTarget<'d, M> { _peri: Peri<'d, T>, scl: Option>, sda: Option>, - config: Config, + config: i2c::Config, + target_config: i2c_target::Config, ) -> Self { if let Some(ref scl) = scl { let pincm = pac::IOMUX.pincm(scl._pin_cm() as usize); @@ -161,17 +233,19 @@ impl<'d, M: Mode> I2cTarget<'d, M> { scl, sda, config, + target_config, _phantom: PhantomData, } } fn init(&mut self) -> Result<(), ConfigError> { let mut config = self.config; + let target_config = self.target_config; let regs = self.info.regs; config.check_config()?; // Target address must be 7-bit - if !(config.target_addr < 0x80) { + if !(target_config.target_addr < 0x80) { return Err(ConfigError::InvalidTargetAddress); } @@ -213,7 +287,7 @@ impl<'d, M: Mode> I2cTarget<'d, M> { // target address can be enabled and configured by using I2Cx.TOAR2 register. regs.target(0).toar().modify(|w| { w.set_oaren(true); - w.set_oar(config.target_addr as u16); + w.set_oar(target_config.target_addr as u16); }); self.state @@ -221,7 +295,7 @@ impl<'d, M: Mode> I2cTarget<'d, M> { .store(config.calculate_clock_source(), Ordering::Relaxed); regs.target(0).tctr().modify(|w| { - w.set_gencall(config.general_call); + w.set_gencall(target_config.general_call); w.set_tclkstretch(true); // Disable target wakeup, follow TI example. (TI note: Workaround for errata I2C_ERR_04.) w.set_twuen(false); -- cgit