diff options
Diffstat (limited to 'embassy-mspm0/src/i2c.rs')
| -rw-r--r-- | embassy-mspm0/src/i2c.rs | 68 |
1 files changed, 34 insertions, 34 deletions
diff --git a/embassy-mspm0/src/i2c.rs b/embassy-mspm0/src/i2c.rs index 168cfccda..f99e02c59 100644 --- a/embassy-mspm0/src/i2c.rs +++ b/embassy-mspm0/src/i2c.rs | |||
| @@ -16,6 +16,7 @@ use crate::interrupt::{Interrupt, InterruptExt}; | |||
| 16 | use crate::mode::{Async, Blocking, Mode}; | 16 | use crate::mode::{Async, Blocking, Mode}; |
| 17 | use crate::pac::i2c::{vals, I2c as Regs}; | 17 | use crate::pac::i2c::{vals, I2c as Regs}; |
| 18 | use crate::pac::{self}; | 18 | use crate::pac::{self}; |
| 19 | use crate::time::Hertz; | ||
| 19 | use crate::Peri; | 20 | use crate::Peri; |
| 20 | 21 | ||
| 21 | /// The clock source for the I2C. | 22 | /// The clock source for the I2C. |
| @@ -31,9 +32,6 @@ pub enum ClockSel { | |||
| 31 | /// | 32 | /// |
| 32 | /// The MCLK runs at 4 MHz. | 33 | /// The MCLK runs at 4 MHz. |
| 33 | MfClk, | 34 | MfClk, |
| 34 | // BusClk, | ||
| 35 | // BusClk depends on the timer's power domain. | ||
| 36 | // This will be implemented later. | ||
| 37 | } | 35 | } |
| 38 | 36 | ||
| 39 | /// The clock divider for the I2C. | 37 | /// The clock divider for the I2C. |
| @@ -110,15 +108,15 @@ pub enum BusSpeed { | |||
| 110 | /// Custom mode. | 108 | /// Custom mode. |
| 111 | /// | 109 | /// |
| 112 | /// The custom mode frequency (in Hz) can be set manually. | 110 | /// The custom mode frequency (in Hz) can be set manually. |
| 113 | Custom(u32), | 111 | Custom(Hertz), |
| 114 | } | 112 | } |
| 115 | 113 | ||
| 116 | impl BusSpeed { | 114 | impl BusSpeed { |
| 117 | fn hertz(self) -> u32 { | 115 | fn hertz(self) -> Hertz { |
| 118 | match self { | 116 | match self { |
| 119 | Self::Standard => 100_000, | 117 | Self::Standard => Hertz::khz(100), |
| 120 | Self::FastMode => 400_000, | 118 | Self::FastMode => Hertz::khz(400), |
| 121 | Self::FastModePlus => 1_000_000, | 119 | Self::FastModePlus => Hertz::mhz(1), |
| 122 | Self::Custom(s) => s, | 120 | Self::Custom(s) => s, |
| 123 | } | 121 | } |
| 124 | } | 122 | } |
| @@ -168,7 +166,7 @@ impl Default for Config { | |||
| 168 | invert_scl: false, | 166 | invert_scl: false, |
| 169 | sda_pull: Pull::None, | 167 | sda_pull: Pull::None, |
| 170 | scl_pull: Pull::None, | 168 | scl_pull: Pull::None, |
| 171 | bus_speed: BusSpeed::FastMode, | 169 | bus_speed: BusSpeed::Standard, |
| 172 | } | 170 | } |
| 173 | } | 171 | } |
| 174 | } | 172 | } |
| @@ -180,28 +178,26 @@ impl Config { | |||
| 180 | pub fn scl_pf(&self) -> PfType { | 178 | pub fn scl_pf(&self) -> PfType { |
| 181 | PfType::input(self.scl_pull, self.invert_scl) | 179 | PfType::input(self.scl_pull, self.invert_scl) |
| 182 | } | 180 | } |
| 183 | fn timer_period(&self, clock_speed: u32) -> u8 { | 181 | fn timer_period(&self) -> u8 { |
| 184 | // Sets the timer period to bring the clock frequency to the selected I2C speed | 182 | // Sets the timer period to bring the clock frequency to the selected I2C speed |
| 185 | // From the documentation: SCL_PERIOD = (1 + TPR ) * (SCL_LP + SCL_HP ) * INT_CLK_PRD where: | 183 | // From the documentation: TPR = (I2C_CLK / (I2C_FREQ * (SCL_LP + SCL_HP))) - 1 where: |
| 186 | // - SCL_PRD is the SCL line period (I2C clock) | 184 | // - I2C_FREQ is desired I2C frequency (= I2C_BASE_FREQ divided by I2C_DIV) |
| 187 | // - TPR is the Timer Period register value (range of 1 to 127) | 185 | // - TPR is the Timer Period register value (range of 1 to 127) |
| 188 | // - SCL_LP is the SCL Low period (fixed at 6) | 186 | // - SCL_LP is the SCL Low period (fixed at 6) |
| 189 | // - SCL_HP is the SCL High period (fixed at 4) | 187 | // - SCL_HP is the SCL High period (fixed at 4) |
| 190 | // - CLK_PRD is the functional clock period in ns | 188 | // - I2C_CLK is functional clock frequency |
| 191 | let scl_period = (1.0 / self.bus_speed.hertz() as f64) * 1_000_000_000.0; | 189 | return (((self.calculate_clock_rate() * self.clock_div.divider()) / (self.bus_speed.hertz() * 10u32)) - 1) |
| 192 | let clock = (clock_speed as f64) / self.clock_div.divider() as f64; | 190 | .try_into() |
| 193 | let clk_period = (1.0 / clock) * 1_000_000_000.0; | 191 | .unwrap(); |
| 194 | let tpr = scl_period / (10.0 * clk_period) - 1.0; | ||
| 195 | tpr.clamp(0.0, 255.0) as u8 | ||
| 196 | } | 192 | } |
| 197 | 193 | ||
| 198 | #[cfg(any(mspm0c110x))] | 194 | #[cfg(any(mspm0c110x))] |
| 199 | pub fn calculate_clock_rate(&self) -> u32 { | 195 | pub fn calculate_clock_rate(&self) -> Hertz { |
| 200 | // Assume that BusClk has default value. | 196 | // Assume that BusClk has default value. |
| 201 | // TODO: calculate BusClk more precisely. | 197 | // TODO: calculate BusClk more precisely. |
| 202 | match self.clock_source { | 198 | match self.clock_source { |
| 203 | ClockSel::MfClk => 4_000_000, | 199 | ClockSel::MfClk => Hertz::mhz(4), |
| 204 | ClockSel::BusClk => 24_000_000, | 200 | ClockSel::BusClk => Hertz::mhz(24), |
| 205 | } | 201 | } |
| 206 | } | 202 | } |
| 207 | 203 | ||
| @@ -209,24 +205,24 @@ impl Config { | |||
| 209 | mspm0g110x, mspm0g150x, mspm0g151x, mspm0g310x, mspm0g350x, mspm0g351x, mspm0l110x, mspm0l122x, mspm0l130x, | 205 | mspm0g110x, mspm0g150x, mspm0g151x, mspm0g310x, mspm0g350x, mspm0g351x, mspm0l110x, mspm0l122x, mspm0l130x, |
| 210 | mspm0l134x, mspm0l222x | 206 | mspm0l134x, mspm0l222x |
| 211 | ))] | 207 | ))] |
| 212 | pub fn calculate_clock_rate(&self) -> u32 { | 208 | pub fn calculate_clock_rate(&self) -> Hertz { |
| 213 | // Assume that BusClk has default value. | 209 | // Assume that BusClk has default value. |
| 214 | // TODO: calculate BusClk more precisely. | 210 | // TODO: calculate BusClk more precisely. |
| 215 | match self.clock_source { | 211 | match self.clock_source { |
| 216 | ClockSel::MfClk => 4_000_000, | 212 | ClockSel::MfClk => Hertz::mhz(4), |
| 217 | ClockSel::BusClk => 32_000_000, | 213 | ClockSel::BusClk => Hertz::mhz(32), |
| 218 | } | 214 | } |
| 219 | } | 215 | } |
| 220 | 216 | ||
| 221 | pub fn check_clock_rate(&self) -> bool { | 217 | pub fn check_clock_rate(&self) -> bool { |
| 222 | // make sure source clock is ~20 faster than i2c clock | 218 | // make sure source clock is ~20 faster than i2c clock |
| 223 | let clk_ratio = 20; | 219 | let clk_ratio = 20u8; |
| 224 | 220 | ||
| 225 | let i2c_clk = self.bus_speed.hertz() / self.clock_div.divider(); | 221 | let i2c_clk = self.bus_speed.hertz() / self.clock_div.divider(); |
| 226 | let src_clk = self.calculate_clock_rate(); | 222 | let src_clk = self.calculate_clock_rate(); |
| 227 | 223 | ||
| 228 | // check clock rate | 224 | // check clock rate |
| 229 | return src_clk >= clk_ratio * i2c_clk; | 225 | return src_clk >= i2c_clk * clk_ratio; |
| 230 | } | 226 | } |
| 231 | } | 227 | } |
| 232 | 228 | ||
| @@ -380,15 +376,15 @@ impl<'d, M: Mode> I2c<'d, M> { | |||
| 380 | .cctr() | 376 | .cctr() |
| 381 | .write_value(i2c::regs::Cctr::default()); | 377 | .write_value(i2c::regs::Cctr::default()); |
| 382 | 378 | ||
| 383 | let clock = config.calculate_clock_rate(); | 379 | self.state |
| 384 | 380 | .clock | |
| 385 | self.state.clock.store(clock, Ordering::Relaxed); | 381 | .store(config.calculate_clock_rate().0, Ordering::Relaxed); |
| 386 | 382 | ||
| 387 | self.info | 383 | self.info |
| 388 | .regs | 384 | .regs |
| 389 | .controller(0) | 385 | .controller(0) |
| 390 | .ctpr() | 386 | .ctpr() |
| 391 | .write(|w| w.set_tpr(config.timer_period(clock))); | 387 | .write(|w| w.set_tpr(config.timer_period())); |
| 392 | 388 | ||
| 393 | // Set Tx Fifo threshold, follow TI example | 389 | // Set Tx Fifo threshold, follow TI example |
| 394 | self.info | 390 | self.info |
| @@ -1095,7 +1091,8 @@ mod tests { | |||
| 1095 | let mut config = Config::default(); | 1091 | let mut config = Config::default(); |
| 1096 | config.clock_div = ClockDiv::DivBy1; | 1092 | config.clock_div = ClockDiv::DivBy1; |
| 1097 | config.bus_speed = BusSpeed::FastMode; | 1093 | config.bus_speed = BusSpeed::FastMode; |
| 1098 | assert!(matches!(config.timer_period(32_000_000), 7)); | 1094 | config.clock_source = ClockSel::BusClk; |
| 1095 | assert!(matches!(config.timer_period(), 7)); | ||
| 1099 | } | 1096 | } |
| 1100 | 1097 | ||
| 1101 | #[test] | 1098 | #[test] |
| @@ -1103,7 +1100,8 @@ mod tests { | |||
| 1103 | let mut config = Config::default(); | 1100 | let mut config = Config::default(); |
| 1104 | config.clock_div = ClockDiv::DivBy2; | 1101 | config.clock_div = ClockDiv::DivBy2; |
| 1105 | config.bus_speed = BusSpeed::FastMode; | 1102 | config.bus_speed = BusSpeed::FastMode; |
| 1106 | assert!(matches!(config.timer_period(32_000_000), 3)); | 1103 | config.clock_source = ClockSel::BusClk; |
| 1104 | assert!(matches!(config.timer_period(), 3)); | ||
| 1107 | } | 1105 | } |
| 1108 | 1106 | ||
| 1109 | #[test] | 1107 | #[test] |
| @@ -1111,7 +1109,8 @@ mod tests { | |||
| 1111 | let mut config = Config::default(); | 1109 | let mut config = Config::default(); |
| 1112 | config.clock_div = ClockDiv::DivBy2; | 1110 | config.clock_div = ClockDiv::DivBy2; |
| 1113 | config.bus_speed = BusSpeed::Standard; | 1111 | config.bus_speed = BusSpeed::Standard; |
| 1114 | assert!(matches!(config.timer_period(32_000_000), 15)); | 1112 | config.clock_source = ClockSel::BusClk; |
| 1113 | assert!(matches!(config.timer_period(), 15)); | ||
| 1115 | } | 1114 | } |
| 1116 | 1115 | ||
| 1117 | #[test] | 1116 | #[test] |
| @@ -1119,7 +1118,8 @@ mod tests { | |||
| 1119 | let mut config = Config::default(); | 1118 | let mut config = Config::default(); |
| 1120 | config.clock_div = ClockDiv::DivBy2; | 1119 | config.clock_div = ClockDiv::DivBy2; |
| 1121 | config.bus_speed = BusSpeed::Custom(100_000); | 1120 | config.bus_speed = BusSpeed::Custom(100_000); |
| 1122 | assert!(matches!(config.timer_period(32_000_000), 15)); | 1121 | config.clock_source = ClockSel::BusClk; |
| 1122 | assert!(matches!(config.timer_period(), 15)); | ||
| 1123 | } | 1123 | } |
| 1124 | 1124 | ||
| 1125 | #[test] | 1125 | #[test] |
