aboutsummaryrefslogtreecommitdiff
path: root/embassy-mspm0
diff options
context:
space:
mode:
authorSiarhei B <[email protected]>2025-07-22 16:40:06 +0200
committerSiarhei B <[email protected]>2025-08-04 10:19:14 +0200
commit45852b852bf7623718f20ab9151655a417370655 (patch)
tree34dcec4f49278369c29b49d677171d9eea7d8c2a /embassy-mspm0
parentf9753f3d314ca00fb36103fa39b0911d3e3047ba (diff)
mspm0-I2C: add type for I2C clock rates + fixed comments
Diffstat (limited to 'embassy-mspm0')
-rw-r--r--embassy-mspm0/src/i2c.rs68
-rw-r--r--embassy-mspm0/src/lib.rs1
-rw-r--r--embassy-mspm0/src/time.rs102
3 files changed, 137 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};
16use crate::mode::{Async, Blocking, Mode}; 16use crate::mode::{Async, Blocking, Mode};
17use crate::pac::i2c::{vals, I2c as Regs}; 17use crate::pac::i2c::{vals, I2c as Regs};
18use crate::pac::{self}; 18use crate::pac::{self};
19use crate::time::Hertz;
19use crate::Peri; 20use 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
116impl BusSpeed { 114impl 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]
diff --git a/embassy-mspm0/src/lib.rs b/embassy-mspm0/src/lib.rs
index 403f9d50c..fd8450daf 100644
--- a/embassy-mspm0/src/lib.rs
+++ b/embassy-mspm0/src/lib.rs
@@ -16,6 +16,7 @@ mod macros;
16pub mod dma; 16pub mod dma;
17pub mod gpio; 17pub mod gpio;
18pub mod i2c; 18pub mod i2c;
19pub mod time;
19pub mod timer; 20pub mod timer;
20pub mod uart; 21pub mod uart;
21 22
diff --git a/embassy-mspm0/src/time.rs b/embassy-mspm0/src/time.rs
new file mode 100644
index 000000000..1353a909a
--- /dev/null
+++ b/embassy-mspm0/src/time.rs
@@ -0,0 +1,102 @@
1//! Time units
2
3use core::fmt::Display;
4use core::ops::{Div, Mul};
5
6/// Hertz
7#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug)]
8pub struct Hertz(pub u32);
9
10impl Display for Hertz {
11 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
12 write!(f, "{} Hz", self.0)
13 }
14}
15
16#[cfg(feature = "defmt")]
17impl defmt::Format for Hertz {
18 fn format(&self, f: defmt::Formatter) {
19 defmt::write!(f, "{=u32} Hz", self.0)
20 }
21}
22
23impl Hertz {
24 /// Create a `Hertz` from the given hertz.
25 pub const fn hz(hertz: u32) -> Self {
26 Self(hertz)
27 }
28
29 /// Create a `Hertz` from the given kilohertz.
30 pub const fn khz(kilohertz: u32) -> Self {
31 Self(kilohertz * 1_000)
32 }
33
34 /// Create a `Hertz` from the given megahertz.
35 pub const fn mhz(megahertz: u32) -> Self {
36 Self(megahertz * 1_000_000)
37 }
38}
39
40/// This is a convenience shortcut for [`Hertz::hz`]
41pub const fn hz(hertz: u32) -> Hertz {
42 Hertz::hz(hertz)
43}
44
45/// This is a convenience shortcut for [`Hertz::khz`]
46pub const fn khz(kilohertz: u32) -> Hertz {
47 Hertz::khz(kilohertz)
48}
49
50/// This is a convenience shortcut for [`Hertz::mhz`]
51pub const fn mhz(megahertz: u32) -> Hertz {
52 Hertz::mhz(megahertz)
53}
54
55impl Mul<u32> for Hertz {
56 type Output = Hertz;
57 fn mul(self, rhs: u32) -> Self::Output {
58 Hertz(self.0 * rhs)
59 }
60}
61
62impl Div<u32> for Hertz {
63 type Output = Hertz;
64 fn div(self, rhs: u32) -> Self::Output {
65 Hertz(self.0 / rhs)
66 }
67}
68
69impl Mul<u16> for Hertz {
70 type Output = Hertz;
71 fn mul(self, rhs: u16) -> Self::Output {
72 self * (rhs as u32)
73 }
74}
75
76impl Div<u16> for Hertz {
77 type Output = Hertz;
78 fn div(self, rhs: u16) -> Self::Output {
79 self / (rhs as u32)
80 }
81}
82
83impl Mul<u8> for Hertz {
84 type Output = Hertz;
85 fn mul(self, rhs: u8) -> Self::Output {
86 self * (rhs as u32)
87 }
88}
89
90impl Div<u8> for Hertz {
91 type Output = Hertz;
92 fn div(self, rhs: u8) -> Self::Output {
93 self / (rhs as u32)
94 }
95}
96
97impl Div<Hertz> for Hertz {
98 type Output = u32;
99 fn div(self, rhs: Hertz) -> Self::Output {
100 self.0 / rhs.0
101 }
102}