aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authori509VCB <[email protected]>2025-08-14 20:36:40 +0000
committerGitHub <[email protected]>2025-08-14 20:36:40 +0000
commit32f142d58587bb219b6835e1507758b7eb6f28b8 (patch)
treea75ab3442f368bdb2020ceee2392a8a04bbb4a6d
parent5bd4722b6018524748dad6343a79adf1a55f1aa9 (diff)
parentf84eb9a7eb2df85b2d0dc7a934f2568640ef6161 (diff)
Merge pull request #4435 from bespsm/mspm0-i2c
MSPM0: Add I2C Controller (blocking & async) + examples for mspm0l1306, mspm0g3507 (tested MCUs)
-rw-r--r--embassy-mspm0/CHANGELOG.md10
-rw-r--r--embassy-mspm0/Cargo.toml5
-rw-r--r--embassy-mspm0/build.rs5
-rw-r--r--embassy-mspm0/src/i2c.rs1208
-rw-r--r--embassy-mspm0/src/lib.rs1
-rw-r--r--examples/mspm0g3507/src/bin/i2c.rs45
-rw-r--r--examples/mspm0g3507/src/bin/i2c_async.rs50
-rw-r--r--examples/mspm0l1306/Cargo.toml4
-rw-r--r--examples/mspm0l1306/src/bin/i2c.rs45
-rw-r--r--examples/mspm0l1306/src/bin/i2c_async.rs50
10 files changed, 1421 insertions, 2 deletions
diff --git a/embassy-mspm0/CHANGELOG.md b/embassy-mspm0/CHANGELOG.md
new file mode 100644
index 000000000..7c22b2f28
--- /dev/null
+++ b/embassy-mspm0/CHANGELOG.md
@@ -0,0 +1,10 @@
1# Changelog for embassy-mspm0
2
3All notable changes to this project will be documented in this file.
4
5The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
8## Unreleased - ReleaseDate
9
10- feat: Add I2C Controller (blocking & async) + examples for mspm0l1306, mspm0g3507 (tested MCUs) (#4435)
diff --git a/embassy-mspm0/Cargo.toml b/embassy-mspm0/Cargo.toml
index ae0c93862..221026b26 100644
--- a/embassy-mspm0/Cargo.toml
+++ b/embassy-mspm0/Cargo.toml
@@ -35,6 +35,7 @@ embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal", fe
35embassy-embedded-hal = { version = "0.4.0", path = "../embassy-embedded-hal", default-features = false } 35embassy-embedded-hal = { version = "0.4.0", path = "../embassy-embedded-hal", default-features = false }
36embassy-executor = { version = "0.8.0", path = "../embassy-executor", optional = true } 36embassy-executor = { version = "0.8.0", path = "../embassy-executor", optional = true }
37 37
38embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
38embedded-hal = { version = "1.0" } 39embedded-hal = { version = "1.0" }
39embedded-hal-nb = { version = "1.0" } 40embedded-hal-nb = { version = "1.0" }
40embedded-hal-async = { version = "1.0" } 41embedded-hal-async = { version = "1.0" }
@@ -49,7 +50,7 @@ cortex-m = "0.7.6"
49critical-section = "1.2.0" 50critical-section = "1.2.0"
50 51
51# mspm0-metapac = { version = "" } 52# mspm0-metapac = { version = "" }
52mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-235158ac2865d8aac3a1eceb2d62026eb12bf38f" } 53mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-df572e257eabf06e6e0ae6c9077e0a2fec1fb5e1" }
53 54
54[build-dependencies] 55[build-dependencies]
55proc-macro2 = "1.0.94" 56proc-macro2 = "1.0.94"
@@ -57,7 +58,7 @@ quote = "1.0.40"
57cfg_aliases = "0.2.1" 58cfg_aliases = "0.2.1"
58 59
59# mspm0-metapac = { version = "", default-features = false, features = ["metadata"] } 60# mspm0-metapac = { version = "", default-features = false, features = ["metadata"] }
60mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-235158ac2865d8aac3a1eceb2d62026eb12bf38f", default-features = false, features = ["metadata"] } 61mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-df572e257eabf06e6e0ae6c9077e0a2fec1fb5e1", default-features = false, features = ["metadata"] }
61 62
62[features] 63[features]
63default = ["rt"] 64default = ["rt"]
diff --git a/embassy-mspm0/build.rs b/embassy-mspm0/build.rs
index b9ba3aecf..efbe6645f 100644
--- a/embassy-mspm0/build.rs
+++ b/embassy-mspm0/build.rs
@@ -549,9 +549,11 @@ fn generate_peripheral_instances() -> TokenStream {
549 549
550 for peripheral in METADATA.peripherals { 550 for peripheral in METADATA.peripherals {
551 let peri = format_ident!("{}", peripheral.name); 551 let peri = format_ident!("{}", peripheral.name);
552 let fifo_size = peripheral.sys_fentries;
552 553
553 let tokens = match peripheral.kind { 554 let tokens = match peripheral.kind {
554 "uart" => Some(quote! { impl_uart_instance!(#peri); }), 555 "uart" => Some(quote! { impl_uart_instance!(#peri); }),
556 "i2c" => Some(quote! { impl_i2c_instance!(#peri, #fifo_size); }),
555 _ => None, 557 _ => None,
556 }; 558 };
557 559
@@ -598,6 +600,9 @@ fn generate_pin_trait_impls() -> TokenStream {
598 ("uart", "RX") => Some(quote! { impl_uart_rx_pin!(#peri, #pin_name, #pf); }), 600 ("uart", "RX") => Some(quote! { impl_uart_rx_pin!(#peri, #pin_name, #pf); }),
599 ("uart", "CTS") => Some(quote! { impl_uart_cts_pin!(#peri, #pin_name, #pf); }), 601 ("uart", "CTS") => Some(quote! { impl_uart_cts_pin!(#peri, #pin_name, #pf); }),
600 ("uart", "RTS") => Some(quote! { impl_uart_rts_pin!(#peri, #pin_name, #pf); }), 602 ("uart", "RTS") => Some(quote! { impl_uart_rts_pin!(#peri, #pin_name, #pf); }),
603 ("i2c", "SDA") => Some(quote! { impl_i2c_sda_pin!(#peri, #pin_name, #pf); }),
604 ("i2c", "SCL") => Some(quote! { impl_i2c_scl_pin!(#peri, #pin_name, #pf); }),
605
601 _ => None, 606 _ => None,
602 }; 607 };
603 608
diff --git a/embassy-mspm0/src/i2c.rs b/embassy-mspm0/src/i2c.rs
new file mode 100644
index 000000000..7e22bb724
--- /dev/null
+++ b/embassy-mspm0/src/i2c.rs
@@ -0,0 +1,1208 @@
1#![macro_use]
2
3use core::future;
4use core::marker::PhantomData;
5use core::sync::atomic::{AtomicU32, Ordering};
6use core::task::Poll;
7
8use embassy_embedded_hal::SetConfig;
9use embassy_hal_internal::PeripheralType;
10use embassy_sync::waitqueue::AtomicWaker;
11use mspm0_metapac::i2c;
12
13use crate::gpio::{AnyPin, PfType, Pull, SealedPin};
14use crate::interrupt::typelevel::Binding;
15use crate::interrupt::{Interrupt, InterruptExt};
16use crate::mode::{Async, Blocking, Mode};
17use crate::pac::i2c::{vals, I2c as Regs};
18use crate::pac::{self};
19use crate::Peri;
20
21/// The clock source for the I2C.
22#[derive(Clone, Copy, PartialEq, Eq, Debug)]
23#[cfg_attr(feature = "defmt", derive(defmt::Format))]
24pub enum ClockSel {
25 /// Use the bus clock.
26 ///
27 /// Configurable clock.
28 BusClk,
29
30 /// Use the middle frequency clock.
31 ///
32 /// The MCLK runs at 4 MHz.
33 MfClk,
34}
35
36/// The clock divider for the I2C.
37#[derive(Clone, Copy, PartialEq, Eq, Debug)]
38#[cfg_attr(feature = "defmt", derive(defmt::Format))]
39pub enum ClockDiv {
40 // "Do not divide clock source.
41 DivBy1,
42 // "Divide clock source by 2.
43 DivBy2,
44 // "Divide clock source by 3.
45 DivBy3,
46 // "Divide clock source by 4.
47 DivBy4,
48 // "Divide clock source by 5.
49 DivBy5,
50 // "Divide clock source by 6.
51 DivBy6,
52 // "Divide clock source by 7.
53 DivBy7,
54 // "Divide clock source by 8.
55 DivBy8,
56}
57
58impl ClockDiv {
59 fn into(self) -> vals::Ratio {
60 match self {
61 Self::DivBy1 => vals::Ratio::DIV_BY_1,
62 Self::DivBy2 => vals::Ratio::DIV_BY_2,
63 Self::DivBy3 => vals::Ratio::DIV_BY_3,
64 Self::DivBy4 => vals::Ratio::DIV_BY_4,
65 Self::DivBy5 => vals::Ratio::DIV_BY_5,
66 Self::DivBy6 => vals::Ratio::DIV_BY_6,
67 Self::DivBy7 => vals::Ratio::DIV_BY_7,
68 Self::DivBy8 => vals::Ratio::DIV_BY_8,
69 }
70 }
71
72 fn divider(self) -> u32 {
73 match self {
74 Self::DivBy1 => 1,
75 Self::DivBy2 => 2,
76 Self::DivBy3 => 3,
77 Self::DivBy4 => 4,
78 Self::DivBy5 => 5,
79 Self::DivBy6 => 6,
80 Self::DivBy7 => 7,
81 Self::DivBy8 => 8,
82 }
83 }
84}
85
86/// The I2C mode.
87#[derive(Clone, Copy, PartialEq, Eq, Debug)]
88#[cfg_attr(feature = "defmt", derive(defmt::Format))]
89pub enum BusSpeed {
90 /// Standard mode.
91 ///
92 /// The Standard mode runs at 100 kHz.
93 Standard,
94
95 /// Fast mode.
96 ///
97 /// The fast mode runs at 400 kHz.
98 FastMode,
99
100 /// Fast mode plus.
101 ///
102 /// The fast mode plus runs at 1 MHz.
103 FastModePlus,
104
105 /// Custom mode.
106 ///
107 /// The custom mode frequency (in Hz) can be set manually.
108 Custom(u32),
109}
110
111impl BusSpeed {
112 fn hertz(self) -> u32 {
113 match self {
114 Self::Standard => 100_000,
115 Self::FastMode => 400_000,
116 Self::FastModePlus => 1_000_000,
117 Self::Custom(s) => s,
118 }
119 }
120}
121
122#[non_exhaustive]
123#[derive(Clone, Copy, PartialEq, Eq, Debug)]
124#[cfg_attr(feature = "defmt", derive(defmt::Format))]
125/// Config Error
126pub enum ConfigError {
127 /// Invalid clock rate.
128 ///
129 /// The clock rate could not be configured with the given conifguratoin.
130 InvalidClockRate,
131
132 /// Clock source not enabled.
133 ///
134 /// The clock soure is not enabled is SYSCTL.
135 ClockSourceNotEnabled,
136}
137
138#[non_exhaustive]
139#[derive(Clone, Copy, PartialEq, Eq, Debug)]
140/// Config
141pub struct Config {
142 /// I2C clock source.
143 clock_source: ClockSel,
144
145 /// I2C clock divider.
146 pub clock_div: ClockDiv,
147
148 /// If true: invert SDA pin signal values (V<sub>DD</sub> = 0/mark, Gnd = 1/idle).
149 pub invert_sda: bool,
150
151 /// If true: invert SCL pin signal values (V<sub>DD</sub> = 0/mark, Gnd = 1/idle).
152 pub invert_scl: bool,
153
154 /// Set the pull configuration for the SDA pin.
155 pub sda_pull: Pull,
156
157 /// Set the pull configuration for the SCL pin.
158 pub scl_pull: Pull,
159
160 /// Set the pull configuration for the SCL pin.
161 pub bus_speed: BusSpeed,
162}
163
164impl Default for Config {
165 fn default() -> Self {
166 Self {
167 clock_source: ClockSel::MfClk,
168 clock_div: ClockDiv::DivBy1,
169 invert_sda: false,
170 invert_scl: false,
171 sda_pull: Pull::None,
172 scl_pull: Pull::None,
173 bus_speed: BusSpeed::Standard,
174 }
175 }
176}
177
178impl Config {
179 pub fn sda_pf(&self) -> PfType {
180 PfType::input(self.sda_pull, self.invert_sda)
181 }
182 pub fn scl_pf(&self) -> PfType {
183 PfType::input(self.scl_pull, self.invert_scl)
184 }
185 fn calculate_timer_period(&self) -> u8 {
186 // Sets the timer period to bring the clock frequency to the selected I2C speed
187 // From the documentation: TPR = (I2C_CLK / (I2C_FREQ * (SCL_LP + SCL_HP))) - 1 where:
188 // - I2C_FREQ is desired I2C frequency (= I2C_BASE_FREQ divided by I2C_DIV)
189 // - TPR is the Timer Period register value (range of 1 to 127)
190 // - SCL_LP is the SCL Low period (fixed at 6)
191 // - SCL_HP is the SCL High period (fixed at 4)
192 // - I2C_CLK is functional clock frequency
193 return ((self.calculate_clock_source() / (self.bus_speed.hertz() * 10u32)) - 1)
194 .try_into()
195 .unwrap();
196 }
197
198 #[cfg(any(mspm0c110x))]
199 fn calculate_clock_source(&self) -> u32 {
200 // Assume that BusClk has default value.
201 // TODO: calculate BusClk more precisely.
202 match self.clock_source {
203 ClockSel::MfClk => 4_000_000 / self.clock_div.divider(),
204 ClockSel::BusClk => 24_000_000 / self.clock_div.divider(),
205 }
206 }
207
208 #[cfg(any(
209 mspm0g110x, mspm0g150x, mspm0g151x, mspm0g310x, mspm0g350x, mspm0g351x, mspm0l110x, mspm0l122x, mspm0l130x,
210 mspm0l134x, mspm0l222x
211 ))]
212 fn calculate_clock_source(&self) -> u32 {
213 // Assume that BusClk has default value.
214 // TODO: calculate BusClk more precisely.
215 match self.clock_source {
216 ClockSel::MfClk => 4_000_000 / self.clock_div.divider(),
217 ClockSel::BusClk => 32_000_000 / self.clock_div.divider(),
218 }
219 }
220
221 fn check_clock_i2c(&self) -> bool {
222 // make sure source clock is ~20 faster than i2c clock
223 let clk_ratio = 20;
224
225 let i2c_clk = self.bus_speed.hertz() / self.clock_div.divider();
226 let src_clk = self.calculate_clock_source();
227
228 // check clock rate
229 return src_clk >= i2c_clk * clk_ratio;
230 }
231
232 fn define_clock_source(&mut self) -> bool {
233 // decide which clock source to choose based on i2c clock.
234 // If i2c speed <= 200kHz, use MfClk, otherwise use BusClk
235 if self.bus_speed.hertz() / self.clock_div.divider() > 200_000 {
236 // TODO: check if BUSCLK enabled
237 self.clock_source = ClockSel::BusClk;
238 } else {
239 // is MFCLK enabled
240 if !pac::SYSCTL.mclkcfg().read().usemftick() {
241 return false;
242 }
243 self.clock_source = ClockSel::MfClk;
244 }
245 return true;
246 }
247
248 /// Check the config.
249 ///
250 /// Make sure that configuration is valid and enabled by the system.
251 pub fn check_config(&mut self) -> Result<(), ConfigError> {
252 if !self.define_clock_source() {
253 return Err(ConfigError::ClockSourceNotEnabled);
254 }
255
256 if !self.check_clock_i2c() {
257 return Err(ConfigError::InvalidClockRate);
258 }
259
260 Ok(())
261 }
262}
263
264/// Serial error
265#[derive(Debug, Eq, PartialEq, Copy, Clone)]
266#[cfg_attr(feature = "defmt", derive(defmt::Format))]
267#[non_exhaustive]
268pub enum Error {
269 /// Bus error
270 Bus,
271
272 /// Arbitration lost
273 Arbitration,
274
275 /// ACK not received (either to the address or to a data byte)
276 Nack,
277
278 /// Timeout
279 Timeout,
280
281 /// CRC error
282 Crc,
283
284 /// Overrun error
285 Overrun,
286
287 /// Zero-length transfers are not allowed.
288 ZeroLengthTransfer,
289
290 /// Transfer length is over limit.
291 TransferLengthIsOverLimit,
292}
293
294impl core::fmt::Display for Error {
295 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
296 let message = match self {
297 Self::Bus => "Bus Error",
298 Self::Arbitration => "Arbitration Lost",
299 Self::Nack => "ACK Not Received",
300 Self::Timeout => "Request Timed Out",
301 Self::Crc => "CRC Mismatch",
302 Self::Overrun => "Buffer Overrun",
303 Self::ZeroLengthTransfer => "Zero-Length Transfers are not allowed",
304 Self::TransferLengthIsOverLimit => "Transfer length is over limit",
305 };
306
307 write!(f, "{}", message)
308 }
309}
310
311impl core::error::Error for Error {}
312
313/// I2C Driver.
314pub struct I2c<'d, M: Mode> {
315 info: &'static Info,
316 state: &'static State,
317 scl: Option<Peri<'d, AnyPin>>,
318 sda: Option<Peri<'d, AnyPin>>,
319 _phantom: PhantomData<M>,
320}
321
322impl<'d, M: Mode> SetConfig for I2c<'d, M> {
323 type Config = Config;
324 type ConfigError = ConfigError;
325
326 fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> {
327 self.set_config(*config)
328 }
329}
330
331impl<'d> I2c<'d, Blocking> {
332 pub fn new_blocking<T: Instance>(
333 peri: Peri<'d, T>,
334 scl: Peri<'d, impl SclPin<T>>,
335 sda: Peri<'d, impl SdaPin<T>>,
336 mut config: Config,
337 ) -> Result<Self, ConfigError> {
338 if let Err(err) = config.check_config() {
339 return Err(err);
340 }
341
342 Self::new_inner(peri, scl, sda, config)
343 }
344}
345
346impl<'d> I2c<'d, Async> {
347 pub fn new_async<T: Instance>(
348 peri: Peri<'d, T>,
349 scl: Peri<'d, impl SclPin<T>>,
350 sda: Peri<'d, impl SdaPin<T>>,
351 _irq: impl Binding<T::Interrupt, InterruptHandler<T>> + 'd,
352 mut config: Config,
353 ) -> Result<Self, ConfigError> {
354 if let Err(err) = config.check_config() {
355 return Err(err);
356 }
357
358 let i2c = Self::new_inner(peri, scl, sda, config);
359
360 T::info().interrupt.unpend();
361 unsafe { T::info().interrupt.enable() };
362
363 i2c
364 }
365}
366
367impl<'d, M: Mode> I2c<'d, M> {
368 /// Reconfigure the driver
369 pub fn set_config(&mut self, mut config: Config) -> Result<(), ConfigError> {
370 if let Err(err) = config.check_config() {
371 return Err(err);
372 }
373
374 self.info.interrupt.disable();
375
376 if let Some(ref sda) = self.sda {
377 sda.update_pf(config.sda_pf());
378 }
379
380 if let Some(ref scl) = self.scl {
381 scl.update_pf(config.scl_pf());
382 }
383
384 self.init(&config)
385 }
386
387 fn init(&mut self, config: &Config) -> Result<(), ConfigError> {
388 // Init I2C
389 self.info.regs.clksel().write(|w| match config.clock_source {
390 ClockSel::BusClk => {
391 w.set_mfclk_sel(false);
392 w.set_busclk_sel(true);
393 }
394 ClockSel::MfClk => {
395 w.set_mfclk_sel(true);
396 w.set_busclk_sel(false);
397 }
398 });
399 self.info.regs.clkdiv().write(|w| w.set_ratio(config.clock_div.into()));
400
401 // set up glitch filter
402 self.info.regs.gfctl().modify(|w| {
403 w.set_agfen(false);
404 w.set_agfsel(vals::Agfsel::AGLIT_50);
405 w.set_chain(true);
406 });
407
408 // Reset controller transfer, follow TI example
409 self.info.regs.controller(0).cctr().modify(|w| {
410 w.set_burstrun(false);
411 w.set_start(false);
412 w.set_stop(false);
413 w.set_ack(false);
414 w.set_cackoen(false);
415 w.set_rd_on_txempty(false);
416 w.set_cblen(0);
417 });
418
419 self.state
420 .clock
421 .store(config.calculate_clock_source(), Ordering::Relaxed);
422
423 self.info
424 .regs
425 .controller(0)
426 .ctpr()
427 .write(|w| w.set_tpr(config.calculate_timer_period()));
428
429 // Set Tx Fifo threshold, follow TI example
430 self.info
431 .regs
432 .controller(0)
433 .cfifoctl()
434 .write(|w| w.set_txtrig(vals::CfifoctlTxtrig::EMPTY));
435 // Set Rx Fifo threshold, follow TI example
436 self.info
437 .regs
438 .controller(0)
439 .cfifoctl()
440 .write(|w| w.set_rxtrig(vals::CfifoctlRxtrig::LEVEL_1));
441 // Enable controller clock stretching, follow TI example
442
443 self.info.regs.controller(0).ccr().modify(|w| {
444 w.set_clkstretch(true);
445 w.set_active(true);
446 });
447
448 Ok(())
449 }
450
451 fn master_stop(&mut self) {
452 // not the first transaction, delay 1000 cycles
453 cortex_m::asm::delay(1000);
454
455 // Stop transaction
456 self.info.regs.controller(0).cctr().modify(|w| {
457 w.set_cblen(0);
458 w.set_stop(true);
459 w.set_start(false);
460 });
461 }
462
463 fn master_continue(&mut self, length: usize, send_ack_nack: bool, send_stop: bool) -> Result<(), Error> {
464 // delay between ongoing transactions, 1000 cycles
465 cortex_m::asm::delay(1000);
466
467 // Update transaction to length amount of bytes
468 self.info.regs.controller(0).cctr().modify(|w| {
469 w.set_cblen(length as u16);
470 w.set_start(false);
471 w.set_ack(send_ack_nack);
472 if send_stop {
473 w.set_stop(true);
474 }
475 });
476
477 Ok(())
478 }
479
480 fn master_read(
481 &mut self,
482 address: u8,
483 length: usize,
484 restart: bool,
485 send_ack_nack: bool,
486 send_stop: bool,
487 ) -> Result<(), Error> {
488 if restart {
489 // not the first transaction, delay 1000 cycles
490 cortex_m::asm::delay(1000);
491 }
492
493 // Set START and prepare to receive bytes into
494 // `buffer`. The START bit can be set even if the bus
495 // is BUSY or I2C is in slave mode.
496 self.info.regs.controller(0).csa().modify(|w| {
497 w.set_taddr(address as u16);
498 w.set_cmode(vals::Mode::MODE7);
499 w.set_dir(vals::Dir::RECEIVE);
500 });
501
502 self.info.regs.controller(0).cctr().modify(|w| {
503 w.set_cblen(length as u16);
504 w.set_burstrun(true);
505 w.set_ack(send_ack_nack);
506 w.set_start(true);
507 if send_stop {
508 w.set_stop(true);
509 }
510 });
511
512 Ok(())
513 }
514
515 fn master_write(&mut self, address: u8, length: usize, send_stop: bool) -> Result<(), Error> {
516 // Start transfer of length amount of bytes
517 self.info.regs.controller(0).csa().modify(|w| {
518 w.set_taddr(address as u16);
519 w.set_cmode(vals::Mode::MODE7);
520 w.set_dir(vals::Dir::TRANSMIT);
521 });
522 self.info.regs.controller(0).cctr().modify(|w| {
523 w.set_cblen(length as u16);
524 w.set_burstrun(true);
525 w.set_start(true);
526 if send_stop {
527 w.set_stop(true);
528 }
529 });
530
531 Ok(())
532 }
533
534 fn check_error(&self) -> Result<(), Error> {
535 let csr = self.info.regs.controller(0).csr().read();
536 if csr.err() {
537 return Err(Error::Nack);
538 } else if csr.arblst() {
539 return Err(Error::Arbitration);
540 }
541 Ok(())
542 }
543}
544
545impl<'d> I2c<'d, Blocking> {
546 fn master_blocking_continue(&mut self, length: usize, send_ack_nack: bool, send_stop: bool) -> Result<(), Error> {
547 // Perform transaction
548 self.master_continue(length, send_ack_nack, send_stop)?;
549
550 // Poll until the Controller process all bytes or NACK
551 while self.info.regs.controller(0).csr().read().busy() {}
552
553 Ok(())
554 }
555
556 fn master_blocking_read(
557 &mut self,
558 address: u8,
559 length: usize,
560 restart: bool,
561 send_ack_nack: bool,
562 send_stop: bool,
563 ) -> Result<(), Error> {
564 // unless restart, Wait for the controller to be idle,
565 if !restart {
566 while !self.info.regs.controller(0).csr().read().idle() {}
567 }
568
569 self.master_read(address, length, restart, send_ack_nack, send_stop)?;
570
571 // Poll until the Controller process all bytes or NACK
572 while self.info.regs.controller(0).csr().read().busy() {}
573
574 Ok(())
575 }
576
577 fn master_blocking_write(&mut self, address: u8, length: usize, send_stop: bool) -> Result<(), Error> {
578 // Wait for the controller to be idle
579 while !self.info.regs.controller(0).csr().read().idle() {}
580
581 // Perform writing
582 self.master_write(address, length, send_stop)?;
583
584 // Poll until the Controller writes all bytes or NACK
585 while self.info.regs.controller(0).csr().read().busy() {}
586
587 Ok(())
588 }
589
590 fn read_blocking_internal(
591 &mut self,
592 address: u8,
593 read: &mut [u8],
594 restart: bool,
595 end_w_stop: bool,
596 ) -> Result<(), Error> {
597 if read.is_empty() {
598 return Err(Error::ZeroLengthTransfer);
599 }
600 if read.len() > self.info.fifo_size {
601 return Err(Error::TransferLengthIsOverLimit);
602 }
603
604 let read_len = read.len();
605 let mut bytes_to_read = read_len;
606 for (number, chunk) in read.chunks_mut(self.info.fifo_size).enumerate() {
607 bytes_to_read -= chunk.len();
608 // if the current transaction is the last & end_w_stop, send stop
609 let send_stop = bytes_to_read == 0 && end_w_stop;
610 // if there are still bytes to read, send ACK
611 let send_ack_nack = bytes_to_read != 0;
612
613 if number == 0 {
614 self.master_blocking_read(
615 address,
616 chunk.len().min(self.info.fifo_size),
617 restart,
618 send_ack_nack,
619 send_stop,
620 )?
621 } else {
622 self.master_blocking_continue(chunk.len(), send_ack_nack, send_stop)?;
623 }
624
625 // check errors
626 if let Err(err) = self.check_error() {
627 self.master_stop();
628 return Err(err);
629 }
630
631 for byte in chunk {
632 *byte = self.info.regs.controller(0).crxdata().read().value();
633 }
634 }
635 Ok(())
636 }
637
638 fn write_blocking_internal(&mut self, address: u8, write: &[u8], end_w_stop: bool) -> Result<(), Error> {
639 if write.is_empty() {
640 return Err(Error::ZeroLengthTransfer);
641 }
642 if write.len() > self.info.fifo_size {
643 return Err(Error::TransferLengthIsOverLimit);
644 }
645
646 let mut bytes_to_send = write.len();
647 for (number, chunk) in write.chunks(self.info.fifo_size).enumerate() {
648 for byte in chunk {
649 let ctrl0 = self.info.regs.controller(0).ctxdata();
650 ctrl0.write(|w| w.set_value(*byte));
651 }
652
653 // if the current transaction is the last & end_w_stop, send stop
654 bytes_to_send -= chunk.len();
655 let send_stop = end_w_stop && bytes_to_send == 0;
656
657 if number == 0 {
658 self.master_blocking_write(address, chunk.len(), send_stop)?;
659 } else {
660 self.master_blocking_continue(chunk.len(), false, send_stop)?;
661 }
662
663 // check errors
664 if let Err(err) = self.check_error() {
665 self.master_stop();
666 return Err(err);
667 }
668 }
669 Ok(())
670 }
671
672 // =========================
673 // Blocking public API
674
675 /// Blocking read.
676 pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> {
677 // wait until bus is free
678 while self.info.regs.controller(0).csr().read().busbsy() {}
679 self.read_blocking_internal(address, read, false, true)
680 }
681
682 /// Blocking write.
683 pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
684 // wait until bus is free
685 while self.info.regs.controller(0).csr().read().busbsy() {}
686 self.write_blocking_internal(address, write, true)
687 }
688
689 /// Blocking write, restart, read.
690 pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
691 // wait until bus is free
692 while self.info.regs.controller(0).csr().read().busbsy() {}
693 let err = self.write_blocking_internal(address, write, false);
694 if err != Ok(()) {
695 return err;
696 }
697 self.read_blocking_internal(address, read, true, true)
698 }
699}
700
701impl<'d> I2c<'d, Async> {
702 async fn write_async_internal(&mut self, addr: u8, write: &[u8], end_w_stop: bool) -> Result<(), Error> {
703 let ctrl = self.info.regs.controller(0);
704
705 let mut bytes_to_send = write.len();
706 for (number, chunk) in write.chunks(self.info.fifo_size).enumerate() {
707 self.info.regs.cpu_int(0).imask().modify(|w| {
708 w.set_carblost(true);
709 w.set_cnack(true);
710 w.set_ctxdone(true);
711 });
712
713 for byte in chunk {
714 ctrl.ctxdata().write(|w| w.set_value(*byte));
715 }
716
717 // if the current transaction is the last & end_w_stop, send stop
718 bytes_to_send -= chunk.len();
719 let send_stop = end_w_stop && bytes_to_send == 0;
720
721 if number == 0 {
722 self.master_write(addr, chunk.len(), send_stop)?;
723 } else {
724 self.master_continue(chunk.len(), false, send_stop)?;
725 }
726
727 let res: Result<(), Error> = future::poll_fn(|cx| {
728 use crate::i2c::vals::CpuIntIidxStat;
729 // Register prior to checking the condition
730 self.state.waker.register(cx.waker());
731
732 let result = match self.info.regs.cpu_int(0).iidx().read().stat() {
733 CpuIntIidxStat::NO_INTR => Poll::Pending,
734 CpuIntIidxStat::CNACKFG => Poll::Ready(Err(Error::Nack)),
735 CpuIntIidxStat::CARBLOSTFG => Poll::Ready(Err(Error::Arbitration)),
736 CpuIntIidxStat::CTXDONEFG => Poll::Ready(Ok(())),
737 _ => Poll::Pending,
738 };
739
740 if !result.is_pending() {
741 self.info
742 .regs
743 .cpu_int(0)
744 .imask()
745 .write_value(i2c::regs::CpuInt::default());
746 }
747 return result;
748 })
749 .await;
750
751 if res.is_err() {
752 self.master_stop();
753 return res;
754 }
755 }
756 Ok(())
757 }
758
759 async fn read_async_internal(
760 &mut self,
761 addr: u8,
762 read: &mut [u8],
763 restart: bool,
764 end_w_stop: bool,
765 ) -> Result<(), Error> {
766 let read_len = read.len();
767
768 let mut bytes_to_read = read_len;
769 for (number, chunk) in read.chunks_mut(self.info.fifo_size).enumerate() {
770 bytes_to_read -= chunk.len();
771 // if the current transaction is the last & end_w_stop, send stop
772 let send_stop = bytes_to_read == 0 && end_w_stop;
773 // if there are still bytes to read, send ACK
774 let send_ack_nack = bytes_to_read != 0;
775
776 self.info.regs.cpu_int(0).imask().modify(|w| {
777 w.set_carblost(true);
778 w.set_cnack(true);
779 w.set_crxdone(true);
780 });
781
782 if number == 0 {
783 self.master_read(addr, chunk.len(), restart, send_ack_nack, send_stop)?
784 } else {
785 self.master_continue(chunk.len(), send_ack_nack, send_stop)?;
786 }
787
788 let res: Result<(), Error> = future::poll_fn(|cx| {
789 use crate::i2c::vals::CpuIntIidxStat;
790 // Register prior to checking the condition
791 self.state.waker.register(cx.waker());
792
793 let result = match self.info.regs.cpu_int(0).iidx().read().stat() {
794 CpuIntIidxStat::NO_INTR => Poll::Pending,
795 CpuIntIidxStat::CNACKFG => Poll::Ready(Err(Error::Nack)),
796 CpuIntIidxStat::CARBLOSTFG => Poll::Ready(Err(Error::Arbitration)),
797 CpuIntIidxStat::CRXDONEFG => Poll::Ready(Ok(())),
798 _ => Poll::Pending,
799 };
800
801 if !result.is_pending() {
802 self.info
803 .regs
804 .cpu_int(0)
805 .imask()
806 .write_value(i2c::regs::CpuInt::default());
807 }
808 return result;
809 })
810 .await;
811
812 if res.is_err() {
813 self.master_stop();
814 return res;
815 }
816
817 for byte in chunk {
818 *byte = self.info.regs.controller(0).crxdata().read().value();
819 }
820 }
821 Ok(())
822 }
823
824 // =========================
825 // Async public API
826
827 pub async fn async_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> {
828 // wait until bus is free
829 while self.info.regs.controller(0).csr().read().busbsy() {}
830 self.write_async_internal(address, write, true).await
831 }
832
833 pub async fn async_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> {
834 // wait until bus is free
835 while self.info.regs.controller(0).csr().read().busbsy() {}
836 self.read_async_internal(address, read, false, true).await
837 }
838
839 pub async fn async_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> {
840 // wait until bus is free
841 while self.info.regs.controller(0).csr().read().busbsy() {}
842
843 let err = self.write_async_internal(address, write, false).await;
844 if err != Ok(()) {
845 return err;
846 }
847 self.read_async_internal(address, read, true, true).await
848 }
849}
850
851impl<'d> embedded_hal_02::blocking::i2c::Read for I2c<'d, Blocking> {
852 type Error = Error;
853
854 fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
855 self.blocking_read(address, buffer)
856 }
857}
858
859impl<'d> embedded_hal_02::blocking::i2c::Write for I2c<'d, Blocking> {
860 type Error = Error;
861
862 fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> {
863 self.blocking_write(address, bytes)
864 }
865}
866
867impl<'d> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, Blocking> {
868 type Error = Error;
869
870 fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> {
871 self.blocking_write_read(address, bytes, buffer)
872 }
873}
874
875impl<'d> embedded_hal_02::blocking::i2c::Transactional for I2c<'d, Blocking> {
876 type Error = Error;
877
878 fn exec(
879 &mut self,
880 address: u8,
881 operations: &mut [embedded_hal_02::blocking::i2c::Operation<'_>],
882 ) -> Result<(), Self::Error> {
883 // wait until bus is free
884 while self.info.regs.controller(0).csr().read().busbsy() {}
885 for i in 0..operations.len() {
886 match &mut operations[i] {
887 embedded_hal_02::blocking::i2c::Operation::Read(buf) => {
888 self.read_blocking_internal(address, buf, false, false)?
889 }
890 embedded_hal_02::blocking::i2c::Operation::Write(buf) => {
891 self.write_blocking_internal(address, buf, false)?
892 }
893 }
894 }
895 self.master_stop();
896 Ok(())
897 }
898}
899
900impl embedded_hal::i2c::Error for Error {
901 fn kind(&self) -> embedded_hal::i2c::ErrorKind {
902 match *self {
903 Self::Bus => embedded_hal::i2c::ErrorKind::Bus,
904 Self::Arbitration => embedded_hal::i2c::ErrorKind::ArbitrationLoss,
905 Self::Nack => embedded_hal::i2c::ErrorKind::NoAcknowledge(embedded_hal::i2c::NoAcknowledgeSource::Unknown),
906 Self::Timeout => embedded_hal::i2c::ErrorKind::Other,
907 Self::Crc => embedded_hal::i2c::ErrorKind::Other,
908 Self::Overrun => embedded_hal::i2c::ErrorKind::Overrun,
909 Self::ZeroLengthTransfer => embedded_hal::i2c::ErrorKind::Other,
910 Self::TransferLengthIsOverLimit => embedded_hal::i2c::ErrorKind::Other,
911 }
912 }
913}
914
915impl<'d, M: Mode> embedded_hal::i2c::ErrorType for I2c<'d, M> {
916 type Error = Error;
917}
918
919impl<'d> embedded_hal::i2c::I2c for I2c<'d, Blocking> {
920 fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
921 self.blocking_read(address, read)
922 }
923
924 fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
925 self.blocking_write(address, write)
926 }
927
928 fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
929 self.blocking_write_read(address, write, read)
930 }
931
932 fn transaction(
933 &mut self,
934 address: u8,
935 operations: &mut [embedded_hal::i2c::Operation<'_>],
936 ) -> Result<(), Self::Error> {
937 // wait until bus is free
938 while self.info.regs.controller(0).csr().read().busbsy() {}
939 for i in 0..operations.len() {
940 match &mut operations[i] {
941 embedded_hal::i2c::Operation::Read(buf) => self.read_blocking_internal(address, buf, false, false)?,
942 embedded_hal::i2c::Operation::Write(buf) => self.write_blocking_internal(address, buf, false)?,
943 }
944 }
945 self.master_stop();
946 Ok(())
947 }
948}
949
950impl<'d> embedded_hal_async::i2c::I2c for I2c<'d, Async> {
951 async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> {
952 self.async_read(address, read).await
953 }
954
955 async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> {
956 self.async_write(address, write).await
957 }
958
959 async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> {
960 self.async_write_read(address, write, read).await
961 }
962
963 async fn transaction(
964 &mut self,
965 address: u8,
966 operations: &mut [embedded_hal::i2c::Operation<'_>],
967 ) -> Result<(), Self::Error> {
968 // wait until bus is free
969 while self.info.regs.controller(0).csr().read().busbsy() {}
970 for i in 0..operations.len() {
971 match &mut operations[i] {
972 embedded_hal::i2c::Operation::Read(buf) => self.read_async_internal(address, buf, false, false).await?,
973 embedded_hal::i2c::Operation::Write(buf) => self.write_async_internal(address, buf, false).await?,
974 }
975 }
976 self.master_stop();
977 Ok(())
978 }
979}
980
981/// Interrupt handler.
982pub struct InterruptHandler<T: Instance> {
983 _i2c: PhantomData<T>,
984}
985
986impl<T: Instance> crate::interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
987 // Mask interrupts and wake any task waiting for this interrupt
988 unsafe fn on_interrupt() {
989 T::state().waker.wake();
990 }
991}
992
993/// Peripheral instance trait.
994#[allow(private_bounds)]
995pub trait Instance: SealedInstance + PeripheralType {
996 type Interrupt: crate::interrupt::typelevel::Interrupt;
997}
998
999/// I2C `SDA` pin trait
1000pub trait SdaPin<T: Instance>: crate::gpio::Pin {
1001 /// Get the PF number needed to use this pin as `SDA`.
1002 fn pf_num(&self) -> u8;
1003}
1004
1005/// I2C `SCL` pin trait
1006pub trait SclPin<T: Instance>: crate::gpio::Pin {
1007 /// Get the PF number needed to use this pin as `SCL`.
1008 fn pf_num(&self) -> u8;
1009}
1010
1011// ==== IMPL types ====
1012
1013pub(crate) struct Info {
1014 pub(crate) regs: Regs,
1015 pub(crate) interrupt: Interrupt,
1016 pub fifo_size: usize,
1017}
1018
1019pub(crate) struct State {
1020 /// The clock rate of the I2C. This might be configured.
1021 pub(crate) clock: AtomicU32,
1022 pub(crate) waker: AtomicWaker,
1023}
1024
1025impl<'d, M: Mode> I2c<'d, M> {
1026 fn new_inner<T: Instance>(
1027 _peri: Peri<'d, T>,
1028 scl: Peri<'d, impl SclPin<T>>,
1029 sda: Peri<'d, impl SdaPin<T>>,
1030 config: Config,
1031 ) -> Result<Self, ConfigError> {
1032 // Init power for I2C
1033 T::info().regs.gprcm(0).rstctl().write(|w| {
1034 w.set_resetstkyclr(true);
1035 w.set_resetassert(true);
1036 w.set_key(vals::ResetKey::KEY);
1037 });
1038
1039 T::info().regs.gprcm(0).pwren().write(|w| {
1040 w.set_enable(true);
1041 w.set_key(vals::PwrenKey::KEY);
1042 });
1043
1044 // init delay, 16 cycles
1045 cortex_m::asm::delay(16);
1046
1047 // Init GPIO
1048 let scl_inner = new_pin!(scl, config.scl_pf());
1049 let sda_inner = new_pin!(sda, config.sda_pf());
1050
1051 if let Some(ref scl) = scl_inner {
1052 let pincm = pac::IOMUX.pincm(scl._pin_cm() as usize);
1053 pincm.modify(|w| {
1054 w.set_hiz1(true);
1055 });
1056 }
1057
1058 if let Some(ref sda) = sda_inner {
1059 let pincm = pac::IOMUX.pincm(sda._pin_cm() as usize);
1060 pincm.modify(|w| {
1061 w.set_hiz1(true);
1062 });
1063 }
1064
1065 let mut this = Self {
1066 info: T::info(),
1067 state: T::state(),
1068 scl: scl_inner,
1069 sda: sda_inner,
1070 _phantom: PhantomData,
1071 };
1072 this.init(&config)?;
1073
1074 Ok(this)
1075 }
1076}
1077
1078pub(crate) trait SealedInstance {
1079 fn info() -> &'static Info;
1080 fn state() -> &'static State;
1081}
1082
1083macro_rules! impl_i2c_instance {
1084 ($instance: ident, $fifo_size: expr) => {
1085 impl crate::i2c::SealedInstance for crate::peripherals::$instance {
1086 fn info() -> &'static crate::i2c::Info {
1087 use crate::i2c::Info;
1088 use crate::interrupt::typelevel::Interrupt;
1089
1090 const INFO: Info = Info {
1091 regs: crate::pac::$instance,
1092 interrupt: crate::interrupt::typelevel::$instance::IRQ,
1093 fifo_size: $fifo_size,
1094 };
1095 &INFO
1096 }
1097
1098 fn state() -> &'static crate::i2c::State {
1099 use crate::i2c::State;
1100 use crate::interrupt::typelevel::Interrupt;
1101
1102 static STATE: State = State {
1103 clock: core::sync::atomic::AtomicU32::new(0),
1104 waker: embassy_sync::waitqueue::AtomicWaker::new(),
1105 };
1106 &STATE
1107 }
1108 }
1109
1110 impl crate::i2c::Instance for crate::peripherals::$instance {
1111 type Interrupt = crate::interrupt::typelevel::$instance;
1112 }
1113 };
1114}
1115
1116macro_rules! impl_i2c_sda_pin {
1117 ($instance: ident, $pin: ident, $pf: expr) => {
1118 impl crate::i2c::SdaPin<crate::peripherals::$instance> for crate::peripherals::$pin {
1119 fn pf_num(&self) -> u8 {
1120 $pf
1121 }
1122 }
1123 };
1124}
1125
1126macro_rules! impl_i2c_scl_pin {
1127 ($instance: ident, $pin: ident, $pf: expr) => {
1128 impl crate::i2c::SclPin<crate::peripherals::$instance> for crate::peripherals::$pin {
1129 fn pf_num(&self) -> u8 {
1130 $pf
1131 }
1132 }
1133 };
1134}
1135
1136#[cfg(test)]
1137mod tests {
1138 use crate::i2c::{BusSpeed, ClockDiv, ClockSel, Config};
1139
1140 /// These tests are based on TI's reference caluclation.
1141 #[test]
1142 fn ti_calculate_timer_period() {
1143 let mut config = Config::default();
1144 config.clock_div = ClockDiv::DivBy1;
1145 config.bus_speed = BusSpeed::FastMode;
1146 config.clock_source = ClockSel::BusClk;
1147 assert_eq!(config.calculate_timer_period(), 7u8);
1148 }
1149
1150 #[test]
1151 fn ti_calculate_timer_period_2() {
1152 let mut config = Config::default();
1153 config.clock_div = ClockDiv::DivBy2;
1154 config.bus_speed = BusSpeed::FastMode;
1155 config.clock_source = ClockSel::BusClk;
1156 assert_eq!(config.calculate_timer_period(), 3u8);
1157 }
1158
1159 #[test]
1160 fn ti_calculate_timer_period_3() {
1161 let mut config = Config::default();
1162 config.clock_div = ClockDiv::DivBy2;
1163 config.bus_speed = BusSpeed::Standard;
1164 config.clock_source = ClockSel::BusClk;
1165 assert_eq!(config.calculate_timer_period(), 15u8);
1166 }
1167
1168 #[test]
1169 fn ti_calculate_timer_period_4() {
1170 let mut config = Config::default();
1171 config.clock_div = ClockDiv::DivBy2;
1172 config.bus_speed = BusSpeed::Custom(100_000);
1173 config.clock_source = ClockSel::BusClk;
1174 assert_eq!(config.calculate_timer_period(), 15u8);
1175 }
1176
1177 #[test]
1178 fn clock_check_fastmodeplus_rate_with_busclk() {
1179 let mut config = Config::default();
1180 config.clock_source = ClockSel::BusClk;
1181 config.bus_speed = BusSpeed::FastModePlus;
1182 assert!(config.check_clock_i2c());
1183 }
1184
1185 #[test]
1186 fn clock_check_fastmode_rate_with_busclk() {
1187 let mut config = Config::default();
1188 config.clock_source = ClockSel::BusClk;
1189 config.bus_speed = BusSpeed::FastMode;
1190 assert!(config.check_clock_i2c());
1191 }
1192
1193 #[test]
1194 fn clock_check_fastmodeplus_rate_with_mfclk() {
1195 let mut config = Config::default();
1196 config.clock_source = ClockSel::MfClk;
1197 config.bus_speed = BusSpeed::FastModePlus;
1198 assert!(!config.check_clock_i2c());
1199 }
1200
1201 #[test]
1202 fn clock_check_fastmode_rate_with_mfclk() {
1203 let mut config = Config::default();
1204 config.clock_source = ClockSel::MfClk;
1205 config.bus_speed = BusSpeed::FastMode;
1206 assert!(!config.check_clock_i2c());
1207 }
1208}
diff --git a/embassy-mspm0/src/lib.rs b/embassy-mspm0/src/lib.rs
index 629ebfa1f..54ac2d9e6 100644
--- a/embassy-mspm0/src/lib.rs
+++ b/embassy-mspm0/src/lib.rs
@@ -15,6 +15,7 @@ mod macros;
15 15
16pub mod dma; 16pub mod dma;
17pub mod gpio; 17pub mod gpio;
18pub mod i2c;
18pub mod timer; 19pub mod timer;
19pub mod uart; 20pub mod uart;
20 21
diff --git a/examples/mspm0g3507/src/bin/i2c.rs b/examples/mspm0g3507/src/bin/i2c.rs
new file mode 100644
index 000000000..8d1ed1726
--- /dev/null
+++ b/examples/mspm0g3507/src/bin/i2c.rs
@@ -0,0 +1,45 @@
1//! This example uses FIFO with polling, and the maximum FIFO size is 8.
2//! Refer to async example to handle larger packets.
3//!
4//! This example controls AD5171 digital potentiometer via I2C with the LP-MSPM0G3507 board.
5
6#![no_std]
7#![no_main]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_mspm0::i2c::{Config, I2c};
12use embassy_time::Timer;
13use {defmt_rtt as _, panic_halt as _};
14
15const ADDRESS: u8 = 0x6a;
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) -> ! {
19 let p = embassy_mspm0::init(Default::default());
20
21 let instance = p.I2C1;
22 let scl = p.PB2;
23 let sda = p.PB3;
24
25 let mut i2c = unwrap!(I2c::new_blocking(instance, scl, sda, Config::default()));
26
27 let mut pot_value: u8 = 0;
28
29 loop {
30 let to_write = [0u8, pot_value];
31
32 match i2c.blocking_write(ADDRESS, &to_write) {
33 Ok(()) => info!("New potentioemter value: {}", pot_value),
34 Err(e) => error!("I2c Error: {:?}", e),
35 }
36
37 pot_value += 1;
38 // if reached 64th position (max)
39 // start over from lowest value
40 if pot_value == 64 {
41 pot_value = 0;
42 }
43 Timer::after_millis(500).await;
44 }
45}
diff --git a/examples/mspm0g3507/src/bin/i2c_async.rs b/examples/mspm0g3507/src/bin/i2c_async.rs
new file mode 100644
index 000000000..d486e2a03
--- /dev/null
+++ b/examples/mspm0g3507/src/bin/i2c_async.rs
@@ -0,0 +1,50 @@
1//! The example uses FIFO and interrupts, wrapped in async API.
2//!
3//! This example controls AD5171 digital potentiometer via I2C with the LP-MSPM0G3507 board.
4
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_mspm0::bind_interrupts;
11use embassy_mspm0::i2c::{Config, I2c, InterruptHandler};
12use embassy_mspm0::peripherals::I2C1;
13use embassy_time::Timer;
14use {defmt_rtt as _, panic_halt as _};
15
16const ADDRESS: u8 = 0x6a;
17
18bind_interrupts!(struct Irqs {
19 I2C1 => InterruptHandler<I2C1>;
20});
21
22#[embassy_executor::main]
23async fn main(_spawner: Spawner) -> ! {
24 let p = embassy_mspm0::init(Default::default());
25
26 let instance = p.I2C1;
27 let scl = p.PB2;
28 let sda = p.PB3;
29
30 let mut i2c = unwrap!(I2c::new_async(instance, scl, sda, Irqs, Config::default()));
31
32 let mut pot_value: u8 = 0;
33
34 loop {
35 let to_write = [0u8, pot_value];
36
37 match i2c.async_write(ADDRESS, &to_write).await {
38 Ok(()) => info!("New potentioemter value: {}", pot_value),
39 Err(e) => error!("I2c Error: {:?}", e),
40 }
41
42 pot_value += 1;
43 // if reached 64th position (max)
44 // start over from lowest value
45 if pot_value == 64 {
46 pot_value = 0;
47 }
48 Timer::after_millis(500).await;
49 }
50}
diff --git a/examples/mspm0l1306/Cargo.toml b/examples/mspm0l1306/Cargo.toml
index 16562f3ee..724ca58a0 100644
--- a/examples/mspm0l1306/Cargo.toml
+++ b/examples/mspm0l1306/Cargo.toml
@@ -19,3 +19,7 @@ panic-semihosting = "0.6.0"
19 19
20[profile.release] 20[profile.release]
21debug = 2 21debug = 2
22
23[profile.dev]
24debug = 2
25opt-level = 2
diff --git a/examples/mspm0l1306/src/bin/i2c.rs b/examples/mspm0l1306/src/bin/i2c.rs
new file mode 100644
index 000000000..e8801c485
--- /dev/null
+++ b/examples/mspm0l1306/src/bin/i2c.rs
@@ -0,0 +1,45 @@
1//! This example uses FIFO with polling, and the maximum FIFO size is 8.
2//! Refer to async example to handle larger packets.
3//!
4//! This example controls AD5171 digital potentiometer via I2C with the LP-MSPM0L1306 board.
5
6#![no_std]
7#![no_main]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_mspm0::i2c::{Config, I2c};
12use embassy_time::Timer;
13use {defmt_rtt as _, panic_halt as _};
14
15const ADDRESS: u8 = 0x2c;
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) -> ! {
19 let p = embassy_mspm0::init(Default::default());
20
21 let instance = p.I2C0;
22 let scl = p.PA1;
23 let sda = p.PA0;
24
25 let mut i2c = unwrap!(I2c::new_blocking(instance, scl, sda, Config::default()));
26
27 let mut pot_value: u8 = 0;
28
29 loop {
30 let to_write = [0u8, pot_value];
31
32 match i2c.blocking_write(ADDRESS, &to_write) {
33 Ok(()) => info!("New potentioemter value: {}", pot_value),
34 Err(e) => error!("I2c Error: {:?}", e),
35 }
36
37 pot_value += 1;
38 // if reached 64th position (max)
39 // start over from lowest value
40 if pot_value == 64 {
41 pot_value = 0;
42 }
43 Timer::after_millis(500).await;
44 }
45}
diff --git a/examples/mspm0l1306/src/bin/i2c_async.rs b/examples/mspm0l1306/src/bin/i2c_async.rs
new file mode 100644
index 000000000..c4a6938ff
--- /dev/null
+++ b/examples/mspm0l1306/src/bin/i2c_async.rs
@@ -0,0 +1,50 @@
1//! The example uses FIFO and interrupts, wrapped in async API.
2//!
3//! This example controls AD5171 digital potentiometer via I2C with the LP-MSPM0L1306 board.
4
5#![no_std]
6#![no_main]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_mspm0::bind_interrupts;
11use embassy_mspm0::i2c::{Config, I2c, InterruptHandler};
12use embassy_mspm0::peripherals::I2C0;
13use embassy_time::Timer;
14use {defmt_rtt as _, panic_halt as _};
15
16const ADDRESS: u8 = 0x6a;
17
18bind_interrupts!(struct Irqs {
19 I2C0 => InterruptHandler<I2C0>;
20});
21
22#[embassy_executor::main]
23async fn main(_spawner: Spawner) -> ! {
24 let p = embassy_mspm0::init(Default::default());
25
26 let instance = p.I2C0;
27 let scl = p.PA1;
28 let sda = p.PA0;
29
30 let mut i2c = unwrap!(I2c::new_async(instance, scl, sda, Irqs, Config::default()));
31
32 let mut pot_value: u8 = 0;
33
34 loop {
35 let to_write = [0u8, pot_value];
36
37 match i2c.async_write(ADDRESS, &to_write).await {
38 Ok(()) => info!("New potentioemter value: {}", pot_value),
39 Err(e) => error!("I2c Error: {:?}", e),
40 }
41
42 pot_value += 1;
43 // if reached 64th position (max)
44 // start over from lowest value
45 if pot_value == 64 {
46 pot_value = 0;
47 }
48 Timer::after_millis(500).await;
49 }
50}