diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2022-06-25 23:45:01 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-06-25 23:45:01 +0000 |
| commit | ffc32d3ddb5840b476a473c0248e32f7b9a8a212 (patch) | |
| tree | 1133ce22c290e669d85d35b639ba6421dfcb9d3b | |
| parent | c460af62e0648850484368d5d4984ddf9a2ade7a (diff) | |
| parent | 0beea82f407d961b43f8923b37c00e87a34eaf13 (diff) | |
Merge #833
833: nrf/uart: add support for tx-only and rx-only uart. r=Dirbaio a=Dirbaio
Allow creating UarteRx/UarteTx directly. This allows using uart unidirectionally
(rx-only or tx-only), without having to 'waste' a pin for the unused direction.
Co-authored-by: Dario Nieuwenhuis <[email protected]>
| -rw-r--r-- | embassy-nrf/src/uarte.rs | 176 |
1 files changed, 149 insertions, 27 deletions
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index f626c62a5..459c56c8e 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs | |||
| @@ -19,9 +19,10 @@ use core::task::Poll; | |||
| 19 | 19 | ||
| 20 | use embassy_hal_common::drop::OnDrop; | 20 | use embassy_hal_common::drop::OnDrop; |
| 21 | use embassy_hal_common::unborrow; | 21 | use embassy_hal_common::unborrow; |
| 22 | use futures::future::poll_fn; // Re-export SVD variants to allow user to directly set values. | 22 | use futures::future::poll_fn; |
| 23 | pub use pac::uarte0::baudrate::BAUDRATE_A as Baudrate; | 23 | use pac::uarte0::RegisterBlock; |
| 24 | pub use pac::uarte0::config::PARITY_A as Parity; | 24 | // Re-export SVD variants to allow user to directly set values. |
| 25 | pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; | ||
| 25 | 26 | ||
| 26 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; | 27 | use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; |
| 27 | use crate::gpio::sealed::Pin as _; | 28 | use crate::gpio::sealed::Pin as _; |
| @@ -32,6 +33,7 @@ use crate::timer::{Frequency, Instance as TimerInstance, Timer}; | |||
| 32 | use crate::util::slice_in_ram_or; | 33 | use crate::util::slice_in_ram_or; |
| 33 | use crate::{pac, Unborrow}; | 34 | use crate::{pac, Unborrow}; |
| 34 | 35 | ||
| 36 | #[derive(Clone)] | ||
| 35 | #[non_exhaustive] | 37 | #[non_exhaustive] |
| 36 | pub struct Config { | 38 | pub struct Config { |
| 37 | pub parity: Parity, | 39 | pub parity: Parity, |
| @@ -144,37 +146,18 @@ impl<'d, T: Instance> Uarte<'d, T> { | |||
| 144 | } | 146 | } |
| 145 | r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); | 147 | r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); |
| 146 | 148 | ||
| 147 | // Configure | 149 | irq.set_handler(Self::on_interrupt); |
| 150 | irq.unpend(); | ||
| 151 | irq.enable(); | ||
| 152 | |||
| 148 | let hardware_flow_control = match (rts.is_some(), cts.is_some()) { | 153 | let hardware_flow_control = match (rts.is_some(), cts.is_some()) { |
| 149 | (false, false) => false, | 154 | (false, false) => false, |
| 150 | (true, true) => true, | 155 | (true, true) => true, |
| 151 | _ => panic!("RTS and CTS pins must be either both set or none set."), | 156 | _ => panic!("RTS and CTS pins must be either both set or none set."), |
| 152 | }; | 157 | }; |
| 153 | r.config.write(|w| { | 158 | configure(r, config, hardware_flow_control); |
| 154 | w.hwfc().bit(hardware_flow_control); | ||
| 155 | w.parity().variant(config.parity); | ||
| 156 | w | ||
| 157 | }); | ||
| 158 | r.baudrate.write(|w| w.baudrate().variant(config.baudrate)); | ||
| 159 | |||
| 160 | // Disable all interrupts | ||
| 161 | r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); | ||
| 162 | |||
| 163 | // Reset rxstarted, txstarted. These are used by drop to know whether a transfer was | ||
| 164 | // stopped midway or not. | ||
| 165 | r.events_rxstarted.reset(); | ||
| 166 | r.events_txstarted.reset(); | ||
| 167 | |||
| 168 | irq.set_handler(Self::on_interrupt); | ||
| 169 | irq.unpend(); | ||
| 170 | irq.enable(); | ||
| 171 | |||
| 172 | // Enable | ||
| 173 | apply_workaround_for_enable_anomaly(&r); | ||
| 174 | r.enable.write(|w| w.enable().enabled()); | ||
| 175 | 159 | ||
| 176 | let s = T::state(); | 160 | let s = T::state(); |
| 177 | |||
| 178 | s.tx_rx_refcount.store(2, Ordering::Relaxed); | 161 | s.tx_rx_refcount.store(2, Ordering::Relaxed); |
| 179 | 162 | ||
| 180 | Self { | 163 | Self { |
| @@ -238,7 +221,87 @@ impl<'d, T: Instance> Uarte<'d, T> { | |||
| 238 | } | 221 | } |
| 239 | } | 222 | } |
| 240 | 223 | ||
| 224 | fn configure(r: &RegisterBlock, config: Config, hardware_flow_control: bool) { | ||
| 225 | r.config.write(|w| { | ||
| 226 | w.hwfc().bit(hardware_flow_control); | ||
| 227 | w.parity().variant(config.parity); | ||
| 228 | w | ||
| 229 | }); | ||
| 230 | r.baudrate.write(|w| w.baudrate().variant(config.baudrate)); | ||
| 231 | |||
| 232 | // Disable all interrupts | ||
| 233 | r.intenclr.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); | ||
| 234 | |||
| 235 | // Reset rxstarted, txstarted. These are used by drop to know whether a transfer was | ||
| 236 | // stopped midway or not. | ||
| 237 | r.events_rxstarted.reset(); | ||
| 238 | r.events_txstarted.reset(); | ||
| 239 | |||
| 240 | // Enable | ||
| 241 | apply_workaround_for_enable_anomaly(&r); | ||
| 242 | r.enable.write(|w| w.enable().enabled()); | ||
| 243 | } | ||
| 244 | |||
| 241 | impl<'d, T: Instance> UarteTx<'d, T> { | 245 | impl<'d, T: Instance> UarteTx<'d, T> { |
| 246 | /// Create a new tx-only UARTE without hardware flow control | ||
| 247 | pub fn new( | ||
| 248 | uarte: impl Unborrow<Target = T> + 'd, | ||
| 249 | irq: impl Unborrow<Target = T::Interrupt> + 'd, | ||
| 250 | txd: impl Unborrow<Target = impl GpioPin> + 'd, | ||
| 251 | config: Config, | ||
| 252 | ) -> Self { | ||
| 253 | unborrow!(txd); | ||
| 254 | Self::new_inner(uarte, irq, txd.degrade(), None, config) | ||
| 255 | } | ||
| 256 | |||
| 257 | /// Create a new tx-only UARTE with hardware flow control (RTS/CTS) | ||
| 258 | pub fn new_with_rtscts( | ||
| 259 | uarte: impl Unborrow<Target = T> + 'd, | ||
| 260 | irq: impl Unborrow<Target = T::Interrupt> + 'd, | ||
| 261 | txd: impl Unborrow<Target = impl GpioPin> + 'd, | ||
| 262 | cts: impl Unborrow<Target = impl GpioPin> + 'd, | ||
| 263 | config: Config, | ||
| 264 | ) -> Self { | ||
| 265 | unborrow!(txd, cts); | ||
| 266 | Self::new_inner(uarte, irq, txd.degrade(), Some(cts.degrade()), config) | ||
| 267 | } | ||
| 268 | |||
| 269 | fn new_inner( | ||
| 270 | _uarte: impl Unborrow<Target = T> + 'd, | ||
| 271 | irq: impl Unborrow<Target = T::Interrupt> + 'd, | ||
| 272 | txd: AnyPin, | ||
| 273 | cts: Option<AnyPin>, | ||
| 274 | config: Config, | ||
| 275 | ) -> Self { | ||
| 276 | unborrow!(irq); | ||
| 277 | |||
| 278 | let r = T::regs(); | ||
| 279 | |||
| 280 | txd.set_high(); | ||
| 281 | txd.conf().write(|w| w.dir().output().drive().s0s1()); | ||
| 282 | r.psel.txd.write(|w| unsafe { w.bits(txd.psel_bits()) }); | ||
| 283 | |||
| 284 | if let Some(pin) = &cts { | ||
| 285 | pin.conf().write(|w| w.input().connect().drive().h0h1()); | ||
| 286 | } | ||
| 287 | r.psel.cts.write(|w| unsafe { w.bits(cts.psel_bits()) }); | ||
| 288 | |||
| 289 | r.psel.rxd.write(|w| w.connect().disconnected()); | ||
| 290 | r.psel.rts.write(|w| w.connect().disconnected()); | ||
| 291 | |||
| 292 | let hardware_flow_control = cts.is_some(); | ||
| 293 | configure(r, config, hardware_flow_control); | ||
| 294 | |||
| 295 | irq.set_handler(Uarte::<T>::on_interrupt); | ||
| 296 | irq.unpend(); | ||
| 297 | irq.enable(); | ||
| 298 | |||
| 299 | let s = T::state(); | ||
| 300 | s.tx_rx_refcount.store(1, Ordering::Relaxed); | ||
| 301 | |||
| 302 | Self { phantom: PhantomData } | ||
| 303 | } | ||
| 304 | |||
| 242 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { | 305 | pub async fn write(&mut self, buffer: &[u8]) -> Result<(), Error> { |
| 243 | match self.write_from_ram(buffer).await { | 306 | match self.write_from_ram(buffer).await { |
| 244 | Ok(_) => Ok(()), | 307 | Ok(_) => Ok(()), |
| @@ -372,6 +435,65 @@ impl<'a, T: Instance> Drop for UarteTx<'a, T> { | |||
| 372 | } | 435 | } |
| 373 | 436 | ||
| 374 | impl<'d, T: Instance> UarteRx<'d, T> { | 437 | impl<'d, T: Instance> UarteRx<'d, T> { |
| 438 | /// Create a new rx-only UARTE without hardware flow control | ||
| 439 | pub fn new( | ||
| 440 | uarte: impl Unborrow<Target = T> + 'd, | ||
| 441 | irq: impl Unborrow<Target = T::Interrupt> + 'd, | ||
| 442 | rxd: impl Unborrow<Target = impl GpioPin> + 'd, | ||
| 443 | config: Config, | ||
| 444 | ) -> Self { | ||
| 445 | unborrow!(rxd); | ||
| 446 | Self::new_inner(uarte, irq, rxd.degrade(), None, config) | ||
| 447 | } | ||
| 448 | |||
| 449 | /// Create a new rx-only UARTE with hardware flow control (RTS/CTS) | ||
| 450 | pub fn new_with_rtscts( | ||
| 451 | uarte: impl Unborrow<Target = T> + 'd, | ||
| 452 | irq: impl Unborrow<Target = T::Interrupt> + 'd, | ||
| 453 | rxd: impl Unborrow<Target = impl GpioPin> + 'd, | ||
| 454 | rts: impl Unborrow<Target = impl GpioPin> + 'd, | ||
| 455 | config: Config, | ||
| 456 | ) -> Self { | ||
| 457 | unborrow!(rxd, rts); | ||
| 458 | Self::new_inner(uarte, irq, rxd.degrade(), Some(rts.degrade()), config) | ||
| 459 | } | ||
| 460 | |||
| 461 | fn new_inner( | ||
| 462 | _uarte: impl Unborrow<Target = T> + 'd, | ||
| 463 | irq: impl Unborrow<Target = T::Interrupt> + 'd, | ||
| 464 | rxd: AnyPin, | ||
| 465 | rts: Option<AnyPin>, | ||
| 466 | config: Config, | ||
| 467 | ) -> Self { | ||
| 468 | unborrow!(irq); | ||
| 469 | |||
| 470 | let r = T::regs(); | ||
| 471 | |||
| 472 | rxd.conf().write(|w| w.input().connect().drive().h0h1()); | ||
| 473 | r.psel.rxd.write(|w| unsafe { w.bits(rxd.psel_bits()) }); | ||
| 474 | |||
| 475 | if let Some(pin) = &rts { | ||
| 476 | pin.set_high(); | ||
| 477 | pin.conf().write(|w| w.dir().output().drive().h0h1()); | ||
| 478 | } | ||
| 479 | r.psel.rts.write(|w| unsafe { w.bits(rts.psel_bits()) }); | ||
| 480 | |||
| 481 | r.psel.txd.write(|w| w.connect().disconnected()); | ||
| 482 | r.psel.cts.write(|w| w.connect().disconnected()); | ||
| 483 | |||
| 484 | irq.set_handler(Uarte::<T>::on_interrupt); | ||
| 485 | irq.unpend(); | ||
| 486 | irq.enable(); | ||
| 487 | |||
| 488 | let hardware_flow_control = rts.is_some(); | ||
| 489 | configure(r, config, hardware_flow_control); | ||
| 490 | |||
| 491 | let s = T::state(); | ||
| 492 | s.tx_rx_refcount.store(1, Ordering::Relaxed); | ||
| 493 | |||
| 494 | Self { phantom: PhantomData } | ||
| 495 | } | ||
| 496 | |||
| 375 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | 497 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { |
| 376 | if buffer.len() == 0 { | 498 | if buffer.len() == 0 { |
| 377 | return Err(Error::BufferZeroLength); | 499 | return Err(Error::BufferZeroLength); |
