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/mod.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/mod.rs')
| -rw-r--r-- | embassy-rp/src/uart/mod.rs | 49 |
1 files changed, 48 insertions, 1 deletions
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>) { |
