diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-06-13 09:43:32 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-06-13 09:43:32 +0000 |
| commit | 38891c29ea708a86ec42c6106ad2fdb1466a0cde (patch) | |
| tree | 8fa89d23d08cbe22191ab0846044896c9ec742d1 | |
| parent | d82c2a1c26c1498d8f18600b650967f1ba2835f3 (diff) | |
| parent | b55e618175e3af81f2b0d04bca45a96adc24a661 (diff) | |
Merge pull request #1549 from timokroeger/uart_rx_idle
embassy-nrf: Idle detection for RX only uarte
| -rw-r--r-- | embassy-nrf/src/uarte.rs | 95 |
1 files changed, 51 insertions, 44 deletions
diff --git a/embassy-nrf/src/uarte.rs b/embassy-nrf/src/uarte.rs index 85a951ae0..48d57fea4 100644 --- a/embassy-nrf/src/uarte.rs +++ b/embassy-nrf/src/uarte.rs | |||
| @@ -205,50 +205,7 @@ impl<'d, T: Instance> Uarte<'d, T> { | |||
| 205 | ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | 205 | ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, |
| 206 | ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | 206 | ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, |
| 207 | ) -> (UarteTx<'d, T>, UarteRxWithIdle<'d, T, U>) { | 207 | ) -> (UarteTx<'d, T>, UarteRxWithIdle<'d, T, U>) { |
| 208 | let timer = Timer::new(timer); | 208 | (self.tx, self.rx.with_idle(timer, ppi_ch1, ppi_ch2)) |
| 209 | |||
| 210 | into_ref!(ppi_ch1, ppi_ch2); | ||
| 211 | |||
| 212 | let r = T::regs(); | ||
| 213 | |||
| 214 | // BAUDRATE register values are `baudrate * 2^32 / 16000000` | ||
| 215 | // source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values | ||
| 216 | // | ||
| 217 | // We want to stop RX if line is idle for 2 bytes worth of time | ||
| 218 | // That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit) | ||
| 219 | // This gives us the amount of 16M ticks for 20 bits. | ||
| 220 | let baudrate = r.baudrate.read().baudrate().variant().unwrap(); | ||
| 221 | let timeout = 0x8000_0000 / (baudrate as u32 / 40); | ||
| 222 | |||
| 223 | timer.set_frequency(Frequency::F16MHz); | ||
| 224 | timer.cc(0).write(timeout); | ||
| 225 | timer.cc(0).short_compare_clear(); | ||
| 226 | timer.cc(0).short_compare_stop(); | ||
| 227 | |||
| 228 | let mut ppi_ch1 = Ppi::new_one_to_two( | ||
| 229 | ppi_ch1.map_into(), | ||
| 230 | Event::from_reg(&r.events_rxdrdy), | ||
| 231 | timer.task_clear(), | ||
| 232 | timer.task_start(), | ||
| 233 | ); | ||
| 234 | ppi_ch1.enable(); | ||
| 235 | |||
| 236 | let mut ppi_ch2 = Ppi::new_one_to_one( | ||
| 237 | ppi_ch2.map_into(), | ||
| 238 | timer.cc(0).event_compare(), | ||
| 239 | Task::from_reg(&r.tasks_stoprx), | ||
| 240 | ); | ||
| 241 | ppi_ch2.enable(); | ||
| 242 | |||
| 243 | ( | ||
| 244 | self.tx, | ||
| 245 | UarteRxWithIdle { | ||
| 246 | rx: self.rx, | ||
| 247 | timer, | ||
| 248 | ppi_ch1: ppi_ch1, | ||
| 249 | _ppi_ch2: ppi_ch2, | ||
| 250 | }, | ||
| 251 | ) | ||
| 252 | } | 209 | } |
| 253 | 210 | ||
| 254 | /// Return the endtx event for use with PPI | 211 | /// Return the endtx event for use with PPI |
| @@ -563,6 +520,56 @@ impl<'d, T: Instance> UarteRx<'d, T> { | |||
| 563 | Self { _p: uarte } | 520 | Self { _p: uarte } |
| 564 | } | 521 | } |
| 565 | 522 | ||
| 523 | /// Upgrade to an instance that supports idle line detection. | ||
| 524 | pub fn with_idle<U: TimerInstance>( | ||
| 525 | self, | ||
| 526 | timer: impl Peripheral<P = U> + 'd, | ||
| 527 | ppi_ch1: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | ||
| 528 | ppi_ch2: impl Peripheral<P = impl ConfigurableChannel + 'd> + 'd, | ||
| 529 | ) -> UarteRxWithIdle<'d, T, U> { | ||
| 530 | let timer = Timer::new(timer); | ||
| 531 | |||
| 532 | into_ref!(ppi_ch1, ppi_ch2); | ||
| 533 | |||
| 534 | let r = T::regs(); | ||
| 535 | |||
| 536 | // BAUDRATE register values are `baudrate * 2^32 / 16000000` | ||
| 537 | // source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values | ||
| 538 | // | ||
| 539 | // We want to stop RX if line is idle for 2 bytes worth of time | ||
| 540 | // That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit) | ||
| 541 | // This gives us the amount of 16M ticks for 20 bits. | ||
| 542 | let baudrate = r.baudrate.read().baudrate().variant().unwrap(); | ||
| 543 | let timeout = 0x8000_0000 / (baudrate as u32 / 40); | ||
| 544 | |||
| 545 | timer.set_frequency(Frequency::F16MHz); | ||
| 546 | timer.cc(0).write(timeout); | ||
| 547 | timer.cc(0).short_compare_clear(); | ||
| 548 | timer.cc(0).short_compare_stop(); | ||
| 549 | |||
| 550 | let mut ppi_ch1 = Ppi::new_one_to_two( | ||
| 551 | ppi_ch1.map_into(), | ||
| 552 | Event::from_reg(&r.events_rxdrdy), | ||
| 553 | timer.task_clear(), | ||
| 554 | timer.task_start(), | ||
| 555 | ); | ||
| 556 | ppi_ch1.enable(); | ||
| 557 | |||
| 558 | let mut ppi_ch2 = Ppi::new_one_to_one( | ||
| 559 | ppi_ch2.map_into(), | ||
| 560 | timer.cc(0).event_compare(), | ||
| 561 | Task::from_reg(&r.tasks_stoprx), | ||
| 562 | ); | ||
| 563 | ppi_ch2.enable(); | ||
| 564 | |||
| 565 | UarteRxWithIdle { | ||
| 566 | rx: self, | ||
| 567 | timer, | ||
| 568 | ppi_ch1: ppi_ch1, | ||
| 569 | _ppi_ch2: ppi_ch2, | ||
| 570 | } | ||
| 571 | } | ||
| 572 | |||
| 566 | /// Read bytes until the buffer is filled. | 573 | /// Read bytes until the buffer is filled. |
| 567 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { | 574 | pub async fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { |
| 568 | if buffer.len() == 0 { | 575 | if buffer.len() == 0 { |
