diff options
| author | Dario Nieuwenhuis <[email protected]> | 2024-07-18 12:10:37 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-07-18 12:10:37 +0000 |
| commit | 5e625f274ac567fcbb37ba797629c6b3d33fad2b (patch) | |
| tree | 3eab45536920ad7f77e045d96fcd198f6f1c535d | |
| parent | 024097d833ee84df89c3b85aedeea98a67462a43 (diff) | |
| parent | 4c34132337f12af079f4c81f5f6e0ff03cf9c728 (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.rs | 16 | ||||
| -rw-r--r-- | embassy-rp/src/uart/mod.rs | 63 | ||||
| -rw-r--r-- | examples/rp/src/bin/uart_buffered_split.rs | 2 |
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}; | |||
| 7 | use embassy_futures::select::{select, Either}; | 7 | use embassy_futures::select::{select, Either}; |
| 8 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 8 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| 9 | use embassy_sync::waitqueue::AtomicWaker; | 9 | use embassy_sync::waitqueue::AtomicWaker; |
| 10 | use embassy_time::Timer; | 10 | use embassy_time::{Delay, Timer}; |
| 11 | use pac::uart::regs::Uartris; | 11 | use pac::uart::regs::Uartris; |
| 12 | 12 | ||
| 13 | use crate::clocks::clk_peri_freq; | 13 | use 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 | ||
| 928 | impl<'d, T: Instance> Uart<'d, T, Async> { | 983 | impl<'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 | ||
