aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-nrf/src/uarte.rs398
-rw-r--r--examples/nrf/src/bin/uart_idle.rs7
2 files changed, 135 insertions, 270 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/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}