aboutsummaryrefslogtreecommitdiff
path: root/embassy-rp/src/uart/buffered.rs
diff options
context:
space:
mode:
authorpennae <[email protected]>2023-04-30 08:04:21 +0200
committerpennae <[email protected]>2023-05-01 15:16:30 +0200
commit1d2f6667df1bb0299c4e9b4e1660ee729ce2b463 (patch)
treea8232ffdd9997e01531250bd1c847fc1333f3bf8 /embassy-rp/src/uart/buffered.rs
parent7336b8cd88daf5299ee7f5b329028bbb64051fc6 (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.rs47
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;
5use embassy_cortex_m::interrupt::{Interrupt, InterruptExt}; 5use embassy_cortex_m::interrupt::{Interrupt, InterruptExt};
6use embassy_hal_common::atomic_ring_buffer::RingBuffer; 6use embassy_hal_common::atomic_ring_buffer::RingBuffer;
7use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
8use embassy_time::{Duration, Timer};
8 9
9use super::*; 10use super::*;
11use crate::clocks::clk_peri_freq;
10use crate::RegExt; 12use crate::RegExt;
11 13
12pub struct State { 14pub 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
376impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> { 423impl<'d, T: Instance> Drop for BufferedUartRx<'d, T> {