diff options
| author | Iooon <[email protected]> | 2025-10-04 17:03:51 +0200 |
|---|---|---|
| committer | crispaudio <[email protected]> | 2025-10-10 07:01:23 +0200 |
| commit | e6988a3acd8abacb33d6cc2f57f1ad576b1d8687 (patch) | |
| tree | 2b8330d049bc2ea97a7e375211a526ad2a068fc8 | |
| parent | 8d13271100595c31001e0dd1078067a96e42816d (diff) | |
mspm0-i2c-target: split i2c controller and i2c target configs
| -rw-r--r-- | embassy-mspm0/src/i2c.rs | 8 | ||||
| -rw-r--r-- | embassy-mspm0/src/i2c_target.rs | 94 |
2 files changed, 84 insertions, 18 deletions
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 { | |||
| 164 | 164 | ||
| 165 | /// Set the pull configuration for the SCL pin. | 165 | /// Set the pull configuration for the SCL pin. |
| 166 | pub bus_speed: BusSpeed, | 166 | pub bus_speed: BusSpeed, |
| 167 | |||
| 168 | /// 7-bit Target Address | ||
| 169 | pub target_addr: u8, | ||
| 170 | |||
| 171 | /// Control if the target should ack to and report general calls. | ||
| 172 | pub general_call: bool, | ||
| 173 | } | 167 | } |
| 174 | 168 | ||
| 175 | impl Default for Config { | 169 | impl Default for Config { |
| @@ -182,8 +176,6 @@ impl Default for Config { | |||
| 182 | sda_pull: Pull::None, | 176 | sda_pull: Pull::None, |
| 183 | scl_pull: Pull::None, | 177 | scl_pull: Pull::None, |
| 184 | bus_speed: BusSpeed::Standard, | 178 | bus_speed: BusSpeed::Standard, |
| 185 | target_addr: 0x48, | ||
| 186 | general_call: false, | ||
| 187 | } | 179 | } |
| 188 | } | 180 | } |
| 189 | } | 181 | } |
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; | |||
| 8 | use core::sync::atomic::Ordering; | 8 | use core::sync::atomic::Ordering; |
| 9 | use core::task::Poll; | 9 | use core::task::Poll; |
| 10 | 10 | ||
| 11 | use embassy_embedded_hal::SetConfig; | ||
| 11 | use mspm0_metapac::i2c::vals::CpuIntIidxStat; | 12 | use mspm0_metapac::i2c::vals::CpuIntIidxStat; |
| 12 | 13 | ||
| 13 | use crate::gpio::{AnyPin, SealedPin}; | 14 | use crate::gpio::{AnyPin, SealedPin}; |
| 14 | use crate::interrupt; | ||
| 15 | use crate::interrupt::InterruptExt; | 15 | use crate::interrupt::InterruptExt; |
| 16 | use crate::mode::{Async, Blocking, Mode}; | 16 | use crate::mode::{Async, Blocking, Mode}; |
| 17 | use crate::pac::{self, i2c::vals}; | 17 | use crate::pac::{self, i2c::vals}; |
| 18 | use crate::Peri; | 18 | use crate::{i2c, i2c_target, interrupt, Peri}; |
| 19 | // Re-use I2c controller types | 19 | // Re-use I2c controller types |
| 20 | use crate::i2c::{ClockSel, Config, ConfigError, Info, Instance, InterruptHandler, SclPin, SdaPin, State}; | 20 | use crate::i2c::{ClockSel, ConfigError, Info, Instance, InterruptHandler, SclPin, SdaPin, State}; |
| 21 | |||
| 22 | #[non_exhaustive] | ||
| 23 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | ||
| 24 | /// Config | ||
| 25 | pub struct Config { | ||
| 26 | /// 7-bit Target Address | ||
| 27 | pub target_addr: u8, | ||
| 28 | |||
| 29 | /// Control if the target should ack to and report general calls. | ||
| 30 | pub general_call: bool, | ||
| 31 | } | ||
| 32 | |||
| 33 | impl Default for Config { | ||
| 34 | fn default() -> Self { | ||
| 35 | Self { | ||
| 36 | target_addr: 0x48, | ||
| 37 | general_call: false, | ||
| 38 | } | ||
| 39 | } | ||
| 40 | } | ||
| 21 | 41 | ||
| 22 | /// I2C error | 42 | /// I2C error |
| 23 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] | 43 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] |
| @@ -75,24 +95,71 @@ pub struct I2cTarget<'d, M: Mode> { | |||
| 75 | state: &'static State, | 95 | state: &'static State, |
| 76 | scl: Option<Peri<'d, AnyPin>>, | 96 | scl: Option<Peri<'d, AnyPin>>, |
| 77 | sda: Option<Peri<'d, AnyPin>>, | 97 | sda: Option<Peri<'d, AnyPin>>, |
| 78 | config: Config, | 98 | config: i2c::Config, |
| 99 | target_config: i2c_target::Config, | ||
| 79 | _phantom: PhantomData<M>, | 100 | _phantom: PhantomData<M>, |
| 80 | } | 101 | } |
| 81 | 102 | ||
| 103 | impl<'d> SetConfig for I2cTarget<'d, Async> { | ||
| 104 | type Config = (i2c::Config, i2c_target::Config); | ||
| 105 | type ConfigError = ConfigError; | ||
| 106 | |||
| 107 | fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { | ||
| 108 | self.info.interrupt.disable(); | ||
| 109 | |||
| 110 | if let Some(ref sda) = self.sda { | ||
| 111 | sda.update_pf(config.0.sda_pf()); | ||
| 112 | } | ||
| 113 | |||
| 114 | if let Some(ref scl) = self.scl { | ||
| 115 | scl.update_pf(config.0.scl_pf()); | ||
| 116 | } | ||
| 117 | |||
| 118 | self.config = config.0.clone(); | ||
| 119 | self.target_config = config.1.clone(); | ||
| 120 | |||
| 121 | self.reset() | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | impl<'d> SetConfig for I2cTarget<'d, Blocking> { | ||
| 126 | type Config = (i2c::Config, i2c_target::Config); | ||
| 127 | type ConfigError = ConfigError; | ||
| 128 | |||
| 129 | fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { | ||
| 130 | if let Some(ref sda) = self.sda { | ||
| 131 | sda.update_pf(config.0.sda_pf()); | ||
| 132 | } | ||
| 133 | |||
| 134 | if let Some(ref scl) = self.scl { | ||
| 135 | scl.update_pf(config.0.scl_pf()); | ||
| 136 | } | ||
| 137 | |||
| 138 | self.config = config.0.clone(); | ||
| 139 | self.target_config = config.1.clone(); | ||
| 140 | |||
| 141 | self.reset() | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 82 | impl<'d> I2cTarget<'d, Async> { | 145 | impl<'d> I2cTarget<'d, Async> { |
| 83 | /// Create a new asynchronous I2C target driver using interrupts | 146 | /// Create a new asynchronous I2C target driver using interrupts |
| 147 | /// The `config` reuses the i2c controller config to setup the clock while `target_config` | ||
| 148 | /// configures i2c target specific parameters. | ||
| 84 | pub fn new<T: Instance>( | 149 | pub fn new<T: Instance>( |
| 85 | peri: Peri<'d, T>, | 150 | peri: Peri<'d, T>, |
| 86 | scl: Peri<'d, impl SclPin<T>>, | 151 | scl: Peri<'d, impl SclPin<T>>, |
| 87 | sda: Peri<'d, impl SdaPin<T>>, | 152 | sda: Peri<'d, impl SdaPin<T>>, |
| 88 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, | 153 | _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd, |
| 89 | config: Config, | 154 | config: i2c::Config, |
| 155 | target_config: i2c_target::Config, | ||
| 90 | ) -> Result<Self, ConfigError> { | 156 | ) -> Result<Self, ConfigError> { |
| 91 | let mut this = Self::new_inner( | 157 | let mut this = Self::new_inner( |
| 92 | peri, | 158 | peri, |
| 93 | new_pin!(scl, config.scl_pf()), | 159 | new_pin!(scl, config.scl_pf()), |
| 94 | new_pin!(sda, config.sda_pf()), | 160 | new_pin!(sda, config.sda_pf()), |
| 95 | config, | 161 | config, |
| 162 | target_config, | ||
| 96 | ); | 163 | ); |
| 97 | this.reset()?; | 164 | this.reset()?; |
| 98 | Ok(this) | 165 | Ok(this) |
| @@ -110,17 +177,21 @@ impl<'d> I2cTarget<'d, Async> { | |||
| 110 | 177 | ||
| 111 | impl<'d> I2cTarget<'d, Blocking> { | 178 | impl<'d> I2cTarget<'d, Blocking> { |
| 112 | /// Create a new blocking I2C target driver. | 179 | /// Create a new blocking I2C target driver. |
| 180 | /// The `config` reuses the i2c controller config to setup the clock while `target_config` | ||
| 181 | /// configures i2c target specific parameters. | ||
| 113 | pub fn new_blocking<T: Instance>( | 182 | pub fn new_blocking<T: Instance>( |
| 114 | peri: Peri<'d, T>, | 183 | peri: Peri<'d, T>, |
| 115 | scl: Peri<'d, impl SclPin<T>>, | 184 | scl: Peri<'d, impl SclPin<T>>, |
| 116 | sda: Peri<'d, impl SdaPin<T>>, | 185 | sda: Peri<'d, impl SdaPin<T>>, |
| 117 | config: Config, | 186 | config: i2c::Config, |
| 187 | target_config: i2c_target::Config, | ||
| 118 | ) -> Result<Self, ConfigError> { | 188 | ) -> Result<Self, ConfigError> { |
| 119 | let mut this = Self::new_inner( | 189 | let mut this = Self::new_inner( |
| 120 | peri, | 190 | peri, |
| 121 | new_pin!(scl, config.scl_pf()), | 191 | new_pin!(scl, config.scl_pf()), |
| 122 | new_pin!(sda, config.sda_pf()), | 192 | new_pin!(sda, config.sda_pf()), |
| 123 | config, | 193 | config, |
| 194 | target_config, | ||
| 124 | ); | 195 | ); |
| 125 | this.reset()?; | 196 | this.reset()?; |
| 126 | Ok(this) | 197 | Ok(this) |
| @@ -140,7 +211,8 @@ impl<'d, M: Mode> I2cTarget<'d, M> { | |||
| 140 | _peri: Peri<'d, T>, | 211 | _peri: Peri<'d, T>, |
| 141 | scl: Option<Peri<'d, AnyPin>>, | 212 | scl: Option<Peri<'d, AnyPin>>, |
| 142 | sda: Option<Peri<'d, AnyPin>>, | 213 | sda: Option<Peri<'d, AnyPin>>, |
| 143 | config: Config, | 214 | config: i2c::Config, |
| 215 | target_config: i2c_target::Config, | ||
| 144 | ) -> Self { | 216 | ) -> Self { |
| 145 | if let Some(ref scl) = scl { | 217 | if let Some(ref scl) = scl { |
| 146 | let pincm = pac::IOMUX.pincm(scl._pin_cm() as usize); | 218 | let pincm = pac::IOMUX.pincm(scl._pin_cm() as usize); |
| @@ -161,17 +233,19 @@ impl<'d, M: Mode> I2cTarget<'d, M> { | |||
| 161 | scl, | 233 | scl, |
| 162 | sda, | 234 | sda, |
| 163 | config, | 235 | config, |
| 236 | target_config, | ||
| 164 | _phantom: PhantomData, | 237 | _phantom: PhantomData, |
| 165 | } | 238 | } |
| 166 | } | 239 | } |
| 167 | 240 | ||
| 168 | fn init(&mut self) -> Result<(), ConfigError> { | 241 | fn init(&mut self) -> Result<(), ConfigError> { |
| 169 | let mut config = self.config; | 242 | let mut config = self.config; |
| 243 | let target_config = self.target_config; | ||
| 170 | let regs = self.info.regs; | 244 | let regs = self.info.regs; |
| 171 | 245 | ||
| 172 | config.check_config()?; | 246 | config.check_config()?; |
| 173 | // Target address must be 7-bit | 247 | // Target address must be 7-bit |
| 174 | if !(config.target_addr < 0x80) { | 248 | if !(target_config.target_addr < 0x80) { |
| 175 | return Err(ConfigError::InvalidTargetAddress); | 249 | return Err(ConfigError::InvalidTargetAddress); |
| 176 | } | 250 | } |
| 177 | 251 | ||
| @@ -213,7 +287,7 @@ impl<'d, M: Mode> I2cTarget<'d, M> { | |||
| 213 | // target address can be enabled and configured by using I2Cx.TOAR2 register. | 287 | // target address can be enabled and configured by using I2Cx.TOAR2 register. |
| 214 | regs.target(0).toar().modify(|w| { | 288 | regs.target(0).toar().modify(|w| { |
| 215 | w.set_oaren(true); | 289 | w.set_oaren(true); |
| 216 | w.set_oar(config.target_addr as u16); | 290 | w.set_oar(target_config.target_addr as u16); |
| 217 | }); | 291 | }); |
| 218 | 292 | ||
| 219 | self.state | 293 | self.state |
| @@ -221,7 +295,7 @@ impl<'d, M: Mode> I2cTarget<'d, M> { | |||
| 221 | .store(config.calculate_clock_source(), Ordering::Relaxed); | 295 | .store(config.calculate_clock_source(), Ordering::Relaxed); |
| 222 | 296 | ||
| 223 | regs.target(0).tctr().modify(|w| { | 297 | regs.target(0).tctr().modify(|w| { |
| 224 | w.set_gencall(config.general_call); | 298 | w.set_gencall(target_config.general_call); |
| 225 | w.set_tclkstretch(true); | 299 | w.set_tclkstretch(true); |
| 226 | // Disable target wakeup, follow TI example. (TI note: Workaround for errata I2C_ERR_04.) | 300 | // Disable target wakeup, follow TI example. (TI note: Workaround for errata I2C_ERR_04.) |
| 227 | w.set_twuen(false); | 301 | w.set_twuen(false); |
