aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32
diff options
context:
space:
mode:
authorAndres Vahter <[email protected]>2023-11-10 15:49:31 +0200
committerAndres Vahter <[email protected]>2023-11-10 16:04:25 +0200
commit3b33cc46915f0b400a2a9dd87cfe51eca9f7e434 (patch)
treea4dcddb350847c19b1d607cc4ed3b7e449d58d6c /embassy-stm32
parentb3367be9c8f0eb54d500dc2e6f652ade05859088 (diff)
i2c: expose async api without needing time
This exposes I2C async API without needing "time" feature. With "time" feature additional async API with timeouts is exposed.
Diffstat (limited to 'embassy-stm32')
-rw-r--r--embassy-stm32/src/i2c/v2.rs207
1 files changed, 175 insertions, 32 deletions
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index fc6dcd6ed..7049affe8 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -1,21 +1,14 @@
1use core::cmp; 1use core::cmp;
2#[cfg(feature = "time")] 2use core::future::{poll_fn, Future};
3use core::future::poll_fn;
4use core::marker::PhantomData; 3use core::marker::PhantomData;
5#[cfg(feature = "time")]
6use core::task::Poll; 4use core::task::Poll;
7 5
8use embassy_embedded_hal::SetConfig; 6use embassy_embedded_hal::SetConfig;
9#[cfg(feature = "time")]
10use embassy_hal_internal::drop::OnDrop; 7use embassy_hal_internal::drop::OnDrop;
11use embassy_hal_internal::{into_ref, PeripheralRef}; 8use embassy_hal_internal::{into_ref, PeripheralRef};
12use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
13#[cfg(feature = "time")]
14use embassy_time::{Duration, Instant};
15 10
16use crate::dma::NoDma; 11use crate::dma::{NoDma, Transfer};
17#[cfg(feature = "time")]
18use crate::dma::Transfer;
19use crate::gpio::sealed::AFType; 12use crate::gpio::sealed::AFType;
20use crate::gpio::Pull; 13use crate::gpio::Pull;
21use crate::i2c::{Error, Instance, SclPin, SdaPin}; 14use crate::i2c::{Error, Instance, SclPin, SdaPin};
@@ -24,6 +17,92 @@ use crate::pac::i2c;
24use crate::time::Hertz; 17use crate::time::Hertz;
25use crate::{interrupt, Peripheral}; 18use crate::{interrupt, Peripheral};
26 19
20/// # Async I2C Operations with Optional Timeouts
21///
22/// This module provides compatibility for async I2C operations with timeout-based APIs,
23/// even when the "time" feature is not enabled. In the absence of the "time" feature,
24/// operations effectively never time out.
25///
26/// ## Usage Scenario
27/// This is particularly useful in scenarios such as when using RTIC, where a user might
28/// have their own monotonic timer and thus choose not to enable the "time" feature.
29/// In such cases, this module allows the use of async I2C APIs without actual timeout
30/// handling.
31///
32/// ## Functionality
33/// - When the "time" feature is disabled, `Duration` and `Instant` types are provided
34/// as dummy implementations, and timeout functions do not perform real timing but
35/// simply mimic the required interfaces.
36/// - When the "time" feature is enabled, `Duration` and `Instant` from the `embassy_time`
37/// are used, and timeouts are handled as expected.
38#[cfg(not(feature = "time"))]
39mod dummy_time {
40 use core::ops::Sub;
41
42 use super::{Error, Future};
43
44 #[derive(Copy, Clone)]
45 pub struct Duration;
46
47 impl Duration {
48 pub fn dummy_duration() -> Duration {
49 Duration
50 }
51 }
52
53 pub struct Instant;
54
55 impl Instant {
56 pub fn now() -> Self {
57 Self
58 }
59
60 pub fn duration_since(&self, _since: Instant) -> Duration {
61 Duration
62 }
63 }
64
65 impl Sub for Duration {
66 type Output = Duration;
67
68 fn sub(self, _rhs: Duration) -> Duration {
69 Duration
70 }
71 }
72
73 /// Timeout that never times out.
74 pub fn timeout_fn(_timeout: Duration) -> impl Fn() -> Result<(), Error> {
75 move || Ok(())
76 }
77
78 /// This is compatible with `embassy_time::with_timeout` however it never times out.
79 pub async fn with_timeout<F: Future>(_timeout: Duration, fut: F) -> Result<F::Output, ()> {
80 Ok(fut.await)
81 }
82}
83
84#[cfg(not(feature = "time"))]
85use dummy_time::{timeout_fn, with_timeout, Duration, Instant};
86#[cfg(feature = "time")]
87use embassy_time::{Duration, Instant};
88
89#[cfg(feature = "time")]
90fn timeout_fn(timeout: Duration) -> impl Fn() -> Result<(), Error> {
91 let deadline = Instant::now() + timeout;
92 move || {
93 if Instant::now() > deadline {
94 Err(Error::Timeout)
95 } else {
96 Ok(())
97 }
98 }
99}
100
101#[cfg(feature = "time")]
102async fn with_timeout<F: Future>(timeout: Duration, fut: F) -> Result<F::Output, embassy_time::TimeoutError> {
103 embassy_time::with_timeout(timeout, fut).await
104}
105
27/// Interrupt handler. 106/// Interrupt handler.
28pub struct InterruptHandler<T: Instance> { 107pub struct InterruptHandler<T: Instance> {
29 _phantom: PhantomData<T>, 108 _phantom: PhantomData<T>,
@@ -437,7 +516,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
437 result 516 result
438 } 517 }
439 518
440 #[cfg(feature = "time")]
441 async fn write_dma_internal( 519 async fn write_dma_internal(
442 &mut self, 520 &mut self,
443 address: u8, 521 address: u8,
@@ -528,7 +606,6 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
528 Ok(()) 606 Ok(())
529 } 607 }
530 608
531 #[cfg(feature = "time")]
532 async fn read_dma_internal( 609 async fn read_dma_internal(
533 &mut self, 610 &mut self,
534 address: u8, 611 address: u8,
@@ -616,7 +693,16 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
616 where 693 where
617 TXDMA: crate::i2c::TxDma<T>, 694 TXDMA: crate::i2c::TxDma<T>,
618 { 695 {
619 self.write_timeout(address, write, self.timeout).await 696 self.write_timeout_internal(address, write, self.timeout).await
697 }
698
699 #[cfg(not(feature = "time"))]
700 pub async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Error>
701 where
702 TXDMA: crate::i2c::TxDma<T>,
703 {
704 self.write_timeout_internal(address, write, Duration::dummy_duration())
705 .await
620 } 706 }
621 707
622 #[cfg(feature = "time")] 708 #[cfg(feature = "time")]
@@ -624,10 +710,17 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
624 where 710 where
625 TXDMA: crate::i2c::TxDma<T>, 711 TXDMA: crate::i2c::TxDma<T>,
626 { 712 {
713 self.write_timeout_internal(address, write, timeout).await
714 }
715
716 async fn write_timeout_internal(&mut self, address: u8, write: &[u8], timeout: Duration) -> Result<(), Error>
717 where
718 TXDMA: crate::i2c::TxDma<T>,
719 {
627 if write.is_empty() { 720 if write.is_empty() {
628 self.write_internal(address, write, true, timeout_fn(timeout)) 721 self.write_internal(address, write, true, timeout_fn(timeout))
629 } else { 722 } else {
630 embassy_time::with_timeout( 723 with_timeout(
631 timeout, 724 timeout,
632 self.write_dma_internal(address, write, true, true, timeout_fn(timeout)), 725 self.write_dma_internal(address, write, true, true, timeout_fn(timeout)),
633 ) 726 )
@@ -641,7 +734,16 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
641 where 734 where
642 TXDMA: crate::i2c::TxDma<T>, 735 TXDMA: crate::i2c::TxDma<T>,
643 { 736 {
644 self.write_vectored_timeout(address, write, self.timeout).await 737 self.write_vectored_timeout_internal(address, write, self.timeout).await
738 }
739
740 #[cfg(not(feature = "time"))]
741 pub async fn write_vectored(&mut self, address: u8, write: &[&[u8]]) -> Result<(), Error>
742 where
743 TXDMA: crate::i2c::TxDma<T>,
744 {
745 self.write_vectored_timeout_internal(address, write, Duration::dummy_duration())
746 .await
645 } 747 }
646 748
647 #[cfg(feature = "time")] 749 #[cfg(feature = "time")]
@@ -649,6 +751,18 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
649 where 751 where
650 TXDMA: crate::i2c::TxDma<T>, 752 TXDMA: crate::i2c::TxDma<T>,
651 { 753 {
754 self.write_vectored_timeout_internal(address, write, timeout).await
755 }
756
757 async fn write_vectored_timeout_internal(
758 &mut self,
759 address: u8,
760 write: &[&[u8]],
761 timeout: Duration,
762 ) -> Result<(), Error>
763 where
764 TXDMA: crate::i2c::TxDma<T>,
765 {
652 if write.is_empty() { 766 if write.is_empty() {
653 return Err(Error::ZeroLengthTransfer); 767 return Err(Error::ZeroLengthTransfer);
654 } 768 }
@@ -660,7 +774,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
660 let next = iter.next(); 774 let next = iter.next();
661 let is_last = next.is_none(); 775 let is_last = next.is_none();
662 776
663 embassy_time::with_timeout( 777 with_timeout(
664 timeout, 778 timeout,
665 self.write_dma_internal(address, c, first, is_last, timeout_fn(timeout)), 779 self.write_dma_internal(address, c, first, is_last, timeout_fn(timeout)),
666 ) 780 )
@@ -677,7 +791,16 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
677 where 791 where
678 RXDMA: crate::i2c::RxDma<T>, 792 RXDMA: crate::i2c::RxDma<T>,
679 { 793 {
680 self.read_timeout(address, buffer, self.timeout).await 794 self.read_timeout_internal(address, buffer, self.timeout).await
795 }
796
797 #[cfg(not(feature = "time"))]
798 pub async fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Error>
799 where
800 RXDMA: crate::i2c::RxDma<T>,
801 {
802 self.read_timeout_internal(address, buffer, Duration::dummy_duration())
803 .await
681 } 804 }
682 805
683 #[cfg(feature = "time")] 806 #[cfg(feature = "time")]
@@ -685,10 +808,17 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
685 where 808 where
686 RXDMA: crate::i2c::RxDma<T>, 809 RXDMA: crate::i2c::RxDma<T>,
687 { 810 {
811 self.read_timeout_internal(address, buffer, timeout).await
812 }
813
814 async fn read_timeout_internal(&mut self, address: u8, buffer: &mut [u8], timeout: Duration) -> Result<(), Error>
815 where
816 RXDMA: crate::i2c::RxDma<T>,
817 {
688 if buffer.is_empty() { 818 if buffer.is_empty() {
689 self.read_internal(address, buffer, false, timeout_fn(timeout)) 819 self.read_internal(address, buffer, false, timeout_fn(timeout))
690 } else { 820 } else {
691 embassy_time::with_timeout( 821 with_timeout(
692 timeout, 822 timeout,
693 self.read_dma_internal(address, buffer, false, timeout_fn(timeout)), 823 self.read_dma_internal(address, buffer, false, timeout_fn(timeout)),
694 ) 824 )
@@ -703,7 +833,18 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
703 TXDMA: super::TxDma<T>, 833 TXDMA: super::TxDma<T>,
704 RXDMA: super::RxDma<T>, 834 RXDMA: super::RxDma<T>,
705 { 835 {
706 self.write_read_timeout(address, write, read, self.timeout).await 836 self.write_read_timeout_internal(address, write, read, self.timeout)
837 .await
838 }
839
840 #[cfg(not(feature = "time"))]
841 pub async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error>
842 where
843 TXDMA: super::TxDma<T>,
844 RXDMA: super::RxDma<T>,
845 {
846 self.write_read_timeout_internal(address, write, read, Duration::dummy_duration())
847 .await
707 } 848 }
708 849
709 #[cfg(feature = "time")] 850 #[cfg(feature = "time")]
@@ -718,12 +859,26 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
718 TXDMA: super::TxDma<T>, 859 TXDMA: super::TxDma<T>,
719 RXDMA: super::RxDma<T>, 860 RXDMA: super::RxDma<T>,
720 { 861 {
862 self.write_read_timeout_internal(address, write, read, timeout).await
863 }
864
865 async fn write_read_timeout_internal(
866 &mut self,
867 address: u8,
868 write: &[u8],
869 read: &mut [u8],
870 timeout: Duration,
871 ) -> Result<(), Error>
872 where
873 TXDMA: super::TxDma<T>,
874 RXDMA: super::RxDma<T>,
875 {
721 let start_instant = Instant::now(); 876 let start_instant = Instant::now();
722 let check_timeout = timeout_fn(timeout); 877 let check_timeout = timeout_fn(timeout);
723 if write.is_empty() { 878 if write.is_empty() {
724 self.write_internal(address, write, false, &check_timeout)?; 879 self.write_internal(address, write, false, &check_timeout)?;
725 } else { 880 } else {
726 embassy_time::with_timeout( 881 with_timeout(
727 timeout, 882 timeout,
728 self.write_dma_internal(address, write, true, true, &check_timeout), 883 self.write_dma_internal(address, write, true, true, &check_timeout),
729 ) 884 )
@@ -736,7 +891,7 @@ impl<'d, T: Instance, TXDMA, RXDMA> I2c<'d, T, TXDMA, RXDMA> {
736 if read.is_empty() { 891 if read.is_empty() {
737 self.read_internal(address, read, true, &check_timeout)?; 892 self.read_internal(address, read, true, &check_timeout)?;
738 } else { 893 } else {
739 embassy_time::with_timeout( 894 with_timeout(
740 time_left_until_timeout, 895 time_left_until_timeout,
741 self.read_dma_internal(address, read, true, &check_timeout), 896 self.read_dma_internal(address, read, true, &check_timeout),
742 ) 897 )
@@ -1201,15 +1356,3 @@ impl<'d, T: Instance> SetConfig for I2c<'d, T> {
1201 Ok(()) 1356 Ok(())
1202 } 1357 }
1203} 1358}
1204
1205#[cfg(feature = "time")]
1206fn 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}