diff options
| author | pennae <[email protected]> | 2023-04-30 08:04:21 +0200 |
|---|---|---|
| committer | pennae <[email protected]> | 2023-05-01 15:16:30 +0200 |
| commit | 1d2f6667df1bb0299c4e9b4e1660ee729ce2b463 (patch) | |
| tree | a8232ffdd9997e01531250bd1c847fc1333f3bf8 /embassy-rp/src/uart/buffered.rs | |
| parent | 7336b8cd88daf5299ee7f5b329028bbb64051fc6 (diff) | |
rp/uart: add set-break functions
sending break conditions is necessary to implement some protocols, and
the hardware supports this natively. we do have to make sure that we
don't assert a break condition while the uart is busy though, otherwise
the break may be inserted before the last character in the tx fifo.
Diffstat (limited to 'embassy-rp/src/uart/buffered.rs')
| -rw-r--r-- | embassy-rp/src/uart/buffered.rs | 47 |
1 files changed, 47 insertions, 0 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> { |
