diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-11-17 23:47:46 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-11-17 23:47:46 +0000 |
| commit | 5bc75578260f4c644cc060e6458a05d7fc0ffb41 (patch) | |
| tree | b870b676717d597b251b0888f176d5a5cf942e15 /embassy-stm32 | |
| parent | 006260feddf4d362a99260a38d86dffddab39d2e (diff) | |
| parent | 0f2208c0af8b89d91368c04ead9f84df664951e6 (diff) | |
Merge pull request #2173 from andresv/expose-i2c-async-api-without-time
STM32 I2C: expose async API without needing "time" feature.
Diffstat (limited to 'embassy-stm32')
| -rw-r--r-- | embassy-stm32/src/i2c/v2.rs | 160 |
1 files changed, 90 insertions, 70 deletions
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs index fc6dcd6ed..062a6225f 100644 --- a/embassy-stm32/src/i2c/v2.rs +++ b/embassy-stm32/src/i2c/v2.rs | |||
| @@ -1,21 +1,16 @@ | |||
| 1 | use core::cmp; | 1 | use core::cmp; |
| 2 | #[cfg(feature = "time")] | ||
| 3 | use core::future::poll_fn; | 2 | use core::future::poll_fn; |
| 4 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 5 | #[cfg(feature = "time")] | ||
| 6 | use core::task::Poll; | 4 | use core::task::Poll; |
| 7 | 5 | ||
| 8 | use embassy_embedded_hal::SetConfig; | 6 | use embassy_embedded_hal::SetConfig; |
| 9 | #[cfg(feature = "time")] | ||
| 10 | use embassy_hal_internal::drop::OnDrop; | 7 | use embassy_hal_internal::drop::OnDrop; |
| 11 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 8 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 12 | use embassy_sync::waitqueue::AtomicWaker; | 9 | use embassy_sync::waitqueue::AtomicWaker; |
| 13 | #[cfg(feature = "time")] | 10 | #[cfg(feature = "time")] |
| 14 | use embassy_time::{Duration, Instant}; | 11 | use embassy_time::{Duration, Instant}; |
| 15 | 12 | ||
| 16 | use crate::dma::NoDma; | 13 | use crate::dma::{NoDma, Transfer}; |
| 17 | #[cfg(feature = "time")] | ||
| 18 | use crate::dma::Transfer; | ||
| 19 | use crate::gpio::sealed::AFType; | 14 | use crate::gpio::sealed::AFType; |
| 20 | use crate::gpio::Pull; | 15 | use crate::gpio::Pull; |
| 21 | use crate::i2c::{Error, Instance, SclPin, SdaPin}; | 16 | use crate::i2c::{Error, Instance, SclPin, SdaPin}; |
| @@ -24,6 +19,23 @@ use crate::pac::i2c; | |||
| 24 | use crate::time::Hertz; | 19 | use crate::time::Hertz; |
| 25 | use crate::{interrupt, Peripheral}; | 20 | use crate::{interrupt, Peripheral}; |
| 26 | 21 | ||
| 22 | #[cfg(feature = "time")] | ||
| 23 | fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> { | ||
| 24 | let deadline = Instant::now() + timeout; | ||
| 25 | move || { | ||
| 26 | if Instant::now() > deadline { | ||
| 27 | Err(Error::Timeout) | ||
| 28 | } else { | ||
| 29 | Ok(()) | ||
| 30 | } | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | #[cfg(not(feature = "time"))] | ||
| 35 | pub fn no_timeout_fn() -> impl Fn() -> Result<(), Error> { | ||
| 36 | move || Ok(()) | ||
| 37 | } | ||
| 38 | |||
| 27 | /// Interrupt handler. | 39 | /// Interrupt handler. |
| 28 | pub struct InterruptHandler<T: Instance> { | 40 | pub struct InterruptHandler<T: Instance> { |
| 29 | _phantom: PhantomData<T>, | 41 | _phantom: PhantomData<T>, |
| @@ -260,21 +272,12 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 260 | } | 272 | } |
| 261 | 273 | ||
| 262 | fn flush_txdr(&self) { | 274 | fn flush_txdr(&self) { |
| 263 | //if $i2c.isr.read().txis().bit_is_set() { | ||
| 264 | //$i2c.txdr.write(|w| w.txdata().bits(0)); | ||
| 265 | //} | ||
| 266 | |||
| 267 | if T::regs().isr().read().txis() { | 275 | if T::regs().isr().read().txis() { |
| 268 | T::regs().txdr().write(|w| w.set_txdata(0)); | 276 | T::regs().txdr().write(|w| w.set_txdata(0)); |
| 269 | } | 277 | } |
| 270 | if !T::regs().isr().read().txe() { | 278 | if !T::regs().isr().read().txe() { |
| 271 | T::regs().isr().modify(|w| w.set_txe(true)) | 279 | T::regs().isr().modify(|w| w.set_txe(true)) |
| 272 | } | 280 | } |
| 273 | |||
| 274 | // If TXDR is not flagged as empty, write 1 to flush it | ||
| 275 | //if $i2c.isr.read().txe().is_not_empty() { | ||
| 276 | //$i2c.isr.write(|w| w.txe().set_bit()); | ||
| 277 | //} | ||
| 278 | } | 281 | } |
| 279 | 282 | ||
| 280 | fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { | 283 | fn wait_txe(&self, check_timeout: impl Fn() -> Result<(), Error>) -> Result<(), Error> { |
| @@ -437,7 +440,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 437 | result | 440 | result |
| 438 | } | 441 | } |
| 439 | 442 | ||
| 440 | #[cfg(feature = "time")] | ||
| 441 | async fn write_dma_internal( | 443 | async fn write_dma_internal( |
| 442 | &mut self, | 444 | &mut self, |
| 443 | address: u8, | 445 | address: u8, |
| @@ -528,7 +530,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 528 | Ok(()) | 530 | Ok(()) |
| 529 | } | 531 | } |
| 530 | 532 | ||
| 531 | #[cfg(feature = "time")] | ||
| 532 | async fn read_dma_internal( | 533 | async fn read_dma_internal( |
| 533 | &mut self, | 534 | &mut self, |
| 534 | address: u8, | 535 | address: u8, |
| @@ -610,42 +611,38 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 610 | 611 | ||
| 611 | // ========================= | 612 | // ========================= |
| 612 | // Async public API | 613 | // Async public API |
| 613 | |||
| 614 | #[cfg(feature = "time")] | 614 | #[cfg(feature = "time")] |
| 615 | pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> | 615 | pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> |
| 616 | where | 616 | where |
| 617 | TXDMA: crate::i2c::TxDma<T>, | 617 | TXDMA: crate::i2c::TxDma<T>, |
| 618 | { | 618 | { |
| 619 | self.write_timeout(address, write, self.timeout).await | ||
| 620 | } | ||
| 621 | |||
| 622 | #[cfg(feature = "time")] | ||
| 623 | pub async fn write_timeout(&mut self, address: u8, write: &[u8], timeout: Duration) -> Result<(), Error> | ||
| 624 | where | ||
| 625 | TXDMA: crate::i2c::TxDma<T>, | ||
| 626 | { | ||
| 627 | if write.is_empty() { | 619 | if write.is_empty() { |
| 628 | self.write_internal(address, write, true, timeout_fn(timeout)) | 620 | self.write_internal(address, write, true, timeout_fn(self.timeout)) |
| 629 | } else { | 621 | } else { |
| 630 | embassy_time::with_timeout( | 622 | embassy_time::with_timeout( |
| 631 | timeout, | 623 | self.timeout, |
| 632 | self.write_dma_internal(address, write, true, true, timeout_fn(timeout)), | 624 | self.write_dma_internal(address, write, true, true, timeout_fn(self.timeout)), |
| 633 | ) | 625 | ) |
| 634 | .await | 626 | .await |
| 635 | .unwrap_or(Err(Error::Timeout)) | 627 | .unwrap_or(Err(Error::Timeout)) |
| 636 | } | 628 | } |
| 637 | } | 629 | } |
| 638 | 630 | ||
| 639 | #[cfg(feature = "time")] | 631 | #[cfg(not(feature = "time"))] |
| 640 | pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> | 632 | pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> |
| 641 | where | 633 | where |
| 642 | TXDMA: crate::i2c::TxDma<T>, | 634 | TXDMA: crate::i2c::TxDma<T>, |
| 643 | { | 635 | { |
| 644 | self.write_vectored_timeout(address, write, self.timeout).await | 636 | if write.is_empty() { |
| 637 | self.write_internal(address, write, true, no_timeout_fn()) | ||
| 638 | } else { | ||
| 639 | self.write_dma_internal(address, write, true, true, no_timeout_fn()) | ||
| 640 | .await | ||
| 641 | } | ||
| 645 | } | 642 | } |
| 646 | 643 | ||
| 647 | #[cfg(feature = "time")] | 644 | #[cfg(feature = "time")] |
| 648 | pub async fn write_vectored_timeout(&mut self, address: u8, write: &[&[u8]], timeout: Duration) -> Result<(), Error> | 645 | pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> |
| 649 | where | 646 | where |
| 650 | TXDMA: crate::i2c::TxDma<T>, | 647 | TXDMA: crate::i2c::TxDma<T>, |
| 651 | { | 648 | { |
| @@ -661,8 +658,8 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 661 | let is_last = next.is_none(); | 658 | let is_last = next.is_none(); |
| 662 | 659 | ||
| 663 | embassy_time::with_timeout( | 660 | embassy_time::with_timeout( |
| 664 | timeout, | 661 | self.timeout, |
| 665 | self.write_dma_internal(address, c, first, is_last, timeout_fn(timeout)), | 662 | self.write_dma_internal(address, c, first, is_last, timeout_fn(self.timeout)), |
| 666 | ) | 663 | ) |
| 667 | .await | 664 | .await |
| 668 | .unwrap_or(Err(Error::Timeout))?; | 665 | .unwrap_or(Err(Error::Timeout))?; |
| @@ -672,66 +669,79 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 672 | Ok(()) | 669 | Ok(()) |
| 673 | } | 670 | } |
| 674 | 671 | ||
| 675 | #[cfg(feature = "time")] | 672 | #[cfg(not(feature = "time"))] |
| 676 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> | 673 | pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error> |
| 677 | where | 674 | where |
| 678 | RXDMA: crate::i2c::RxDma<T>, | 675 | TXDMA: crate::i2c::TxDma<T>, |
| 679 | { | 676 | { |
| 680 | self.read_timeout(address, buffer, self.timeout).await | 677 | if write.is_empty() { |
| 678 | return Err(Error::ZeroLengthTransfer); | ||
| 679 | } | ||
| 680 | let mut iter = write.iter(); | ||
| 681 | |||
| 682 | let mut first = true; | ||
| 683 | let mut current = iter.next(); | ||
| 684 | while let Some(c) = current { | ||
| 685 | let next = iter.next(); | ||
| 686 | let is_last = next.is_none(); | ||
| 687 | |||
| 688 | self.write_dma_internal(address, c, first, is_last, no_timeout_fn()) | ||
| 689 | .await?; | ||
| 690 | first = false; | ||
| 691 | current = next; | ||
| 692 | } | ||
| 693 | Ok(()) | ||
| 681 | } | 694 | } |
| 682 | 695 | ||
| 683 | #[cfg(feature = "time")] | 696 | #[cfg(feature = "time")] |
| 684 | pub async fn read_timeout(&mut self, address: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error> | 697 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> |
| 685 | where | 698 | where |
| 686 | RXDMA: crate::i2c::RxDma<T>, | 699 | RXDMA: crate::i2c::RxDma<T>, |
| 687 | { | 700 | { |
| 688 | if buffer.is_empty() { | 701 | if buffer.is_empty() { |
| 689 | self.read_internal(address, buffer, false, timeout_fn(timeout)) | 702 | self.read_internal(address, buffer, false, timeout_fn(self.timeout)) |
| 690 | } else { | 703 | } else { |
| 691 | embassy_time::with_timeout( | 704 | embassy_time::with_timeout( |
| 692 | timeout, | 705 | self.timeout, |
| 693 | self.read_dma_internal(address, buffer, false, timeout_fn(timeout)), | 706 | self.read_dma_internal(address, buffer, false, timeout_fn(self.timeout)), |
| 694 | ) | 707 | ) |
| 695 | .await | 708 | .await |
| 696 | .unwrap_or(Err(Error::Timeout)) | 709 | .unwrap_or(Err(Error::Timeout)) |
| 697 | } | 710 | } |
| 698 | } | 711 | } |
| 699 | 712 | ||
| 700 | #[cfg(feature = "time")] | 713 | #[cfg(not(feature = "time"))] |
| 701 | pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> | 714 | pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error> |
| 702 | where | 715 | where |
| 703 | TXDMA: super::TxDma<T>, | 716 | RXDMA: crate::i2c::RxDma<T>, |
| 704 | RXDMA: super::RxDma<T>, | ||
| 705 | { | 717 | { |
| 706 | self.write_read_timeout(address, write, read, self.timeout).await | 718 | if buffer.is_empty() { |
| 719 | self.read_internal(address, buffer, false, no_timeout_fn()) | ||
| 720 | } else { | ||
| 721 | self.read_dma_internal(address, buffer, false, no_timeout_fn()).await | ||
| 722 | } | ||
| 707 | } | 723 | } |
| 708 | 724 | ||
| 709 | #[cfg(feature = "time")] | 725 | #[cfg(feature = "time")] |
| 710 | pub async fn write_read_timeout( | 726 | pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> |
| 711 | &mut self, | ||
| 712 | address: u8, | ||
| 713 | write: &[u8], | ||
| 714 | read: &mut [u8], | ||
| 715 | timeout: Duration, | ||
| 716 | ) -> Result<(), Error> | ||
| 717 | where | 727 | where |
| 718 | TXDMA: super::TxDma<T>, | 728 | TXDMA: super::TxDma<T>, |
| 719 | RXDMA: super::RxDma<T>, | 729 | RXDMA: super::RxDma<T>, |
| 720 | { | 730 | { |
| 721 | let start_instant = Instant::now(); | 731 | let start_instant = Instant::now(); |
| 722 | let check_timeout = timeout_fn(timeout); | 732 | let check_timeout = timeout_fn(self.timeout); |
| 723 | if write.is_empty() { | 733 | if write.is_empty() { |
| 724 | self.write_internal(address, write, false, &check_timeout)?; | 734 | self.write_internal(address, write, false, &check_timeout)?; |
| 725 | } else { | 735 | } else { |
| 726 | embassy_time::with_timeout( | 736 | embassy_time::with_timeout( |
| 727 | timeout, | 737 | self.timeout, |
| 728 | self.write_dma_internal(address, write, true, true, &check_timeout), | 738 | self.write_dma_internal(address, write, true, true, &check_timeout), |
| 729 | ) | 739 | ) |
| 730 | .await | 740 | .await |
| 731 | .unwrap_or(Err(Error::Timeout))?; | 741 | .unwrap_or(Err(Error::Timeout))?; |
| 732 | } | 742 | } |
| 733 | 743 | ||
| 734 | let time_left_until_timeout = timeout - Instant::now().duration_since(start_instant); | 744 | let time_left_until_timeout = self.timeout - Instant::now().duration_since(start_instant); |
| 735 | 745 | ||
| 736 | if read.is_empty() { | 746 | if read.is_empty() { |
| 737 | self.read_internal(address, read, true, &check_timeout)?; | 747 | self.read_internal(address, read, true, &check_timeout)?; |
| @@ -747,6 +757,28 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> { | |||
| 747 | Ok(()) | 757 | Ok(()) |
| 748 | } | 758 | } |
| 749 | 759 | ||
| 760 | #[cfg(not(feature = "time"))] | ||
| 761 | pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> | ||
| 762 | where | ||
| 763 | TXDMA: super::TxDma<T>, | ||
| 764 | RXDMA: super::RxDma<T>, | ||
| 765 | { | ||
| 766 | let no_timeout = no_timeout_fn(); | ||
| 767 | if write.is_empty() { | ||
| 768 | self.write_internal(address, write, false, &no_timeout)?; | ||
| 769 | } else { | ||
| 770 | self.write_dma_internal(address, write, true, true, &no_timeout).await?; | ||
| 771 | } | ||
| 772 | |||
| 773 | if read.is_empty() { | ||
| 774 | self.read_internal(address, read, true, &no_timeout)?; | ||
| 775 | } else { | ||
| 776 | self.read_dma_internal(address, read, true, &no_timeout).await?; | ||
| 777 | } | ||
| 778 | |||
| 779 | Ok(()) | ||
| 780 | } | ||
| 781 | |||
| 750 | // ========================= | 782 | // ========================= |
| 751 | // Blocking public API | 783 | // Blocking public API |
| 752 | 784 | ||
| @@ -1201,15 +1233,3 @@ impl<'d, T: Instance> SetConfig for I2c<'d, T> { | |||
| 1201 | Ok(()) | 1233 | Ok(()) |
| 1202 | } | 1234 | } |
| 1203 | } | 1235 | } |
| 1204 | |||
| 1205 | #[cfg(feature = "time")] | ||
| 1206 | fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> { | ||
| 1207 | let deadline = Instant::now() + timeout; | ||
| 1208 | move || { | ||
| 1209 | if Instant::now() > deadline { | ||
| 1210 | Err(Error::Timeout) | ||
| 1211 | } else { | ||
| 1212 | Ok(()) | ||
| 1213 | } | ||
| 1214 | } | ||
| 1215 | } | ||
