diff options
Diffstat (limited to 'src/i2c/controller.rs')
| -rw-r--r-- | src/i2c/controller.rs | 253 |
1 files changed, 244 insertions, 9 deletions
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 | ||
| 3 | use core::future::Future; | ||
| 3 | use core::marker::PhantomData; | 4 | use core::marker::PhantomData; |
| 4 | 5 | ||
| 5 | use embassy_hal_internal::Peri; | 6 | use embassy_hal_internal::Peri; |
| 6 | use mcxa_pac::lpi2c0::mtdr::Cmd; | 7 | use mcxa_pac::lpi2c0::mtdr::Cmd; |
| 7 | 8 | ||
| 8 | use super::{Blocking, Error, Instance, Mode, Result, SclPin, SdaPin}; | 9 | use super::{Async, Blocking, Error, Instance, InterruptHandler, Mode, Result, SclPin, SdaPin}; |
| 9 | use crate::clocks::periph_helpers::{Div4, Lpi2cClockSel, Lpi2cConfig}; | 10 | use crate::clocks::periph_helpers::{Div4, Lpi2cClockSel, Lpi2cConfig}; |
| 10 | use crate::clocks::{enable_and_reset, PoweredClock}; | 11 | use crate::clocks::{enable_and_reset, PoweredClock}; |
| 12 | use crate::interrupt::typelevel::Interrupt; | ||
| 11 | use crate::AnyPin; | 13 | use 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 | ||
| 362 | impl<'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 | |||
| 354 | impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Read for I2c<'d, T, M> { | 557 | impl<'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 | ||
| 651 | impl<'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 | |||
| 448 | impl<'d, T: Instance, M: Mode> embassy_embedded_hal::SetConfig for I2c<'d, T, M> { | 683 | impl<'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; |
