aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/src/bin/i2c-async.rs39
-rw-r--r--src/i2c/controller.rs253
-rw-r--r--src/i2c/mod.rs43
3 files changed, 316 insertions, 19 deletions
diff --git a/examples/src/bin/i2c-async.rs b/examples/src/bin/i2c-async.rs
new file mode 100644
index 000000000..47b5f3cbe
--- /dev/null
+++ b/examples/src/bin/i2c-async.rs
@@ -0,0 +1,39 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_time::Timer;
6use hal::bind_interrupts;
7use hal::clocks::config::Div8;
8use hal::config::Config;
9use hal::i2c::controller::{self, I2c, Speed};
10use hal::i2c::InterruptHandler;
11use hal::peripherals::LPI2C3;
12use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
13
14bind_interrupts!(
15 struct Irqs {
16 LPI2C3 => InterruptHandler<LPI2C3>;
17 }
18);
19
20#[embassy_executor::main]
21async fn main(_spawner: Spawner) {
22 let mut config = Config::default();
23 config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1);
24
25 let p = hal::init(config);
26
27 defmt::info!("I2C example");
28
29 let mut config = controller::Config::default();
30 config.speed = Speed::Standard;
31 let mut i2c = I2c::new_async(p.LPI2C3, p.P3_27, p.P3_28, Irqs, config).unwrap();
32 let mut buf = [0u8; 2];
33
34 loop {
35 i2c.async_write_read(0x48, &[0x00], &mut buf).await.unwrap();
36 defmt::info!("Buffer: {:02x}", buf);
37 Timer::after_secs(1).await;
38 }
39}
diff --git a/src/i2c/controller.rs b/src/i2c/controller.rs
index 41bbc821d..818024bc9 100644
--- a/src/i2c/controller.rs
+++ b/src/i2c/controller.rs
@@ -1,13 +1,15 @@
1//! LPI2C controller driver 1//! LPI2C controller driver
2 2
3use core::future::Future;
3use core::marker::PhantomData; 4use core::marker::PhantomData;
4 5
5use embassy_hal_internal::Peri; 6use embassy_hal_internal::Peri;
6use mcxa_pac::lpi2c0::mtdr::Cmd; 7use mcxa_pac::lpi2c0::mtdr::Cmd;
7 8
8use super::{Blocking, Error, Instance, Mode, Result, SclPin, SdaPin}; 9use super::{Async, Blocking, Error, Instance, InterruptHandler, Mode, Result, SclPin, SdaPin};
9use crate::clocks::periph_helpers::{Div4, Lpi2cClockSel, Lpi2cConfig}; 10use crate::clocks::periph_helpers::{Div4, Lpi2cClockSel, Lpi2cConfig};
10use crate::clocks::{enable_and_reset, PoweredClock}; 11use crate::clocks::{enable_and_reset, PoweredClock};
12use crate::interrupt::typelevel::Interrupt;
11use crate::AnyPin; 13use crate::AnyPin;
12 14
13/// Bus speed (nominal SCL, no clock stretching) 15/// Bus speed (nominal SCL, no clock stretching)
@@ -199,9 +201,6 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
199 } 201 }
200 202
201 fn status(&mut self) -> Result<()> { 203 fn status(&mut self) -> Result<()> {
202 // Wait for TxFIFO to be drained
203 while !self.is_tx_fifo_empty() {}
204
205 let msr = T::regs().msr().read(); 204 let msr = T::regs().msr().read();
206 T::regs().msr().write(|w| { 205 T::regs().msr().write(|w| {
207 w.epf() 206 w.epf()
@@ -228,6 +227,8 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
228 Err(Error::AddressNack) 227 Err(Error::AddressNack)
229 } else if msr.alf().bit_is_set() { 228 } else if msr.alf().bit_is_set() {
230 Err(Error::ArbitrationLoss) 229 Err(Error::ArbitrationLoss)
230 } else if msr.fef().bit_is_set() {
231 Err(Error::FifoError)
231 } else { 232 } else {
232 Ok(()) 233 Ok(())
233 } 234 }
@@ -259,6 +260,9 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
259 let addr_rw = address << 1 | if read { 1 } else { 0 }; 260 let addr_rw = address << 1 | if read { 1 } else { 0 };
260 self.send_cmd(if self.is_hs { Cmd::StartHs } else { Cmd::Start }, addr_rw); 261 self.send_cmd(if self.is_hs { Cmd::StartHs } else { Cmd::Start }, addr_rw);
261 262
263 // Wait for TxFIFO to be drained
264 while !self.is_tx_fifo_empty() {}
265
262 // Check controller status 266 // Check controller status
263 self.status() 267 self.status()
264 } 268 }
@@ -268,17 +272,21 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
268 while self.is_tx_fifo_full() {} 272 while self.is_tx_fifo_full() {}
269 273
270 self.send_cmd(Cmd::Stop, 0); 274 self.send_cmd(Cmd::Stop, 0);
275
276 // Wait for TxFIFO to be drained
277 while !self.is_tx_fifo_empty() {}
278
271 self.status() 279 self.status()
272 } 280 }
273 281
274 fn blocking_read_internal(&mut self, address: u8, read: &mut [u8], send_stop: SendStop) -> Result<()> { 282 fn blocking_read_internal(&mut self, address: u8, read: &mut [u8], send_stop: SendStop) -> Result<()> {
275 self.start(address, true)?;
276
277 if read.is_empty() { 283 if read.is_empty() {
278 return Err(Error::InvalidReadBufferLength); 284 return Err(Error::InvalidReadBufferLength);
279 } 285 }
280 286
281 for chunk in read.chunks_mut(256) { 287 for chunk in read.chunks_mut(256) {
288 self.start(address, true)?;
289
282 // Wait until we have space in the TxFIFO 290 // Wait until we have space in the TxFIFO
283 while self.is_tx_fifo_full() {} 291 while self.is_tx_fifo_full() {}
284 292
@@ -290,10 +298,10 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
290 298
291 *byte = T::regs().mrdr().read().data().bits(); 299 *byte = T::regs().mrdr().read().data().bits();
292 } 300 }
301 }
293 302
294 if send_stop == SendStop::Yes { 303 if send_stop == SendStop::Yes {
295 self.stop()?; 304 self.stop()?;
296 }
297 } 305 }
298 306
299 Ok(()) 307 Ok(())
@@ -351,6 +359,201 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
351 } 359 }
352} 360}
353 361
362impl<'d, T: Instance> I2c<'d, T, Async> {
363 /// Create a new async instance of the I2C Controller bus driver.
364 pub fn new_async(
365 peri: Peri<'d, T>,
366 scl: Peri<'d, impl SclPin<T>>,
367 sda: Peri<'d, impl SdaPin<T>>,
368 _irq: impl crate::interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
369 config: Config,
370 ) -> Result<Self> {
371 T::Interrupt::unpend();
372
373 // Safety: `_irq` ensures an Interrupt Handler exists.
374 unsafe { T::Interrupt::enable() };
375
376 Self::new_inner(peri, scl, sda, config)
377 }
378
379 fn enable_rx_ints(&mut self) {
380 T::regs().mier().write(|w| {
381 w.rdie()
382 .enabled()
383 .ndie()
384 .enabled()
385 .alie()
386 .enabled()
387 .feie()
388 .enabled()
389 .pltie()
390 .enabled()
391 });
392 }
393
394 fn enable_tx_ints(&mut self) {
395 T::regs().mier().write(|w| {
396 w.tdie()
397 .enabled()
398 .ndie()
399 .enabled()
400 .alie()
401 .enabled()
402 .feie()
403 .enabled()
404 .pltie()
405 .enabled()
406 });
407 }
408
409 async fn async_start(&mut self, address: u8, read: bool) -> Result<()> {
410 if address >= 0x80 {
411 return Err(Error::AddressOutOfRange(address));
412 }
413
414 // send the start command
415 let addr_rw = address << 1 | if read { 1 } else { 0 };
416 self.send_cmd(if self.is_hs { Cmd::StartHs } else { Cmd::Start }, addr_rw);
417
418 T::wait_cell()
419 .wait_for(|| {
420 // enable interrupts
421 self.enable_tx_ints();
422 // if the command FIFO is empty, we're done sending start
423 self.is_tx_fifo_empty()
424 })
425 .await
426 .map_err(|_| Error::Other)?;
427
428 self.status()
429 }
430
431 async fn async_stop(&mut self) -> Result<()> {
432 // send the stop command
433 self.send_cmd(Cmd::Stop, 0);
434
435 T::wait_cell()
436 .wait_for(|| {
437 // enable interrupts
438 self.enable_tx_ints();
439 // if the command FIFO is empty, we're done sending stop
440 self.is_tx_fifo_empty()
441 })
442 .await
443 .map_err(|_| Error::Other)?;
444
445 self.status()
446 }
447
448 async fn async_read_internal(&mut self, address: u8, read: &mut [u8], send_stop: SendStop) -> Result<()> {
449 if read.is_empty() {
450 return Err(Error::InvalidReadBufferLength);
451 }
452
453 for chunk in read.chunks_mut(256) {
454 self.async_start(address, true).await?;
455
456 // send receive command
457 self.send_cmd(Cmd::Receive, (chunk.len() - 1) as u8);
458
459 T::wait_cell()
460 .wait_for(|| {
461 // enable interrupts
462 self.enable_tx_ints();
463 // if the command FIFO is empty, we're done sending start
464 self.is_tx_fifo_empty()
465 })
466 .await
467 .map_err(|_| Error::Other)?;
468
469 for byte in chunk.iter_mut() {
470 T::wait_cell()
471 .wait_for(|| {
472 // enable interrupts
473 self.enable_rx_ints();
474 // it the rx FIFO is not empty, we need to read a byte
475 !self.is_rx_fifo_empty()
476 })
477 .await
478 .map_err(|_| Error::ReadFail)?;
479
480 *byte = T::regs().mrdr().read().data().bits();
481 }
482 }
483
484 if send_stop == SendStop::Yes {
485 self.async_stop().await?;
486 }
487
488 Ok(())
489 }
490
491 async fn async_write_internal(&mut self, address: u8, write: &[u8], send_stop: SendStop) -> Result<()> {
492 self.async_start(address, false).await?;
493
494 // Usually, embassy HALs error out with an empty write,
495 // however empty writes are useful for writing I2C scanning
496 // logic through write probing. That is, we send a start with
497 // R/w bit cleared, but instead of writing any data, just send
498 // the stop onto the bus. This has the effect of checking if
499 // the resulting address got an ACK but causing no
500 // side-effects to the device on the other end.
501 //
502 // Because of this, we are not going to error out in case of
503 // empty writes.
504 #[cfg(feature = "defmt")]
505 if write.is_empty() {
506 defmt::trace!("Empty write, write probing?");
507 }
508
509 for byte in write {
510 T::wait_cell()
511 .wait_for(|| {
512 // enable interrupts
513 self.enable_tx_ints();
514 // initiate trasmit
515 self.send_cmd(Cmd::Transmit, *byte);
516 // it the rx FIFO is not empty, we're done transmiting
517 self.is_tx_fifo_empty()
518 })
519 .await
520 .map_err(|_| Error::WriteFail)?;
521 }
522
523 if send_stop == SendStop::Yes {
524 self.async_stop().await?;
525 }
526
527 Ok(())
528 }
529
530 // Public API: Async
531
532 /// Read from address into buffer asynchronously.
533 pub fn async_read<'a>(
534 &mut self,
535 address: u8,
536 read: &'a mut [u8],
537 ) -> impl Future<Output = Result<()>> + use<'_, 'a, 'd, T> {
538 self.async_read_internal(address, read, SendStop::Yes)
539 }
540
541 /// Write to address from buffer asynchronously.
542 pub fn async_write<'a>(
543 &mut self,
544 address: u8,
545 write: &'a [u8],
546 ) -> impl Future<Output = Result<()>> + use<'_, 'a, 'd, T> {
547 self.async_write_internal(address, write, SendStop::Yes)
548 }
549
550 /// Write to address from bytes and read from address into buffer asynchronously.
551 pub async fn async_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<()> {
552 self.async_write_internal(address, write, SendStop::No).await?;
553 self.async_read_internal(address, read, SendStop::Yes).await
554 }
555}
556
354impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Read for I2c<'d, T, M> { 557impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Read for I2c<'d, T, M> {
355 type Error = Error; 558 type Error = Error;
356 559
@@ -445,6 +648,38 @@ impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::I2c for I2c<'d, T, M> {
445 } 648 }
446} 649}
447 650
651impl<'d, T: Instance> embedded_hal_async::i2c::I2c for I2c<'d, T, Async> {
652 async fn transaction(
653 &mut self,
654 address: u8,
655 operations: &mut [embedded_hal_async::i2c::Operation<'_>],
656 ) -> Result<()> {
657 if let Some((last, rest)) = operations.split_last_mut() {
658 for op in rest {
659 match op {
660 embedded_hal_async::i2c::Operation::Read(buf) => {
661 self.async_read_internal(address, buf, SendStop::No).await?
662 }
663 embedded_hal_async::i2c::Operation::Write(buf) => {
664 self.async_write_internal(address, buf, SendStop::No).await?
665 }
666 }
667 }
668
669 match last {
670 embedded_hal_async::i2c::Operation::Read(buf) => {
671 self.async_read_internal(address, buf, SendStop::Yes).await
672 }
673 embedded_hal_async::i2c::Operation::Write(buf) => {
674 self.async_write_internal(address, buf, SendStop::Yes).await
675 }
676 }
677 } else {
678 Ok(())
679 }
680 }
681}
682
448impl<'d, T: Instance, M: Mode> embassy_embedded_hal::SetConfig for I2c<'d, T, M> { 683impl<'d, T: Instance, M: Mode> embassy_embedded_hal::SetConfig for I2c<'d, T, M> {
449 type Config = Config; 684 type Config = Config;
450 type ConfigError = Error; 685 type ConfigError = Error;
diff --git a/src/i2c/mod.rs b/src/i2c/mod.rs
index a1f842029..9a014224a 100644
--- a/src/i2c/mod.rs
+++ b/src/i2c/mod.rs
@@ -3,7 +3,7 @@
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4 4
5use embassy_hal_internal::PeripheralType; 5use embassy_hal_internal::PeripheralType;
6use embassy_sync::waitqueue::AtomicWaker; 6use maitake_sync::WaitCell;
7use paste::paste; 7use paste::paste;
8 8
9use crate::clocks::periph_helpers::Lpi2cConfig; 9use crate::clocks::periph_helpers::Lpi2cConfig;
@@ -22,6 +22,8 @@ pub mod controller;
22pub enum Error { 22pub enum Error {
23 /// Clock configuration error. 23 /// Clock configuration error.
24 ClockSetup(ClockError), 24 ClockSetup(ClockError),
25 /// FIFO Error
26 FifoError,
25 /// Reading for I2C failed. 27 /// Reading for I2C failed.
26 ReadFail, 28 ReadFail,
27 /// Writing to I2C failed. 29 /// Writing to I2C failed.
@@ -47,11 +49,32 @@ pub struct InterruptHandler<T: Instance> {
47 49
48impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> { 50impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
49 unsafe fn on_interrupt() { 51 unsafe fn on_interrupt() {
50 let waker = T::waker(); 52 if T::regs().mier().read().bits() != 0 {
51 53 T::regs().mier().write(|w| {
52 waker.wake(); 54 w.tdie()
53 55 .disabled()
54 todo!() 56 .rdie()
57 .disabled()
58 .epie()
59 .disabled()
60 .sdie()
61 .disabled()
62 .ndie()
63 .disabled()
64 .alie()
65 .disabled()
66 .feie()
67 .disabled()
68 .pltie()
69 .disabled()
70 .dmie()
71 .disabled()
72 .stie()
73 .disabled()
74 });
75
76 T::wait_cell().wake();
77 }
55 } 78 }
56} 79}
57 80
@@ -64,7 +87,7 @@ impl<T: GpioPin> sealed::Sealed for T {}
64 87
65trait SealedInstance { 88trait SealedInstance {
66 fn regs() -> &'static pac::lpi2c0::RegisterBlock; 89 fn regs() -> &'static pac::lpi2c0::RegisterBlock;
67 fn waker() -> &'static AtomicWaker; 90 fn wait_cell() -> &'static WaitCell;
68} 91}
69 92
70/// I2C Instance 93/// I2C Instance
@@ -85,9 +108,9 @@ macro_rules! impl_instance {
85 unsafe { &*pac::[<Lpi2c $n>]::ptr() } 108 unsafe { &*pac::[<Lpi2c $n>]::ptr() }
86 } 109 }
87 110
88 fn waker() -> &'static AtomicWaker { 111 fn wait_cell() -> &'static WaitCell {
89 static WAKER: AtomicWaker = AtomicWaker::new(); 112 static WAIT_CELL: WaitCell = WaitCell::new();
90 &WAKER 113 &WAIT_CELL
91 } 114 }
92 } 115 }
93 116