aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-07-18 12:10:37 +0000
committerGitHub <[email protected]>2024-07-18 12:10:37 +0000
commit5e625f274ac567fcbb37ba797629c6b3d33fad2b (patch)
tree3eab45536920ad7f77e045d96fcd198f6f1c535d
parent024097d833ee84df89c3b85aedeea98a67462a43 (diff)
parent4c34132337f12af079f4c81f5f6e0ff03cf9c728 (diff)
Merge pull request #3185 from MathiasKoch/embassy-rp/uart-split-ref
(embassy-rp): Add split_ref fn to uart, allowing a mutable reference split into RX & TX handles
-rw-r--r--embassy-rp/src/uart/buffered.rs16
-rw-r--r--embassy-rp/src/uart/mod.rs63
-rw-r--r--examples/rp/src/bin/uart_buffered_split.rs2
3 files changed, 74 insertions, 7 deletions
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs
index cfbd82ccf..152a432c9 100644
--- a/embassy-rp/src/uart/buffered.rs
+++ b/embassy-rp/src/uart/buffered.rs
@@ -163,9 +163,21 @@ impl<'d, T: Instance> BufferedUart<'d, T> {
163 self.tx.send_break(bits).await 163 self.tx.send_break(bits).await
164 } 164 }
165 165
166 /// sets baudrate on runtime
167 pub fn set_baudrate(&mut self, baudrate: u32) {
168 super::Uart::<'d, T, Async>::set_baudrate_inner(baudrate);
169 }
170
166 /// Split into separate RX and TX handles. 171 /// Split into separate RX and TX handles.
167 pub fn split(self) -> (BufferedUartRx<'d, T>, BufferedUartTx<'d, T>) { 172 pub fn split(self) -> (BufferedUartTx<'d, T>, BufferedUartRx<'d, T>) {
168 (self.rx, self.tx) 173 (self.tx, self.rx)
174 }
175
176 /// Split the Uart into a transmitter and receiver by mutable reference,
177 /// which is particularly useful when having two tasks correlating to
178 /// transmitting and receiving.
179 pub fn split_ref(&mut self) -> (&mut BufferedUartTx<'d, T>, &mut BufferedUartRx<'d, T>) {
180 (&mut self.tx, &mut self.rx)
169 } 181 }
170} 182}
171 183
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs
index 30ece15bd..f546abe71 100644
--- a/embassy-rp/src/uart/mod.rs
+++ b/embassy-rp/src/uart/mod.rs
@@ -7,7 +7,7 @@ use atomic_polyfill::{AtomicU16, Ordering};
7use embassy_futures::select::{select, Either}; 7use embassy_futures::select::{select, Either};
8use embassy_hal_internal::{into_ref, PeripheralRef}; 8use embassy_hal_internal::{into_ref, PeripheralRef};
9use embassy_sync::waitqueue::AtomicWaker; 9use embassy_sync::waitqueue::AtomicWaker;
10use embassy_time::Timer; 10use embassy_time::{Delay, Timer};
11use pac::uart::regs::Uartris; 11use pac::uart::regs::Uartris;
12 12
13use crate::clocks::clk_peri_freq; 13use crate::clocks::clk_peri_freq;
@@ -860,6 +860,56 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
860 }); 860 });
861 } 861 }
862 862
863 fn lcr_modify<R>(f: impl FnOnce(&mut rp_pac::uart::regs::UartlcrH) -> R) -> R {
864 let r = T::regs();
865
866 // Notes from PL011 reference manual:
867 //
868 // - Before writing the LCR, if the UART is enabled it needs to be
869 // disabled and any current TX + RX activity has to be completed
870 //
871 // - There is a BUSY flag which waits for the current TX char, but this is
872 // OR'd with TX FIFO !FULL, so not usable when FIFOs are enabled and
873 // potentially nonempty
874 //
875 // - FIFOs can't be set to disabled whilst a character is in progress
876 // (else "FIFO integrity is not guaranteed")
877 //
878 // Combination of these means there is no general way to halt and poll for
879 // end of TX character, if FIFOs may be enabled. Either way, there is no
880 // way to poll for end of RX character.
881 //
882 // So, insert a 15 Baud period delay before changing the settings.
883 // 15 Baud is comfortably higher than start + max data + parity + stop.
884 // Anything else would require API changes to permit a non-enabled UART
885 // state after init() where settings can be changed safely.
886 let clk_base = crate::clocks::clk_peri_freq();
887
888 let cr = r.uartcr().read();
889 if cr.uarten() {
890 r.uartcr().modify(|w| {
891 w.set_uarten(false);
892 w.set_txe(false);
893 w.set_rxe(false);
894 });
895
896 // Note: Maximise precision here. Show working, the compiler will mop this up.
897 // Create a 16.6 fixed-point fractional division ratio; then scale to 32-bits.
898 let mut brdiv_ratio = 64 * r.uartibrd().read().0 + r.uartfbrd().read().0;
899 brdiv_ratio <<= 10;
900 // 3662 is ~(15 * 244.14) where 244.14 is 16e6 / 2^16
901 let scaled_freq = clk_base / 3662;
902 let wait_time_us = brdiv_ratio / scaled_freq;
903 embedded_hal_1::delay::DelayNs::delay_us(&mut Delay, wait_time_us);
904 }
905
906 let res = r.uartlcr_h().modify(f);
907
908 r.uartcr().write_value(cr);
909
910 res
911 }
912
863 /// sets baudrate on runtime 913 /// sets baudrate on runtime
864 pub fn set_baudrate(&mut self, baudrate: u32) { 914 pub fn set_baudrate(&mut self, baudrate: u32) {
865 Self::set_baudrate_inner(baudrate); 915 Self::set_baudrate_inner(baudrate);
@@ -886,9 +936,7 @@ impl<'d, T: Instance + 'd, M: Mode> Uart<'d, T, M> {
886 r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd)); 936 r.uartibrd().write_value(pac::uart::regs::Uartibrd(baud_ibrd));
887 r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd)); 937 r.uartfbrd().write_value(pac::uart::regs::Uartfbrd(baud_fbrd));
888 938
889 // PL011 needs a (dummy) line control register write to latch in the 939 Self::lcr_modify(|_| {});
890 // divisors. We don't want to actually change LCR contents here.
891 r.uartlcr_h().modify(|_| {});
892 } 940 }
893} 941}
894 942
@@ -923,6 +971,13 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> {
923 pub fn split(self) -> (UartTx<'d, T, M>, UartRx<'d, T, M>) { 971 pub fn split(self) -> (UartTx<'d, T, M>, UartRx<'d, T, M>) {
924 (self.tx, self.rx) 972 (self.tx, self.rx)
925 } 973 }
974
975 /// Split the Uart into a transmitter and receiver by mutable reference,
976 /// which is particularly useful when having two tasks correlating to
977 /// transmitting and receiving.
978 pub fn split_ref(&mut self) -> (&mut UartTx<'d, T, M>, &mut UartRx<'d, T, M>) {
979 (&mut self.tx, &mut self.rx)
980 }
926} 981}
927 982
928impl<'d, T: Instance> Uart<'d, T, Async> { 983impl<'d, T: Instance> Uart<'d, T, Async> {
diff --git a/examples/rp/src/bin/uart_buffered_split.rs b/examples/rp/src/bin/uart_buffered_split.rs
index fac61aa04..468d2b61a 100644
--- a/examples/rp/src/bin/uart_buffered_split.rs
+++ b/examples/rp/src/bin/uart_buffered_split.rs
@@ -31,7 +31,7 @@ async fn main(spawner: Spawner) {
31 static RX_BUF: StaticCell<[u8; 16]> = StaticCell::new(); 31 static RX_BUF: StaticCell<[u8; 16]> = StaticCell::new();
32 let rx_buf = &mut RX_BUF.init([0; 16])[..]; 32 let rx_buf = &mut RX_BUF.init([0; 16])[..];
33 let uart = BufferedUart::new(uart, Irqs, tx_pin, rx_pin, tx_buf, rx_buf, Config::default()); 33 let uart = BufferedUart::new(uart, Irqs, tx_pin, rx_pin, tx_buf, rx_buf, Config::default());
34 let (rx, mut tx) = uart.split(); 34 let (mut tx, rx) = uart.split();
35 35
36 unwrap!(spawner.spawn(reader(rx))); 36 unwrap!(spawner.spawn(reader(rx)));
37 37