diff options
| author | Dario Nieuwenhuis <[email protected]> | 2022-05-03 00:43:59 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2022-05-03 00:52:48 +0200 |
| commit | 0be6df168bf8d9121c37118dde5f86e144ec9b37 (patch) | |
| tree | a981f496f79526761fc6ade1c1afa51f353a9091 | |
| parent | 1a3f7879321a13aa9bd42a7058eb909340fa941d (diff) | |
nrf/twim: add blocking methods variants with timeout.
| -rw-r--r-- | embassy-nrf/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-nrf/src/twim.rs | 124 |
2 files changed, 127 insertions, 1 deletions
diff --git a/embassy-nrf/Cargo.toml b/embassy-nrf/Cargo.toml index 979e66a94..b7c09286f 100644 --- a/embassy-nrf/Cargo.toml +++ b/embassy-nrf/Cargo.toml | |||
| @@ -17,6 +17,8 @@ flavors = [ | |||
| 17 | 17 | ||
| 18 | [features] | 18 | [features] |
| 19 | 19 | ||
| 20 | time = ["embassy/time"] | ||
| 21 | |||
| 20 | defmt = ["dep:defmt", "embassy/defmt", "embassy-usb?/defmt"] | 22 | defmt = ["dep:defmt", "embassy/defmt", "embassy-usb?/defmt"] |
| 21 | 23 | ||
| 22 | # Enable nightly-only features | 24 | # Enable nightly-only features |
| @@ -56,7 +58,7 @@ _nrf5340-net = ["_nrf5340", "nrf5340-net-pac"] | |||
| 56 | _nrf5340 = ["_gpio-p1", "_dppi"] | 58 | _nrf5340 = ["_gpio-p1", "_dppi"] |
| 57 | _nrf9160 = ["nrf9160-pac", "_dppi"] | 59 | _nrf9160 = ["nrf9160-pac", "_dppi"] |
| 58 | 60 | ||
| 59 | _time-driver = ["embassy/time-tick-32768hz"] | 61 | _time-driver = ["embassy/time-tick-32768hz", "time"] |
| 60 | 62 | ||
| 61 | _ppi = [] | 63 | _ppi = [] |
| 62 | _dppi = [] | 64 | _dppi = [] |
diff --git a/embassy-nrf/src/twim.rs b/embassy-nrf/src/twim.rs index 298441bea..bb943c2c7 100644 --- a/embassy-nrf/src/twim.rs +++ b/embassy-nrf/src/twim.rs | |||
| @@ -11,6 +11,8 @@ use core::marker::PhantomData; | |||
| 11 | use core::sync::atomic::{compiler_fence, Ordering::SeqCst}; | 11 | use core::sync::atomic::{compiler_fence, Ordering::SeqCst}; |
| 12 | use core::task::Poll; | 12 | use core::task::Poll; |
| 13 | use embassy::interrupt::{Interrupt, InterruptExt}; | 13 | use embassy::interrupt::{Interrupt, InterruptExt}; |
| 14 | #[cfg(feature = "time")] | ||
| 15 | use embassy::time::{Duration, Instant}; | ||
| 14 | use embassy::util::Unborrow; | 16 | use embassy::util::Unborrow; |
| 15 | use embassy::waitqueue::AtomicWaker; | 17 | use embassy::waitqueue::AtomicWaker; |
| 16 | use embassy_hal_common::unborrow; | 18 | use embassy_hal_common::unborrow; |
| @@ -66,6 +68,7 @@ pub enum Error { | |||
| 66 | AddressNack, | 68 | AddressNack, |
| 67 | DataNack, | 69 | DataNack, |
| 68 | Overrun, | 70 | Overrun, |
| 71 | Timeout, | ||
| 69 | } | 72 | } |
| 70 | 73 | ||
| 71 | /// Interface to a TWIM instance using EasyDMA to offload the transmission and reception workload. | 74 | /// Interface to a TWIM instance using EasyDMA to offload the transmission and reception workload. |
| @@ -279,6 +282,29 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 279 | } | 282 | } |
| 280 | 283 | ||
| 281 | /// Wait for stop or error | 284 | /// Wait for stop or error |
| 285 | #[cfg(feature = "time")] | ||
| 286 | fn blocking_wait_timeout(&mut self, timeout: Duration) -> Result<(), Error> { | ||
| 287 | let r = T::regs(); | ||
| 288 | let deadline = Instant::now() + timeout; | ||
| 289 | loop { | ||
| 290 | if r.events_stopped.read().bits() != 0 { | ||
| 291 | r.events_stopped.reset(); | ||
| 292 | break; | ||
| 293 | } | ||
| 294 | if r.events_error.read().bits() != 0 { | ||
| 295 | r.events_error.reset(); | ||
| 296 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 297 | } | ||
| 298 | if Instant::now() > deadline { | ||
| 299 | r.tasks_stop.write(|w| unsafe { w.bits(1) }); | ||
| 300 | return Err(Error::Timeout); | ||
| 301 | } | ||
| 302 | } | ||
| 303 | |||
| 304 | Ok(()) | ||
| 305 | } | ||
| 306 | |||
| 307 | /// Wait for stop or error | ||
| 282 | fn async_wait(&mut self) -> impl Future<Output = ()> { | 308 | fn async_wait(&mut self) -> impl Future<Output = ()> { |
| 283 | poll_fn(move |cx| { | 309 | poll_fn(move |cx| { |
| 284 | let r = T::regs(); | 310 | let r = T::regs(); |
| @@ -505,6 +531,103 @@ impl<'d, T: Instance> Twim<'d, T> { | |||
| 505 | Ok(()) | 531 | Ok(()) |
| 506 | } | 532 | } |
| 507 | 533 | ||
| 534 | // =========================================== | ||
| 535 | |||
| 536 | /// Write to an I2C slave with timeout. | ||
| 537 | /// | ||
| 538 | /// See [`blocking_write`]. | ||
| 539 | #[cfg(feature = "time")] | ||
| 540 | pub fn blocking_write_timeout( | ||
| 541 | &mut self, | ||
| 542 | address: u8, | ||
| 543 | buffer: &[u8], | ||
| 544 | timeout: Duration, | ||
| 545 | ) -> Result<(), Error> { | ||
| 546 | self.setup_write(address, buffer, false)?; | ||
| 547 | self.blocking_wait_timeout(timeout)?; | ||
| 548 | compiler_fence(SeqCst); | ||
| 549 | self.check_errorsrc()?; | ||
| 550 | self.check_tx(buffer.len())?; | ||
| 551 | Ok(()) | ||
| 552 | } | ||
| 553 | |||
| 554 | /// Same as [`blocking_write`](Twim::blocking_write) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. | ||
| 555 | #[cfg(feature = "time")] | ||
| 556 | pub fn blocking_write_from_ram_timeout( | ||
| 557 | &mut self, | ||
| 558 | address: u8, | ||
| 559 | buffer: &[u8], | ||
| 560 | timeout: Duration, | ||
| 561 | ) -> Result<(), Error> { | ||
| 562 | self.setup_write_from_ram(address, buffer, false)?; | ||
| 563 | self.blocking_wait_timeout(timeout)?; | ||
| 564 | compiler_fence(SeqCst); | ||
| 565 | self.check_errorsrc()?; | ||
| 566 | self.check_tx(buffer.len())?; | ||
| 567 | Ok(()) | ||
| 568 | } | ||
| 569 | |||
| 570 | /// Read from an I2C slave. | ||
| 571 | /// | ||
| 572 | /// The buffer must have a length of at most 255 bytes on the nRF52832 | ||
| 573 | /// and at most 65535 bytes on the nRF52840. | ||
| 574 | #[cfg(feature = "time")] | ||
| 575 | pub fn blocking_read_timeout( | ||
| 576 | &mut self, | ||
| 577 | address: u8, | ||
| 578 | buffer: &mut [u8], | ||
| 579 | timeout: Duration, | ||
| 580 | ) -> Result<(), Error> { | ||
| 581 | self.setup_read(address, buffer, false)?; | ||
| 582 | self.blocking_wait_timeout(timeout)?; | ||
| 583 | compiler_fence(SeqCst); | ||
| 584 | self.check_errorsrc()?; | ||
| 585 | self.check_rx(buffer.len())?; | ||
| 586 | Ok(()) | ||
| 587 | } | ||
| 588 | |||
| 589 | /// Write data to an I2C slave, then read data from the slave without | ||
| 590 | /// triggering a stop condition between the two. | ||
| 591 | /// | ||
| 592 | /// The buffers must have a length of at most 255 bytes on the nRF52832 | ||
| 593 | /// and at most 65535 bytes on the nRF52840. | ||
| 594 | #[cfg(feature = "time")] | ||
| 595 | pub fn blocking_write_read_timeout( | ||
| 596 | &mut self, | ||
| 597 | address: u8, | ||
| 598 | wr_buffer: &[u8], | ||
| 599 | rd_buffer: &mut [u8], | ||
| 600 | timeout: Duration, | ||
| 601 | ) -> Result<(), Error> { | ||
| 602 | self.setup_write_read(address, wr_buffer, rd_buffer, false)?; | ||
| 603 | self.blocking_wait_timeout(timeout)?; | ||
| 604 | compiler_fence(SeqCst); | ||
| 605 | self.check_errorsrc()?; | ||
| 606 | self.check_tx(wr_buffer.len())?; | ||
| 607 | self.check_rx(rd_buffer.len())?; | ||
| 608 | Ok(()) | ||
| 609 | } | ||
| 610 | |||
| 611 | /// Same as [`blocking_write_read`](Twim::blocking_write_read) but will fail instead of copying data into RAM. Consult the module level documentation to learn more. | ||
| 612 | #[cfg(feature = "time")] | ||
| 613 | pub fn blocking_write_read_from_ram_timeout( | ||
| 614 | &mut self, | ||
| 615 | address: u8, | ||
| 616 | wr_buffer: &[u8], | ||
| 617 | rd_buffer: &mut [u8], | ||
| 618 | timeout: Duration, | ||
| 619 | ) -> Result<(), Error> { | ||
| 620 | self.setup_write_read_from_ram(address, wr_buffer, rd_buffer, false)?; | ||
| 621 | self.blocking_wait_timeout(timeout)?; | ||
| 622 | compiler_fence(SeqCst); | ||
| 623 | self.check_errorsrc()?; | ||
| 624 | self.check_tx(wr_buffer.len())?; | ||
| 625 | self.check_rx(rd_buffer.len())?; | ||
| 626 | Ok(()) | ||
| 627 | } | ||
| 628 | |||
| 629 | // =========================================== | ||
| 630 | |||
| 508 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { | 631 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> { |
| 509 | self.setup_read(address, buffer, true)?; | 632 | self.setup_read(address, buffer, true)?; |
| 510 | self.async_wait().await; | 633 | self.async_wait().await; |
| @@ -689,6 +812,7 @@ mod eh1 { | |||
| 689 | embedded_hal_1::i2c::NoAcknowledgeSource::Data, | 812 | embedded_hal_1::i2c::NoAcknowledgeSource::Data, |
| 690 | ), | 813 | ), |
| 691 | Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun, | 814 | Self::Overrun => embedded_hal_1::i2c::ErrorKind::Overrun, |
| 815 | Self::Timeout => embedded_hal_1::i2c::ErrorKind::Other, | ||
| 692 | } | 816 | } |
| 693 | } | 817 | } |
| 694 | } | 818 | } |
