aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-nrf/src/uarte.rs398
-rw-r--r--embassy-rp/src/i2c.rs400
-rw-r--r--examples/nrf/src/bin/uart_idle.rs7
-rw-r--r--examples/rp/Cargo.toml3
-rw-r--r--examples/rp/src/bin/i2c_async.rs102
5 files changed, 620 insertions, 290 deletions
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs
index d99599112..636d6c7a3 100644
--- a/embassy-nrf/src/uarte.rs
+++ b/embassy-nrf/src/uarte.rs
@@ -173,6 +173,61 @@ impl<'d, T: Instance> Uarte<'d, T> {
173 (self.tx, self.rx) 173 (self.tx, self.rx)
174 } 174 }
175 175
176 /// Split the Uarte into a transmitter and receiver that will
177 /// return on idle, which is determined as the time it takes
178 /// for two bytes to be received.
179 pub fn split_with_idle<U: TimerInstance>(
180 self,
181 timer: impl Peripheral<P = U> + 'd,
182 ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
183 ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
184 ) -> (UarteTx<'d, T>, UarteRxWithIdle<'d, T, U>) {
185 let mut timer = Timer::new(timer);
186
187 into_ref!(ppi_ch1, ppi_ch2);
188
189 let r = T::regs();
190
191 // BAUDRATE register values are `baudrate * 2^32 / 16000000`
192 // source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values
193 //
194 // We want to stop RX if line is idle for 2 bytes worth of time
195 // That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit)
196 // This gives us the amount of 16M ticks for 20 bits.
197 let baudrate = r.baudrate.read().baudrate().variant().unwrap();
198 let timeout = 0x8000_0000 / (baudrate as u32 / 40);
199
200 timer.set_frequency(Frequency::F16MHz);
201 timer.cc(0).write(timeout);
202 timer.cc(0).short_compare_clear();
203 timer.cc(0).short_compare_stop();
204
205 let mut ppi_ch1 = Ppi::new_one_to_two(
206 ppi_ch1.map_into(),
207 Event::from_reg(&r.events_rxdrdy),
208 timer.task_clear(),
209 timer.task_start(),
210 );
211 ppi_ch1.enable();
212
213 let mut ppi_ch2 = Ppi::new_one_to_one(
214 ppi_ch2.map_into(),
215 timer.cc(0).event_compare(),
216 Task::from_reg(&r.tasks_stoprx),
217 );
218 ppi_ch2.enable();
219
220 (
221 self.tx,
222 UarteRxWithIdle {
223 rx: self.rx,
224 timer,
225 ppi_ch1: ppi_ch1,
226 _ppi_ch2: ppi_ch2,
227 },
228 )
229 }
230
176 /// Return the endtx event for use with PPI 231 /// Return the endtx event for use with PPI
177 pub fn event_endtx(&self) -> Event { 232 pub fn event_endtx(&self) -> Event {
178 let r = T::regs(); 233 let r = T::regs();
@@ -597,236 +652,14 @@ impl<'a, T: Instance> Drop for UarteRx<'a, T> {
597 } 652 }
598} 653}
599 654
600#[cfg(not(any(feature = "_nrf9160", feature = "nrf5340")))] 655pub struct UarteRxWithIdle<'d, T: Instance, U: TimerInstance> {
601pub(crate) fn apply_workaround_for_enable_anomaly(_r: &crate::pac::uarte0::RegisterBlock) { 656 rx: UarteRx<'d, T>,
602 // Do nothing 657 timer: Timer<'d, U>,
603}
604
605#[cfg(any(feature = "_nrf9160", feature = "nrf5340"))]
606pub(crate) fn apply_workaround_for_enable_anomaly(r: &crate::pac::uarte0::RegisterBlock) {
607 use core::ops::Deref;
608
609 // Apply workaround for anomalies:
610 // - nRF9160 - anomaly 23
611 // - nRF5340 - anomaly 44
612 let rxenable_reg: *const u32 = ((r.deref() as *const _ as usize) + 0x564) as *const u32;
613 let txenable_reg: *const u32 = ((r.deref() as *const _ as usize) + 0x568) as *const u32;
614
615 // NB Safety: This is taken from Nordic's driver -
616 // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197
617 if unsafe { core::ptr::read_volatile(txenable_reg) } == 1 {
618 r.tasks_stoptx.write(|w| unsafe { w.bits(1) });
619 }
620
621 // NB Safety: This is taken from Nordic's driver -
622 // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197
623 if unsafe { core::ptr::read_volatile(rxenable_reg) } == 1 {
624 r.enable.write(|w| w.enable().enabled());
625 r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
626
627 let mut workaround_succeded = false;
628 // The UARTE is able to receive up to four bytes after the STOPRX task has been triggered.
629 // On lowest supported baud rate (1200 baud), with parity bit and two stop bits configured
630 // (resulting in 12 bits per data byte sent), this may take up to 40 ms.
631 for _ in 0..40000 {
632 // NB Safety: This is taken from Nordic's driver -
633 // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197
634 if unsafe { core::ptr::read_volatile(rxenable_reg) } == 0 {
635 workaround_succeded = true;
636 break;
637 } else {
638 // Need to sleep for 1us here
639 }
640 }
641
642 if !workaround_succeded {
643 panic!("Failed to apply workaround for UART");
644 }
645
646 let errors = r.errorsrc.read().bits();
647 // NB Safety: safe to write back the bits we just read to clear them
648 r.errorsrc.write(|w| unsafe { w.bits(errors) });
649 r.enable.write(|w| w.enable().disabled());
650 }
651}
652
653pub(crate) fn drop_tx_rx(r: &pac::uarte0::RegisterBlock, s: &sealed::State) {
654 if s.tx_rx_refcount.fetch_sub(1, Ordering::Relaxed) == 1 {
655 // Finally we can disable, and we do so for the peripheral
656 // i.e. not just rx concerns.
657 r.enable.write(|w| w.enable().disabled());
658
659 gpio::deconfigure_pin(r.psel.rxd.read().bits());
660 gpio::deconfigure_pin(r.psel.txd.read().bits());
661 gpio::deconfigure_pin(r.psel.rts.read().bits());
662 gpio::deconfigure_pin(r.psel.cts.read().bits());
663
664 trace!("uarte tx and rx drop: done");
665 }
666}
667
668/// Interface to an UARTE peripheral that uses an additional timer and two PPI channels,
669/// allowing it to implement the ReadUntilIdle trait.
670pub struct UarteWithIdle<'d, U: Instance, T: TimerInstance> {
671 tx: UarteTx<'d, U>,
672 rx: UarteRxWithIdle<'d, U, T>,
673}
674
675impl<'d, U: Instance, T: TimerInstance> UarteWithIdle<'d, U, T> {
676 /// Create a new UARTE without hardware flow control
677 pub fn new(
678 uarte: impl Peripheral<P = U> + 'd,
679 timer: impl Peripheral<P = T> + 'd,
680 ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
681 ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
682 irq: impl Peripheral<P = U::Interrupt> + 'd,
683 rxd: impl Peripheral<P = impl GpioPin> + 'd,
684 txd: impl Peripheral<P = impl GpioPin> + 'd,
685 config: Config,
686 ) -> Self {
687 into_ref!(rxd, txd);
688 Self::new_inner(
689 uarte,
690 timer,
691 ppi_ch1,
692 ppi_ch2,
693 irq,
694 rxd.map_into(),
695 txd.map_into(),
696 None,
697 None,
698 config,
699 )
700 }
701
702 /// Create a new UARTE with hardware flow control (RTS/CTS)
703 pub fn new_with_rtscts(
704 uarte: impl Peripheral<P = U> + 'd,
705 timer: impl Peripheral<P = T> + 'd,
706 ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
707 ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
708 irq: impl Peripheral<P = U::Interrupt> + 'd,
709 rxd: impl Peripheral<P = impl GpioPin> + 'd,
710 txd: impl Peripheral<P = impl GpioPin> + 'd,
711 cts: impl Peripheral<P = impl GpioPin> + 'd,
712 rts: impl Peripheral<P = impl GpioPin> + 'd,
713 config: Config,
714 ) -> Self {
715 into_ref!(rxd, txd, cts, rts);
716 Self::new_inner(
717 uarte,
718 timer,
719 ppi_ch1,
720 ppi_ch2,
721 irq,
722 rxd.map_into(),
723 txd.map_into(),
724 Some(cts.map_into()),
725 Some(rts.map_into()),
726 config,
727 )
728 }
729
730 fn new_inner(
731 uarte: impl Peripheral<P = U> + 'd,
732 timer: impl Peripheral<P = T> + 'd,
733 ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
734 ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd,
735 irq: impl Peripheral<P = U::Interrupt> + 'd,
736 rxd: PeripheralRef<'d, AnyPin>,
737 txd: PeripheralRef<'d, AnyPin>,
738 cts: Option<PeripheralRef<'d, AnyPin>>,
739 rts: Option<PeripheralRef<'d, AnyPin>>,
740 config: Config,
741 ) -> Self {
742 let baudrate = config.baudrate;
743 let (tx, rx) = Uarte::new_inner(uarte, irq, rxd, txd, cts, rts, config).split();
744
745 let mut timer = Timer::new(timer);
746
747 into_ref!(ppi_ch1, ppi_ch2);
748
749 let r = U::regs();
750
751 // BAUDRATE register values are `baudrate * 2^32 / 16000000`
752 // source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values
753 //
754 // We want to stop RX if line is idle for 2 bytes worth of time
755 // That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit)
756 // This gives us the amount of 16M ticks for 20 bits.
757 let timeout = 0x8000_0000 / (baudrate as u32 / 40);
758
759 timer.set_frequency(Frequency::F16MHz);
760 timer.cc(0).write(timeout);
761 timer.cc(0).short_compare_clear();
762 timer.cc(0).short_compare_stop();
763
764 let mut ppi_ch1 = Ppi::new_one_to_two(
765 ppi_ch1.map_into(),
766 Event::from_reg(&r.events_rxdrdy),
767 timer.task_clear(),
768 timer.task_start(),
769 );
770 ppi_ch1.enable();
771
772 let mut ppi_ch2 = Ppi::new_one_to_one(
773 ppi_ch2.map_into(),
774 timer.cc(0).event_compare(),
775 Task::from_reg(&r.tasks_stoprx),
776 );
777 ppi_ch2.enable();
778
779 Self {
780 tx,
781 rx: UarteRxWithIdle {
782 rx,
783 timer,
784 ppi_ch1: ppi_ch1,
785 _ppi_ch2: ppi_ch2,
786 },
787 }
788 }
789
790 /// Split the Uarte into a transmitter and receiver, which is
791 /// particuarly useful when having two tasks correlating to
792 /// transmitting and receiving.
793 pub fn split(self) -> (UarteTx<'d, U>, UarteRxWithIdle<'d, U, T>) {
794 (self.tx, self.rx)
795 }
796
797 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
798 self.rx.read(buffer).await
799 }
800
801 pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> {
802 self.tx.write(buffer).await
803 }
804
805 pub fn blocking_read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
806 self.rx.blocking_read(buffer)
807 }
808
809 pub fn blocking_write(&mut self, buffer: &[u8]) -> Result<(), Error> {
810 self.tx.blocking_write(buffer)
811 }
812
813 pub async fn read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
814 self.rx.read_until_idle(buffer).await
815 }
816
817 pub fn blocking_read_until_idle(&mut self, buffer: &mut [u8]) -> Result<usize, Error> {
818 self.rx.blocking_read_until_idle(buffer)
819 }
820}
821
822pub struct UarteRxWithIdle<'d, U: Instance, T: TimerInstance> {
823 rx: UarteRx<'d, U>,
824 timer: Timer<'d, T>,
825 ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 2>, 658 ppi_ch1: Ppi<'d, AnyConfigurableChannel, 1, 2>,
826 _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 1>, 659 _ppi_ch2: Ppi<'d, AnyConfigurableChannel, 1, 1>,
827} 660}
828 661
829impl<'d, U: Instance, T: TimerInstance> UarteRxWithIdle<'d, U, T> { 662impl<'d, T: Instance, U: TimerInstance> UarteRxWithIdle<'d, T, U> {
830 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { 663 pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> {
831 self.ppi_ch1.disable(); 664 self.ppi_ch1.disable();
832 self.rx.read(buffer).await 665 self.rx.read(buffer).await
@@ -848,8 +681,8 @@ impl<'d, U: Instance, T: TimerInstance> UarteRxWithIdle<'d, U, T> {
848 let ptr = buffer.as_ptr(); 681 let ptr = buffer.as_ptr();
849 let len = buffer.len(); 682 let len = buffer.len();
850 683
851 let r = U::regs(); 684 let r = T::regs();
852 let s = U::state(); 685 let s = T::state();
853 686
854 self.ppi_ch1.enable(); 687 self.ppi_ch1.enable();
855 688
@@ -904,7 +737,7 @@ impl<'d, U: Instance, T: TimerInstance> UarteRxWithIdle<'d, U, T> {
904 let ptr = buffer.as_ptr(); 737 let ptr = buffer.as_ptr();
905 let len = buffer.len(); 738 let len = buffer.len();
906 739
907 let r = U::regs(); 740 let r = T::regs();
908 741
909 self.ppi_ch1.enable(); 742 self.ppi_ch1.enable();
910 743
@@ -929,6 +762,75 @@ impl<'d, U: Instance, T: TimerInstance> UarteRxWithIdle<'d, U, T> {
929 Ok(n) 762 Ok(n)
930 } 763 }
931} 764}
765
766#[cfg(not(any(feature = "_nrf9160", feature = "nrf5340")))]
767pub(crate) fn apply_workaround_for_enable_anomaly(_r: &crate::pac::uarte0::RegisterBlock) {
768 // Do nothing
769}
770
771#[cfg(any(feature = "_nrf9160", feature = "nrf5340"))]
772pub(crate) fn apply_workaround_for_enable_anomaly(r: &crate::pac::uarte0::RegisterBlock) {
773 use core::ops::Deref;
774
775 // Apply workaround for anomalies:
776 // - nRF9160 - anomaly 23
777 // - nRF5340 - anomaly 44
778 let rxenable_reg: *const u32 = ((r.deref() as *const _ as usize) + 0x564) as *const u32;
779 let txenable_reg: *const u32 = ((r.deref() as *const _ as usize) + 0x568) as *const u32;
780
781 // NB Safety: This is taken from Nordic's driver -
782 // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197
783 if unsafe { core::ptr::read_volatile(txenable_reg) } == 1 {
784 r.tasks_stoptx.write(|w| unsafe { w.bits(1) });
785 }
786
787 // NB Safety: This is taken from Nordic's driver -
788 // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197
789 if unsafe { core::ptr::read_volatile(rxenable_reg) } == 1 {
790 r.enable.write(|w| w.enable().enabled());
791 r.tasks_stoprx.write(|w| unsafe { w.bits(1) });
792
793 let mut workaround_succeded = false;
794 // The UARTE is able to receive up to four bytes after the STOPRX task has been triggered.
795 // On lowest supported baud rate (1200 baud), with parity bit and two stop bits configured
796 // (resulting in 12 bits per data byte sent), this may take up to 40 ms.
797 for _ in 0..40000 {
798 // NB Safety: This is taken from Nordic's driver -
799 // https://github.com/NordicSemiconductor/nrfx/blob/master/drivers/src/nrfx_uarte.c#L197
800 if unsafe { core::ptr::read_volatile(rxenable_reg) } == 0 {
801 workaround_succeded = true;
802 break;
803 } else {
804 // Need to sleep for 1us here
805 }
806 }
807
808 if !workaround_succeded {
809 panic!("Failed to apply workaround for UART");
810 }
811
812 let errors = r.errorsrc.read().bits();
813 // NB Safety: safe to write back the bits we just read to clear them
814 r.errorsrc.write(|w| unsafe { w.bits(errors) });
815 r.enable.write(|w| w.enable().disabled());
816 }
817}
818
819pub(crate) fn drop_tx_rx(r: &pac::uarte0::RegisterBlock, s: &sealed::State) {
820 if s.tx_rx_refcount.fetch_sub(1, Ordering::Relaxed) == 1 {
821 // Finally we can disable, and we do so for the peripheral
822 // i.e. not just rx concerns.
823 r.enable.write(|w| w.enable().disabled());
824
825 gpio::deconfigure_pin(r.psel.rxd.read().bits());
826 gpio::deconfigure_pin(r.psel.txd.read().bits());
827 gpio::deconfigure_pin(r.psel.rts.read().bits());
828 gpio::deconfigure_pin(r.psel.cts.read().bits());
829
830 trace!("uarte tx and rx drop: done");
831 }
832}
833
932pub(crate) mod sealed { 834pub(crate) mod sealed {
933 use core::sync::atomic::AtomicU8; 835 use core::sync::atomic::AtomicU8;
934 836
@@ -1006,18 +908,6 @@ mod eh02 {
1006 Ok(()) 908 Ok(())
1007 } 909 }
1008 } 910 }
1009
1010 impl<'d, U: Instance, T: TimerInstance> embedded_hal_02::blocking::serial::Write<u8> for UarteWithIdle<'d, U, T> {
1011 type Error = Error;
1012
1013 fn bwrite_all(&mut self, buffer: &[u8]) -> Result<(), Self::Error> {
1014 self.blocking_write(buffer)
1015 }
1016
1017 fn bflush(&mut self) -> Result<(), Self::Error> {
1018 Ok(())
1019 }
1020 }
1021} 911}
1022 912
1023#[cfg(feature = "unstable-traits")] 913#[cfg(feature = "unstable-traits")]
@@ -1067,10 +957,6 @@ mod eh1 {
1067 impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for UarteRx<'d, T> { 957 impl<'d, T: Instance> embedded_hal_1::serial::ErrorType for UarteRx<'d, T> {
1068 type Error = Error; 958 type Error = Error;
1069 } 959 }
1070
1071 impl<'d, U: Instance, T: TimerInstance> embedded_hal_1::serial::ErrorType for UarteWithIdle<'d, U, T> {
1072 type Error = Error;
1073 }
1074} 960}
1075 961
1076#[cfg(all( 962#[cfg(all(
@@ -1126,26 +1012,4 @@ mod eha {
1126 self.read(buffer) 1012 self.read(buffer)
1127 } 1013 }
1128 } 1014 }
1129
1130 impl<'d, U: Instance, T: TimerInstance> embedded_hal_async::serial::Read for UarteWithIdle<'d, U, T> {
1131 type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
1132
1133 fn read<'a>(&'a mut self, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
1134 self.read(buffer)
1135 }
1136 }
1137
1138 impl<'d, U: Instance, T: TimerInstance> embedded_hal_async::serial::Write for UarteWithIdle<'d, U, T> {
1139 type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
1140
1141 fn write<'a>(&'a mut self, buffer: &'a [u8]) -> Self::WriteFuture<'a> {
1142 self.write(buffer)
1143 }
1144
1145 type FlushFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a where Self: 'a;
1146
1147 fn flush<'a>(&'a mut self) -> Self::FlushFuture<'a> {
1148 async move { Ok(()) }
1149 }
1150 }
1151} 1015}
diff --git a/embassy-rp/src/i2c.rs b/embassy-rp/src/i2c.rs
index 52f910cef..68cfc653e 100644
--- a/embassy-rp/src/i2c.rs
+++ b/embassy-rp/src/i2c.rs
@@ -1,9 +1,12 @@
1use core::future;
1use core::marker::PhantomData; 2use core::marker::PhantomData;
3use core::task::Poll;
2 4
5use embassy_cortex_m::interrupt::InterruptExt;
3use embassy_hal_common::{into_ref, PeripheralRef}; 6use embassy_hal_common::{into_ref, PeripheralRef};
7use embassy_sync::waitqueue::AtomicWaker;
4use pac::i2c; 8use pac::i2c;
5 9
6use crate::dma::AnyChannel;
7use crate::gpio::sealed::Pin; 10use crate::gpio::sealed::Pin;
8use crate::gpio::AnyPin; 11use crate::gpio::AnyPin;
9use crate::{pac, peripherals, Peripheral}; 12use crate::{pac, peripherals, Peripheral};
@@ -52,31 +55,278 @@ impl Default for Config {
52const FIFO_SIZE: u8 = 16; 55const FIFO_SIZE: u8 = 16;
53 56
54pub struct I2c<'d, T: Instance, M: Mode> { 57pub struct I2c<'d, T: Instance, M: Mode> {
55 _tx_dma: Option<PeripheralRef<'d, AnyChannel>>,
56 _rx_dma: Option<PeripheralRef<'d, AnyChannel>>,
57 _dma_buf: [u16; 256],
58 phantom: PhantomData<(&'d mut T, M)>, 58 phantom: PhantomData<(&'d mut T, M)>,
59} 59}
60 60
61impl<'d, T: Instance> I2c<'d, T, Blocking> { 61impl<'d, T: Instance> I2c<'d, T, Blocking> {
62 pub fn new_blocking( 62 pub fn new_blocking(
63 _peri: impl Peripheral<P = T> + 'd, 63 peri: impl Peripheral<P = T> + 'd,
64 scl: impl Peripheral<P = impl SclPin<T>> + 'd, 64 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
65 sda: impl Peripheral<P = impl SdaPin<T>> + 'd, 65 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
66 config: Config, 66 config: Config,
67 ) -> Self { 67 ) -> Self {
68 into_ref!(scl, sda); 68 into_ref!(scl, sda);
69 Self::new_inner(_peri, scl.map_into(), sda.map_into(), None, None, config) 69 Self::new_inner(peri, scl.map_into(), sda.map_into(), config)
70 } 70 }
71} 71}
72 72
73impl<'d, T: Instance, M: Mode> I2c<'d, T, M> { 73static I2C_WAKER: AtomicWaker = AtomicWaker::new();
74
75impl<'d, T: Instance> I2c<'d, T, Async> {
76 pub fn new_async(
77 peri: impl Peripheral<P = T> + 'd,
78 scl: impl Peripheral<P = impl SclPin<T>> + 'd,
79 sda: impl Peripheral<P = impl SdaPin<T>> + 'd,
80 irq: impl Peripheral<P = T::Interrupt> + 'd,
81 config: Config,
82 ) -> Self {
83 into_ref!(scl, sda, irq);
84
85 let i2c = Self::new_inner(peri, scl.map_into(), sda.map_into(), config);
86
87 irq.set_handler(Self::on_interrupt);
88 unsafe {
89 let i2c = T::regs();
90
91 // mask everything initially
92 i2c.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0));
93 }
94 irq.unpend();
95 debug_assert!(!irq.is_pending());
96 irq.enable();
97
98 i2c
99 }
100
101 /// Calls `f` to check if we are ready or not.
102 /// If not, `g` is called once the waker is set (to eg enable the required interrupts).
103 async fn wait_on<F, U, G>(&mut self, mut f: F, mut g: G) -> U
104 where
105 F: FnMut(&mut Self) -> Poll<U>,
106 G: FnMut(&mut Self),
107 {
108 future::poll_fn(|cx| {
109 let r = f(self);
110
111 if r.is_pending() {
112 I2C_WAKER.register(cx.waker());
113 g(self);
114 }
115 r
116 })
117 .await
118 }
119
120 // Mask interrupts and wake any task waiting for this interrupt
121 unsafe fn on_interrupt(_: *mut ()) {
122 let i2c = T::regs();
123 i2c.ic_intr_mask().write_value(pac::i2c::regs::IcIntrMask::default());
124
125 I2C_WAKER.wake();
126 }
127
128 async fn read_async_internal(&mut self, buffer: &mut [u8], restart: bool, send_stop: bool) -> Result<(), Error> {
129 if buffer.is_empty() {
130 return Err(Error::InvalidReadBufferLength);
131 }
132
133 let p = T::regs();
134
135 let mut remaining = buffer.len();
136 let mut remaining_queue = buffer.len();
137
138 let mut abort_reason = Ok(());
139
140 while remaining > 0 {
141 // Waggle SCK - basically the same as write
142 let tx_fifo_space = Self::tx_fifo_capacity();
143 let mut batch = 0;
144
145 debug_assert!(remaining_queue > 0);
146
147 for _ in 0..remaining_queue.min(tx_fifo_space as usize) {
148 remaining_queue -= 1;
149 let last = remaining_queue == 0;
150 batch += 1;
151
152 unsafe {
153 p.ic_data_cmd().write(|w| {
154 w.set_restart(restart && remaining_queue == buffer.len() - 1);
155 w.set_stop(last && send_stop);
156 w.set_cmd(true);
157 });
158 }
159 }
160
161 // We've either run out of txfifo or just plain finished setting up
162 // the clocks for the message - either way we need to wait for rx
163 // data.
164
165 debug_assert!(batch > 0);
166 let res = self
167 .wait_on(
168 |me| {
169 let rxfifo = Self::rx_fifo_len();
170 if let Err(abort_reason) = me.read_and_clear_abort_reason() {
171 Poll::Ready(Err(abort_reason))
172 } else if rxfifo >= batch {
173 Poll::Ready(Ok(rxfifo))
174 } else {
175 Poll::Pending
176 }
177 },
178 |_me| unsafe {
179 // Set the read threshold to the number of bytes we're
180 // expecting so we don't get spurious interrupts.
181 p.ic_rx_tl().write(|w| w.set_rx_tl(batch - 1));
182
183 p.ic_intr_mask().modify(|w| {
184 w.set_m_rx_full(true);
185 w.set_m_tx_abrt(true);
186 });
187 },
188 )
189 .await;
190
191 match res {
192 Err(reason) => {
193 abort_reason = Err(reason);
194 break;
195 }
196 Ok(rxfifo) => {
197 // Fetch things from rx fifo. We're assuming we're the only
198 // rxfifo reader, so nothing else can take things from it.
199 let rxbytes = (rxfifo as usize).min(remaining);
200 let received = buffer.len() - remaining;
201 for b in &mut buffer[received..received + rxbytes] {
202 *b = unsafe { p.ic_data_cmd().read().dat() };
203 }
204 remaining -= rxbytes;
205 }
206 };
207 }
208
209 self.wait_stop_det(abort_reason, send_stop).await
210 }
211
212 async fn write_async_internal(
213 &mut self,
214 bytes: impl IntoIterator<Item = u8>,
215 send_stop: bool,
216 ) -> Result<(), Error> {
217 let p = T::regs();
218
219 let mut bytes = bytes.into_iter().peekable();
220
221 let res = 'xmit: loop {
222 let tx_fifo_space = Self::tx_fifo_capacity();
223
224 for _ in 0..tx_fifo_space {
225 if let Some(byte) = bytes.next() {
226 let last = bytes.peek().is_none();
227
228 unsafe {
229 p.ic_data_cmd().write(|w| {
230 w.set_stop(last && send_stop);
231 w.set_cmd(false);
232 w.set_dat(byte);
233 });
234 }
235 } else {
236 break 'xmit Ok(());
237 }
238 }
239
240 let res = self
241 .wait_on(
242 |me| {
243 if let abort_reason @ Err(_) = me.read_and_clear_abort_reason() {
244 Poll::Ready(abort_reason)
245 } else if !Self::tx_fifo_full() {
246 // resume if there's any space free in the tx fifo
247 Poll::Ready(Ok(()))
248 } else {
249 Poll::Pending
250 }
251 },
252 |_me| unsafe {
253 // Set tx "free" threshold a little high so that we get
254 // woken before the fifo completely drains to minimize
255 // transfer stalls.
256 p.ic_tx_tl().write(|w| w.set_tx_tl(1));
257
258 p.ic_intr_mask().modify(|w| {
259 w.set_m_tx_empty(true);
260 w.set_m_tx_abrt(true);
261 })
262 },
263 )
264 .await;
265 if res.is_err() {
266 break res;
267 }
268 };
269
270 self.wait_stop_det(res, send_stop).await
271 }
272
273 /// Helper to wait for a stop bit, for both tx and rx. If we had an abort,
274 /// then we'll get a hardware-generated stop, otherwise wait for a stop if
275 /// we're expecting it.
276 ///
277 /// Also handles an abort which arises while processing the tx fifo.
278 async fn wait_stop_det(&mut self, had_abort: Result<(), Error>, do_stop: bool) -> Result<(), Error> {
279 if had_abort.is_err() || do_stop {
280 let p = T::regs();
281
282 let had_abort2 = self
283 .wait_on(
284 |me| unsafe {
285 // We could see an abort while processing fifo backlog,
286 // so handle it here.
287 let abort = me.read_and_clear_abort_reason();
288 if had_abort.is_ok() && abort.is_err() {
289 Poll::Ready(abort)
290 } else if p.ic_raw_intr_stat().read().stop_det() {
291 Poll::Ready(Ok(()))
292 } else {
293 Poll::Pending
294 }
295 },
296 |_me| unsafe {
297 p.ic_intr_mask().modify(|w| {
298 w.set_m_stop_det(true);
299 w.set_m_tx_abrt(true);
300 });
301 },
302 )
303 .await;
304 unsafe {
305 p.ic_clr_stop_det().read();
306 }
307
308 had_abort.and(had_abort2)
309 } else {
310 had_abort
311 }
312 }
313
314 pub async fn read_async(&mut self, addr: u16, buffer: &mut [u8]) -> Result<(), Error> {
315 Self::setup(addr)?;
316 self.read_async_internal(buffer, false, true).await
317 }
318
319 pub async fn write_async(&mut self, addr: u16, bytes: impl IntoIterator<Item = u8>) -> Result<(), Error> {
320 Self::setup(addr)?;
321 self.write_async_internal(bytes, true).await
322 }
323}
324
325impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> {
74 fn new_inner( 326 fn new_inner(
75 _peri: impl Peripheral<P = T> + 'd, 327 _peri: impl Peripheral<P = T> + 'd,
76 scl: PeripheralRef<'d, AnyPin>, 328 scl: PeripheralRef<'d, AnyPin>,
77 sda: PeripheralRef<'d, AnyPin>, 329 sda: PeripheralRef<'d, AnyPin>,
78 _tx_dma: Option<PeripheralRef<'d, AnyChannel>>,
79 _rx_dma: Option<PeripheralRef<'d, AnyChannel>>,
80 config: Config, 330 config: Config,
81 ) -> Self { 331 ) -> Self {
82 into_ref!(_peri); 332 into_ref!(_peri);
@@ -87,6 +337,10 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
87 let p = T::regs(); 337 let p = T::regs();
88 338
89 unsafe { 339 unsafe {
340 let reset = T::reset();
341 crate::reset::reset(reset);
342 crate::reset::unreset_wait(reset);
343
90 p.ic_enable().write(|w| w.set_enable(false)); 344 p.ic_enable().write(|w| w.set_enable(false));
91 345
92 // Select controller mode & speed 346 // Select controller mode & speed
@@ -172,12 +426,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
172 p.ic_enable().write(|w| w.set_enable(true)); 426 p.ic_enable().write(|w| w.set_enable(true));
173 } 427 }
174 428
175 Self { 429 Self { phantom: PhantomData }
176 _tx_dma,
177 _rx_dma,
178 _dma_buf: [0; 256],
179 phantom: PhantomData,
180 }
181 } 430 }
182 431
183 fn setup(addr: u16) -> Result<(), Error> { 432 fn setup(addr: u16) -> Result<(), Error> {
@@ -198,6 +447,23 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
198 Ok(()) 447 Ok(())
199 } 448 }
200 449
450 #[inline]
451 fn tx_fifo_full() -> bool {
452 Self::tx_fifo_capacity() == 0
453 }
454
455 #[inline]
456 fn tx_fifo_capacity() -> u8 {
457 let p = T::regs();
458 unsafe { FIFO_SIZE - p.ic_txflr().read().txflr() }
459 }
460
461 #[inline]
462 fn rx_fifo_len() -> u8 {
463 let p = T::regs();
464 unsafe { p.ic_rxflr().read().rxflr() }
465 }
466
201 fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> { 467 fn read_and_clear_abort_reason(&mut self) -> Result<(), Error> {
202 let p = T::regs(); 468 let p = T::regs();
203 unsafe { 469 unsafe {
@@ -240,7 +506,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
240 // NOTE(unsafe) We have &mut self 506 // NOTE(unsafe) We have &mut self
241 unsafe { 507 unsafe {
242 // wait until there is space in the FIFO to write the next byte 508 // wait until there is space in the FIFO to write the next byte
243 while p.ic_txflr().read().txflr() == FIFO_SIZE {} 509 while Self::tx_fifo_full() {}
244 510
245 p.ic_data_cmd().write(|w| { 511 p.ic_data_cmd().write(|w| {
246 w.set_restart(restart && first); 512 w.set_restart(restart && first);
@@ -249,7 +515,7 @@ impl<'d, T: Instance, M: Mode> I2c<'d, T, M> {
249 w.set_cmd(true); 515 w.set_cmd(true);
250 }); 516 });
251 517
252 while p.ic_rxflr().read().rxflr() == 0 { 518 while Self::rx_fifo_len() == 0 {
253 self.read_and_clear_abort_reason()?; 519 self.read_and_clear_abort_reason()?;
254 } 520 }
255 521
@@ -451,6 +717,91 @@ mod eh1 {
451 } 717 }
452 } 718 }
453} 719}
720#[cfg(all(feature = "unstable-traits", feature = "nightly"))]
721mod nightly {
722 use core::future::Future;
723
724 use embedded_hal_1::i2c::Operation;
725 use embedded_hal_async::i2c::AddressMode;
726
727 use super::*;
728
729 impl<'d, A, T> embedded_hal_async::i2c::I2c<A> for I2c<'d, T, Async>
730 where
731 A: AddressMode + Into<u16> + 'static,
732 T: Instance + 'd,
733 {
734 type ReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
735 where Self: 'a;
736 type WriteFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
737 where Self: 'a;
738 type WriteReadFuture<'a> = impl Future<Output = Result<(), Self::Error>> + 'a
739 where Self: 'a;
740 type TransactionFuture<'a, 'b> = impl Future<Output = Result<(), Error>> + 'a
741 where Self: 'a, 'b: 'a;
742
743 fn read<'a>(&'a mut self, address: A, buffer: &'a mut [u8]) -> Self::ReadFuture<'a> {
744 let addr: u16 = address.into();
745
746 async move {
747 Self::setup(addr)?;
748 self.read_async_internal(buffer, false, true).await
749 }
750 }
751
752 fn write<'a>(&'a mut self, address: A, write: &'a [u8]) -> Self::WriteFuture<'a> {
753 let addr: u16 = address.into();
754
755 async move {
756 Self::setup(addr)?;
757 self.write_async_internal(write.iter().copied(), true).await
758 }
759 }
760
761 fn write_read<'a>(
762 &'a mut self,
763 address: A,
764 bytes: &'a [u8],
765 buffer: &'a mut [u8],
766 ) -> Self::WriteReadFuture<'a> {
767 let addr: u16 = address.into();
768
769 async move {
770 Self::setup(addr)?;
771 self.write_async_internal(bytes.iter().cloned(), false).await?;
772 self.read_async_internal(buffer, false, true).await
773 }
774 }
775
776 fn transaction<'a, 'b>(
777 &'a mut self,
778 address: A,
779 operations: &'a mut [Operation<'b>],
780 ) -> Self::TransactionFuture<'a, 'b> {
781 let addr: u16 = address.into();
782
783 async move {
784 let mut iterator = operations.iter_mut();
785
786 while let Some(op) = iterator.next() {
787 let last = iterator.len() == 0;
788
789 match op {
790 Operation::Read(buffer) => {
791 Self::setup(addr)?;
792 self.read_async_internal(buffer, false, last).await?;
793 }
794 Operation::Write(buffer) => {
795 Self::setup(addr)?;
796 self.write_async_internal(buffer.into_iter().cloned(), last).await?;
797 }
798 }
799 }
800 Ok(())
801 }
802 }
803 }
804}
454 805
455fn i2c_reserved_addr(addr: u16) -> bool { 806fn i2c_reserved_addr(addr: u16) -> bool {
456 (addr & 0x78) == 0 || (addr & 0x78) == 0x78 807 (addr & 0x78) == 0 || (addr & 0x78) == 0x78
@@ -466,6 +817,7 @@ mod sealed {
466 type Interrupt: Interrupt; 817 type Interrupt: Interrupt;
467 818
468 fn regs() -> crate::pac::i2c::I2c; 819 fn regs() -> crate::pac::i2c::I2c;
820 fn reset() -> crate::pac::resets::regs::Peripherals;
469 } 821 }
470 822
471 pub trait Mode {} 823 pub trait Mode {}
@@ -492,23 +844,31 @@ impl_mode!(Async);
492pub trait Instance: sealed::Instance {} 844pub trait Instance: sealed::Instance {}
493 845
494macro_rules! impl_instance { 846macro_rules! impl_instance {
495 ($type:ident, $irq:ident, $tx_dreq:expr, $rx_dreq:expr) => { 847 ($type:ident, $irq:ident, $reset:ident, $tx_dreq:expr, $rx_dreq:expr) => {
496 impl sealed::Instance for peripherals::$type { 848 impl sealed::Instance for peripherals::$type {
497 const TX_DREQ: u8 = $tx_dreq; 849 const TX_DREQ: u8 = $tx_dreq;
498 const RX_DREQ: u8 = $rx_dreq; 850 const RX_DREQ: u8 = $rx_dreq;
499 851
500 type Interrupt = crate::interrupt::$irq; 852 type Interrupt = crate::interrupt::$irq;
501 853
854 #[inline]
502 fn regs() -> pac::i2c::I2c { 855 fn regs() -> pac::i2c::I2c {
503 pac::$type 856 pac::$type
504 } 857 }
858
859 #[inline]
860 fn reset() -> pac::resets::regs::Peripherals {
861 let mut ret = pac::resets::regs::Peripherals::default();
862 ret.$reset(true);
863 ret
864 }
505 } 865 }
506 impl Instance for peripherals::$type {} 866 impl Instance for peripherals::$type {}
507 }; 867 };
508} 868}
509 869
510impl_instance!(I2C0, I2C0_IRQ, 32, 33); 870impl_instance!(I2C0, I2C0_IRQ, set_i2c0, 32, 33);
511impl_instance!(I2C1, I2C1_IRQ, 34, 35); 871impl_instance!(I2C1, I2C1_IRQ, set_i2c1, 34, 35);
512 872
513pub trait SdaPin<T: Instance>: sealed::SdaPin<T> + crate::gpio::Pin {} 873pub trait SdaPin<T: Instance>: sealed::SdaPin<T> + crate::gpio::Pin {}
514pub trait SclPin<T: Instance>: sealed::SclPin<T> + crate::gpio::Pin {} 874pub trait SclPin<T: Instance>: sealed::SclPin<T> + crate::gpio::Pin {}
diff --git a/examples/nrf/src/bin/uart_idle.rs b/examples/nrf/src/bin/uart_idle.rs
index 09ec624c0..6af4f7097 100644
--- a/examples/nrf/src/bin/uart_idle.rs
+++ b/examples/nrf/src/bin/uart_idle.rs
@@ -15,7 +15,8 @@ async fn main(_spawner: Spawner) {
15 config.baudrate = uarte::Baudrate::BAUD115200; 15 config.baudrate = uarte::Baudrate::BAUD115200;
16 16
17 let irq = interrupt::take!(UARTE0_UART0); 17 let irq = interrupt::take!(UARTE0_UART0);
18 let mut uart = uarte::UarteWithIdle::new(p.UARTE0, p.TIMER0, p.PPI_CH0, p.PPI_CH1, irq, p.P0_08, p.P0_06, config); 18 let uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, config);
19 let (mut tx, mut rx) = uart.split_with_idle(p.TIMER0, p.PPI_CH0, p.PPI_CH1);
19 20
20 info!("uarte initialized!"); 21 info!("uarte initialized!");
21 22
@@ -23,12 +24,12 @@ async fn main(_spawner: Spawner) {
23 let mut buf = [0; 8]; 24 let mut buf = [0; 8];
24 buf.copy_from_slice(b"Hello!\r\n"); 25 buf.copy_from_slice(b"Hello!\r\n");
25 26
26 unwrap!(uart.write(&buf).await); 27 unwrap!(tx.write(&buf).await);
27 info!("wrote hello in uart!"); 28 info!("wrote hello in uart!");
28 29
29 loop { 30 loop {
30 info!("reading..."); 31 info!("reading...");
31 let n = unwrap!(uart.read_until_idle(&mut buf).await); 32 let n = unwrap!(rx.read_until_idle(&mut buf).await);
32 info!("got {} bytes", n); 33 info!("got {} bytes", n);
33 } 34 }
34} 35}
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index a5af8b2f0..747dde515 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -31,3 +31,6 @@ embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.9" }
31embedded-hal-async = { version = "0.1.0-alpha.1" } 31embedded-hal-async = { version = "0.1.0-alpha.1" }
32embedded-io = { version = "0.3.0", features = ["async", "defmt"] } 32embedded-io = { version = "0.3.0", features = ["async", "defmt"] }
33static_cell = "1.0.0" 33static_cell = "1.0.0"
34
35[profile.release]
36debug = true
diff --git a/examples/rp/src/bin/i2c_async.rs b/examples/rp/src/bin/i2c_async.rs
new file mode 100644
index 000000000..d1a2e3cd7
--- /dev/null
+++ b/examples/rp/src/bin/i2c_async.rs
@@ -0,0 +1,102 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_rp::i2c::{self, Config};
8use embassy_rp::interrupt;
9use embassy_time::{Duration, Timer};
10use embedded_hal_async::i2c::I2c;
11use {defmt_rtt as _, panic_probe as _};
12
13#[allow(dead_code)]
14mod mcp23017 {
15 pub const ADDR: u8 = 0x20; // default addr
16
17 macro_rules! mcpregs {
18 ($($name:ident : $val:expr),* $(,)?) => {
19 $(
20 pub const $name: u8 = $val;
21 )*
22
23 pub fn regname(reg: u8) -> &'static str {
24 match reg {
25 $(
26 $val => stringify!($name),
27 )*
28 _ => panic!("bad reg"),
29 }
30 }
31 }
32 }
33
34 // These are correct for IOCON.BANK=0
35 mcpregs! {
36 IODIRA: 0x00,
37 IPOLA: 0x02,
38 GPINTENA: 0x04,
39 DEFVALA: 0x06,
40 INTCONA: 0x08,
41 IOCONA: 0x0A,
42 GPPUA: 0x0C,
43 INTFA: 0x0E,
44 INTCAPA: 0x10,
45 GPIOA: 0x12,
46 OLATA: 0x14,
47 IODIRB: 0x01,
48 IPOLB: 0x03,
49 GPINTENB: 0x05,
50 DEFVALB: 0x07,
51 INTCONB: 0x09,
52 IOCONB: 0x0B,
53 GPPUB: 0x0D,
54 INTFB: 0x0F,
55 INTCAPB: 0x11,
56 GPIOB: 0x13,
57 OLATB: 0x15,
58 }
59}
60
61#[embassy_executor::main]
62async fn main(_spawner: Spawner) {
63 let p = embassy_rp::init(Default::default());
64
65 let sda = p.PIN_14;
66 let scl = p.PIN_15;
67 let irq = interrupt::take!(I2C1_IRQ);
68
69 info!("set up i2c ");
70 let mut i2c = i2c::I2c::new_async(p.I2C1, scl, sda, irq, Config::default());
71
72 use mcp23017::*;
73
74 info!("init mcp23017 config for IxpandO");
75 // init - a outputs, b inputs
76 i2c.write(ADDR, &[IODIRA, 0x00]).await.unwrap();
77 i2c.write(ADDR, &[IODIRB, 0xff]).await.unwrap();
78 i2c.write(ADDR, &[GPPUB, 0xff]).await.unwrap(); // pullups
79
80 let mut val = 1;
81 loop {
82 let mut portb = [0];
83
84 i2c.write_read(mcp23017::ADDR, &[GPIOB], &mut portb).await.unwrap();
85 info!("portb = {:02x}", portb[0]);
86 i2c.write(mcp23017::ADDR, &[GPIOA, val | portb[0]]).await.unwrap();
87 val = val.rotate_left(1);
88
89 // get a register dump
90 info!("getting register dump");
91 let mut regs = [0; 22];
92 i2c.write_read(ADDR, &[0], &mut regs).await.unwrap();
93 // always get the regdump but only display it if portb'0 is set
94 if portb[0] & 1 != 0 {
95 for (idx, reg) in regs.into_iter().enumerate() {
96 info!("{} => {:02x}", regname(idx as u8), reg);
97 }
98 }
99
100 Timer::after(Duration::from_millis(100)).await;
101 }
102}