diff options
| -rw-r--r-- | embassy-rp/src/uart/buffered.rs | 47 | ||||
| -rw-r--r-- | embassy-rp/src/uart/mod.rs | 49 |
2 files changed, 95 insertions, 1 deletions
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs index cb0461930..b87345ee9 100644 --- a/embassy-rp/src/uart/buffered.rs +++ b/embassy-rp/src/uart/buffered.rs | |||
| @@ -5,8 +5,10 @@ use core::task::Poll; | |||
| 5 | use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; | 5 | use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; |
| 6 | use embassy_hal_common::atomic_ring_buffer::RingBuffer; | 6 | use embassy_hal_common::atomic_ring_buffer::RingBuffer; |
| 7 | use embassy_sync::waitqueue::AtomicWaker; | 7 | use embassy_sync::waitqueue::AtomicWaker; |
| 8 | use embassy_time::{Duration, Timer}; | ||
| 8 | 9 | ||
| 9 | use super::*; | 10 | use super::*; |
| 11 | use crate::clocks::clk_peri_freq; | ||
| 10 | use crate::RegExt; | 12 | use crate::RegExt; |
| 11 | 13 | ||
| 12 | pub struct State { | 14 | pub struct State { |
| @@ -136,6 +138,14 @@ impl<'d, T: Instance> BufferedUart<'d, T> { | |||
| 136 | self.rx.blocking_read(buffer) | 138 | self.rx.blocking_read(buffer) |
| 137 | } | 139 | } |
| 138 | 140 | ||
| 141 | pub fn busy(&self) -> bool { | ||
| 142 | self.tx.busy() | ||
| 143 | } | ||
| 144 | |||
| 145 | pub async fn send_break(&mut self, bits: u32) { | ||
| 146 | self.tx.send_break(bits).await | ||
| 147 | } | ||
| 148 | |||
| 139 | pub fn split(self) -> (BufferedUartRx<'d, T>, BufferedUartTx<'d, T>) { | 149 | pub fn split(self) -> (BufferedUartRx<'d, T>, BufferedUartTx<'d, T>) { |
| 140 | (self.rx, self.tx) | 150 | (self.rx, self.tx) |
| 141 | } | 151 | } |
| @@ -371,6 +381,43 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> { | |||
| 371 | } | 381 | } |
| 372 | } | 382 | } |
| 373 | } | 383 | } |
| 384 | |||
| 385 | pub fn busy(&self) -> bool { | ||
| 386 | unsafe { T::regs().uartfr().read().busy() } | ||
| 387 | } | ||
| 388 | |||
| 389 | /// Assert a break condition after waiting for the transmit buffers to empty, | ||
| 390 | /// for the specified number of bit times. This condition must be asserted | ||
| 391 | /// for at least two frame times to be effective, `bits` will adjusted | ||
| 392 | /// according to frame size, parity, and stop bit settings to ensure this. | ||
| 393 | /// | ||
| 394 | /// This method may block for a long amount of time since it has to wait | ||
| 395 | /// for the transmit fifo to empty, which may take a while on slow links. | ||
| 396 | pub async fn send_break(&mut self, bits: u32) { | ||
| 397 | let regs = T::regs(); | ||
| 398 | let bits = bits.max(unsafe { | ||
| 399 | let lcr = regs.uartlcr_h().read(); | ||
| 400 | let width = lcr.wlen() as u32 + 5; | ||
| 401 | let parity = lcr.pen() as u32; | ||
| 402 | let stops = 1 + lcr.stp2() as u32; | ||
| 403 | 2 * (1 + width + parity + stops) | ||
| 404 | }); | ||
| 405 | let divx64 = unsafe { | ||
| 406 | ((regs.uartibrd().read().baud_divint() as u32) << 6) + regs.uartfbrd().read().baud_divfrac() as u32 | ||
| 407 | } as u64; | ||
| 408 | let div_clk = clk_peri_freq() as u64 * 64; | ||
| 409 | let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk; | ||
| 410 | |||
| 411 | Self::flush().await.unwrap(); | ||
| 412 | while self.busy() {} | ||
| 413 | unsafe { | ||
| 414 | regs.uartlcr_h().write_set(|w| w.set_brk(true)); | ||
| 415 | } | ||
| 416 | Timer::after(Duration::from_micros(wait_usecs)).await; | ||
| 417 | unsafe { | ||
| 418 | regs.uartlcr_h().write_clear(|w| w.set_brk(true)); | ||
| 419 | } | ||
| 420 | } | ||
| 374 | } | 421 | } |
| 375 | 422 | ||
| 376 | impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> { | 423 | impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> { |
diff --git a/embassy-rp/src/uart/mod.rs b/embassy-rp/src/uart/mod.rs index f4a93f637..dd4a1cce2 100644 --- a/embassy-rp/src/uart/mod.rs +++ b/embassy-rp/src/uart/mod.rs | |||
| @@ -1,12 +1,14 @@ | |||
| 1 | use core::marker::PhantomData; | 1 | use core::marker::PhantomData; |
| 2 | 2 | ||
| 3 | use embassy_hal_common::{into_ref, PeripheralRef}; | 3 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 4 | use embassy_time::{Duration, Timer}; | ||
| 4 | 5 | ||
| 6 | use crate::clocks::clk_peri_freq; | ||
| 5 | use crate::dma::{AnyChannel, Channel}; | 7 | use crate::dma::{AnyChannel, Channel}; |
| 6 | use crate::gpio::sealed::Pin; | 8 | use crate::gpio::sealed::Pin; |
| 7 | use crate::gpio::AnyPin; | 9 | use crate::gpio::AnyPin; |
| 8 | use crate::pac::io::vals::{Inover, Outover}; | 10 | use crate::pac::io::vals::{Inover, Outover}; |
| 9 | use crate::{pac, peripherals, Peripheral}; | 11 | use crate::{pac, peripherals, Peripheral, RegExt}; |
| 10 | 12 | ||
| 11 | #[cfg(feature = "nightly")] | 13 | #[cfg(feature = "nightly")] |
| 12 | mod buffered; | 14 | mod buffered; |
| @@ -146,6 +148,43 @@ impl<'d, T: Instance, M: Mode> UartTx<'d, T, M> { | |||
| 146 | unsafe { while !r.uartfr().read().txfe() {} } | 148 | unsafe { while !r.uartfr().read().txfe() {} } |
| 147 | Ok(()) | 149 | Ok(()) |
| 148 | } | 150 | } |
| 151 | |||
| 152 | pub fn busy(&self) -> bool { | ||
| 153 | unsafe { T::regs().uartfr().read().busy() } | ||
| 154 | } | ||
| 155 | |||
| 156 | /// Assert a break condition after waiting for the transmit buffers to empty, | ||
| 157 | /// for the specified number of bit times. This condition must be asserted | ||
| 158 | /// for at least two frame times to be effective, `bits` will adjusted | ||
| 159 | /// according to frame size, parity, and stop bit settings to ensure this. | ||
| 160 | /// | ||
| 161 | /// This method may block for a long amount of time since it has to wait | ||
| 162 | /// for the transmit fifo to empty, which may take a while on slow links. | ||
| 163 | pub async fn send_break(&mut self, bits: u32) { | ||
| 164 | let regs = T::regs(); | ||
| 165 | let bits = bits.max(unsafe { | ||
| 166 | let lcr = regs.uartlcr_h().read(); | ||
| 167 | let width = lcr.wlen() as u32 + 5; | ||
| 168 | let parity = lcr.pen() as u32; | ||
| 169 | let stops = 1 + lcr.stp2() as u32; | ||
| 170 | 2 * (1 + width + parity + stops) | ||
| 171 | }); | ||
| 172 | let divx64 = unsafe { | ||
| 173 | ((regs.uartibrd().read().baud_divint() as u32) << 6) + regs.uartfbrd().read().baud_divfrac() as u32 | ||
| 174 | } as u64; | ||
| 175 | let div_clk = clk_peri_freq() as u64 * 64; | ||
| 176 | let wait_usecs = (1_000_000 * bits as u64 * divx64 * 16 + div_clk - 1) / div_clk; | ||
| 177 | |||
| 178 | self.blocking_flush().unwrap(); | ||
| 179 | while self.busy() {} | ||
| 180 | unsafe { | ||
| 181 | regs.uartlcr_h().write_set(|w| w.set_brk(true)); | ||
| 182 | } | ||
| 183 | Timer::after(Duration::from_micros(wait_usecs)).await; | ||
| 184 | unsafe { | ||
| 185 | regs.uartlcr_h().write_clear(|w| w.set_brk(true)); | ||
| 186 | } | ||
| 187 | } | ||
| 149 | } | 188 | } |
| 150 | 189 | ||
| 151 | impl<'d, T: Instance> UartTx<'d, T, Blocking> { | 190 | impl<'d, T: Instance> UartTx<'d, T, Blocking> { |
| @@ -526,6 +565,14 @@ impl<'d, T: Instance, M: Mode> Uart<'d, T, M> { | |||
| 526 | self.rx.blocking_read(buffer) | 565 | self.rx.blocking_read(buffer) |
| 527 | } | 566 | } |
| 528 | 567 | ||
| 568 | pub fn busy(&self) -> bool { | ||
| 569 | self.tx.busy() | ||
| 570 | } | ||
| 571 | |||
| 572 | pub async fn send_break(&mut self, bits: u32) { | ||
| 573 | self.tx.send_break(bits).await | ||
| 574 | } | ||
| 575 | |||
| 529 | /// Split the Uart into a transmitter and receiver, which is particuarly | 576 | /// Split the Uart into a transmitter and receiver, which is particuarly |
| 530 | /// useful when having two tasks correlating to transmitting and receiving. | 577 | /// useful when having two tasks correlating to transmitting and receiving. |
| 531 | pub fn split(self) -> (UartTx<'d, T, M>, UartRx<'d, T, M>) { | 578 | pub fn split(self) -> (UartTx<'d, T, M>, UartRx<'d, T, M>) { |
