diff options
| author | Dario Nieuwenhuis <[email protected]> | 2021-01-06 23:36:46 +0100 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2021-01-06 23:36:46 +0100 |
| commit | 5b10ac9cacd4044c53eb89dea6a4d01d8e7f04e8 (patch) | |
| tree | cc35e4d4b9102eede378f301466831235e5f31c8 | |
| parent | deb3c9389202c2e98e092ba7ea9b16f39af006d2 (diff) | |
Add PPI+TIMER to buffered_uarte to prevent IRQ storm
| -rw-r--r-- | embassy-nrf-examples/src/bin/buffered_uart.rs | 6 | ||||
| -rw-r--r-- | embassy-nrf/src/buffered_uarte.rs | 181 |
2 files changed, 106 insertions, 81 deletions
diff --git a/embassy-nrf-examples/src/bin/buffered_uart.rs b/embassy-nrf-examples/src/bin/buffered_uart.rs index 68a76f71e..57c6b4cf4 100644 --- a/embassy-nrf-examples/src/bin/buffered_uart.rs +++ b/embassy-nrf-examples/src/bin/buffered_uart.rs | |||
| @@ -8,6 +8,7 @@ use example_common::*; | |||
| 8 | 8 | ||
| 9 | use cortex_m_rt::entry; | 9 | use cortex_m_rt::entry; |
| 10 | use defmt::panic; | 10 | use defmt::panic; |
| 11 | use nrf52840_hal as hal; | ||
| 11 | use nrf52840_hal::gpio; | 12 | use nrf52840_hal::gpio; |
| 12 | 13 | ||
| 13 | use embassy::executor::{task, Executor}; | 14 | use embassy::executor::{task, Executor}; |
| @@ -35,9 +36,14 @@ async fn run() { | |||
| 35 | rts: None, | 36 | rts: None, |
| 36 | }; | 37 | }; |
| 37 | 38 | ||
| 39 | let ppi = hal::ppi::Parts::new(p.PPI); | ||
| 40 | |||
| 38 | let irq = interrupt::take!(UARTE0_UART0); | 41 | let irq = interrupt::take!(UARTE0_UART0); |
| 39 | let mut u = buffered_uarte::BufferedUarte::new( | 42 | let mut u = buffered_uarte::BufferedUarte::new( |
| 40 | p.UARTE0, | 43 | p.UARTE0, |
| 44 | p.TIMER0, | ||
| 45 | ppi.ppi0, | ||
| 46 | ppi.ppi1, | ||
| 41 | irq, | 47 | irq, |
| 42 | unsafe { &mut RX_BUFFER }, | 48 | unsafe { &mut RX_BUFFER }, |
| 43 | unsafe { &mut TX_BUFFER }, | 49 | unsafe { &mut TX_BUFFER }, |
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index ceb52916f..fac3703a6 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs | |||
| @@ -16,22 +16,20 @@ use embedded_hal::digital::v2::OutputPin; | |||
| 16 | 16 | ||
| 17 | use crate::fmt::{panic, todo, *}; | 17 | use crate::fmt::{panic, todo, *}; |
| 18 | use crate::hal::gpio::Port as GpioPort; | 18 | use crate::hal::gpio::Port as GpioPort; |
| 19 | use crate::hal::ppi::ConfigurablePpi; | ||
| 19 | use crate::interrupt::{self, OwnedInterrupt}; | 20 | use crate::interrupt::{self, OwnedInterrupt}; |
| 20 | use crate::pac; | 21 | use crate::pac; |
| 21 | use crate::pac::uarte0; | ||
| 22 | use crate::util::peripheral::{PeripheralMutex, PeripheralState}; | 22 | use crate::util::peripheral::{PeripheralMutex, PeripheralState}; |
| 23 | use crate::util::ring_buffer::RingBuffer; | 23 | use crate::util::ring_buffer::RingBuffer; |
| 24 | 24 | ||
| 25 | // Re-export SVD variants to allow user to directly set values | 25 | // Re-export SVD variants to allow user to directly set values |
| 26 | pub use crate::hal::uarte::Pins; | 26 | pub use crate::hal::uarte::Pins; |
| 27 | pub use uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; | 27 | pub use pac::uarte0::{baudrate::BAUDRATE_A as Baudrate, config::PARITY_A as Parity}; |
| 28 | 28 | ||
| 29 | #[derive(Copy, Clone, Debug, PartialEq)] | 29 | #[derive(Copy, Clone, Debug, PartialEq)] |
| 30 | enum RxState { | 30 | enum RxState { |
| 31 | Idle, | 31 | Idle, |
| 32 | Receiving, | 32 | Receiving, |
| 33 | ReceivingReady, | ||
| 34 | Stopping, | ||
| 35 | } | 33 | } |
| 36 | 34 | ||
| 37 | #[derive(Copy, Clone, Debug, PartialEq)] | 35 | #[derive(Copy, Clone, Debug, PartialEq)] |
| @@ -40,8 +38,11 @@ enum TxState { | |||
| 40 | Transmitting(usize), | 38 | Transmitting(usize), |
| 41 | } | 39 | } |
| 42 | 40 | ||
| 43 | struct State<'a, U: Instance> { | 41 | struct State<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi> { |
| 44 | inner: U, | 42 | uarte: U, |
| 43 | timer: T, | ||
| 44 | ppi_channel_1: P1, | ||
| 45 | ppi_channel_2: P2, | ||
| 45 | 46 | ||
| 46 | rx: RingBuffer<'a>, | 47 | rx: RingBuffer<'a>, |
| 47 | rx_state: RxState, | 48 | rx_state: RxState, |
| @@ -60,12 +61,16 @@ struct State<'a, U: Instance> { | |||
| 60 | /// are disabled before using `Uarte`. See product specification: | 61 | /// are disabled before using `Uarte`. See product specification: |
| 61 | /// - nrf52832: Section 15.2 | 62 | /// - nrf52832: Section 15.2 |
| 62 | /// - nrf52840: Section 6.1.2 | 63 | /// - nrf52840: Section 6.1.2 |
| 63 | pub struct BufferedUarte<'a, U: Instance> { | 64 | pub struct BufferedUarte< |
| 64 | inner: PeripheralMutex<State<'a, U>>, | 65 | 'a, |
| 66 | U: Instance, | ||
| 67 | T: TimerInstance, | ||
| 68 | P1: ConfigurablePpi, | ||
| 69 | P2: ConfigurablePpi, | ||
| 70 | > { | ||
| 71 | inner: PeripheralMutex<State<'a, U, T, P1, P2>>, | ||
| 65 | } | 72 | } |
| 66 | 73 | ||
| 67 | impl<'a, U: Instance> Unpin for BufferedUarte<'a, U> {} | ||
| 68 | |||
| 69 | #[cfg(any(feature = "52833", feature = "52840"))] | 74 | #[cfg(any(feature = "52833", feature = "52840"))] |
| 70 | fn port_bit(port: GpioPort) -> bool { | 75 | fn port_bit(port: GpioPort) -> bool { |
| 71 | match port { | 76 | match port { |
| @@ -74,9 +79,14 @@ fn port_bit(port: GpioPort) -> bool { | |||
| 74 | } | 79 | } |
| 75 | } | 80 | } |
| 76 | 81 | ||
| 77 | impl<'a, U: Instance> BufferedUarte<'a, U> { | 82 | impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi> |
| 83 | BufferedUarte<'a, U, T, P1, P2> | ||
| 84 | { | ||
| 78 | pub fn new( | 85 | pub fn new( |
| 79 | uarte: U, | 86 | uarte: U, |
| 87 | timer: T, | ||
| 88 | mut ppi_channel_1: P1, | ||
| 89 | mut ppi_channel_2: P2, | ||
| 80 | irq: U::Interrupt, | 90 | irq: U::Interrupt, |
| 81 | rx_buffer: &'a mut [u8], | 91 | rx_buffer: &'a mut [u8], |
| 82 | tx_buffer: &'a mut [u8], | 92 | tx_buffer: &'a mut [u8], |
| @@ -141,10 +151,41 @@ impl<'a, U: Instance> BufferedUarte<'a, U> { | |||
| 141 | irq.disable(); | 151 | irq.disable(); |
| 142 | irq.pend(); | 152 | irq.pend(); |
| 143 | 153 | ||
| 154 | // BAUDRATE register values are `baudrate * 2^32 / 16000000` | ||
| 155 | // source: https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values | ||
| 156 | // | ||
| 157 | // We want to stop RX if line is idle for 2 bytes worth of time | ||
| 158 | // That is 20 bits (each byte is 1 start bit + 8 data bits + 1 stop bit) | ||
| 159 | // This gives us the amount of 16M ticks for 20 bits. | ||
| 160 | let timeout = 0x8000_0000 / (baudrate as u32 / 40); | ||
| 161 | |||
| 162 | timer.tasks_stop.write(|w| w.tasks_stop().set_bit()); | ||
| 163 | timer.bitmode.write(|w| w.bitmode()._32bit()); | ||
| 164 | timer.prescaler.write(|w| unsafe { w.prescaler().bits(0) }); | ||
| 165 | timer.cc[0].write(|w| unsafe { w.bits(timeout) }); | ||
| 166 | timer.mode.write(|w| w.mode().timer()); | ||
| 167 | timer.shorts.write(|w| { | ||
| 168 | w.compare0_clear().set_bit(); | ||
| 169 | w.compare0_stop().set_bit(); | ||
| 170 | w | ||
| 171 | }); | ||
| 172 | |||
| 173 | ppi_channel_1.set_event_endpoint(&uarte.events_rxdrdy); | ||
| 174 | ppi_channel_1.set_task_endpoint(&timer.tasks_clear); | ||
| 175 | ppi_channel_1.set_fork_task_endpoint(&timer.tasks_start); | ||
| 176 | ppi_channel_1.enable(); | ||
| 177 | |||
| 178 | ppi_channel_2.set_event_endpoint(&timer.events_compare[0]); | ||
| 179 | ppi_channel_2.set_task_endpoint(&uarte.tasks_stoprx); | ||
| 180 | ppi_channel_2.enable(); | ||
| 181 | |||
| 144 | BufferedUarte { | 182 | BufferedUarte { |
| 145 | inner: PeripheralMutex::new( | 183 | inner: PeripheralMutex::new( |
| 146 | State { | 184 | State { |
| 147 | inner: uarte, | 185 | uarte, |
| 186 | timer, | ||
| 187 | ppi_channel_1, | ||
| 188 | ppi_channel_2, | ||
| 148 | 189 | ||
| 149 | rx: RingBuffer::new(rx_buffer), | 190 | rx: RingBuffer::new(rx_buffer), |
| 150 | rx_state: RxState::Idle, | 191 | rx_state: RxState::Idle, |
| @@ -159,19 +200,23 @@ impl<'a, U: Instance> BufferedUarte<'a, U> { | |||
| 159 | } | 200 | } |
| 160 | } | 201 | } |
| 161 | 202 | ||
| 162 | fn inner(self: Pin<&mut Self>) -> Pin<&mut PeripheralMutex<State<'a, U>>> { | 203 | fn inner(self: Pin<&mut Self>) -> Pin<&mut PeripheralMutex<State<'a, U, T, P1, P2>>> { |
| 163 | unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) } | 204 | unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) } |
| 164 | } | 205 | } |
| 165 | } | 206 | } |
| 166 | 207 | ||
| 167 | impl<'a, U: Instance> Drop for BufferedUarte<'a, U> { | 208 | impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi> Drop |
| 209 | for BufferedUarte<'a, U, T, P1, P2> | ||
| 210 | { | ||
| 168 | fn drop(&mut self) { | 211 | fn drop(&mut self) { |
| 169 | // stop DMA before dropping, because DMA is using the buffer in `self`. | 212 | // stop DMA before dropping, because DMA is using the buffer in `self`. |
| 170 | todo!() | 213 | todo!() |
| 171 | } | 214 | } |
| 172 | } | 215 | } |
| 173 | 216 | ||
| 174 | impl<'a, U: Instance> AsyncBufRead for BufferedUarte<'a, U> { | 217 | impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi> AsyncBufRead |
| 218 | for BufferedUarte<'a, U, T, P1, P2> | ||
| 219 | { | ||
| 175 | fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> { | 220 | fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> { |
| 176 | self.inner().with(|state, _irq| { | 221 | self.inner().with(|state, _irq| { |
| 177 | // Conservative compiler fence to prevent optimizations that do not | 222 | // Conservative compiler fence to prevent optimizations that do not |
| @@ -190,13 +235,6 @@ impl<'a, U: Instance> AsyncBufRead for BufferedUarte<'a, U> { | |||
| 190 | } | 235 | } |
| 191 | 236 | ||
| 192 | trace!(" empty"); | 237 | trace!(" empty"); |
| 193 | |||
| 194 | if state.rx_state == RxState::ReceivingReady { | ||
| 195 | trace!(" stopping"); | ||
| 196 | state.rx_state = RxState::Stopping; | ||
| 197 | state.inner.tasks_stoprx.write(|w| unsafe { w.bits(1) }); | ||
| 198 | } | ||
| 199 | |||
| 200 | state.rx_waker.register(cx.waker()); | 238 | state.rx_waker.register(cx.waker()); |
| 201 | Poll::<Result<&[u8]>>::Pending | 239 | Poll::<Result<&[u8]>>::Pending |
| 202 | }) | 240 | }) |
| @@ -211,7 +249,9 @@ impl<'a, U: Instance> AsyncBufRead for BufferedUarte<'a, U> { | |||
| 211 | } | 249 | } |
| 212 | } | 250 | } |
| 213 | 251 | ||
| 214 | impl<'a, U: Instance> AsyncWrite for BufferedUarte<'a, U> { | 252 | impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi> AsyncWrite |
| 253 | for BufferedUarte<'a, U, T, P1, P2> | ||
| 254 | { | ||
| 215 | fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize>> { | 255 | fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize>> { |
| 216 | self.inner().with(|state, irq| { | 256 | self.inner().with(|state, irq| { |
| 217 | trace!("poll_write: {:?}", buf.len()); | 257 | trace!("poll_write: {:?}", buf.len()); |
| @@ -241,38 +281,28 @@ impl<'a, U: Instance> AsyncWrite for BufferedUarte<'a, U> { | |||
| 241 | } | 281 | } |
| 242 | } | 282 | } |
| 243 | 283 | ||
| 244 | impl<'a, U: Instance> PeripheralState for State<'a, U> { | 284 | impl<'a, U: Instance, T: TimerInstance, P1: ConfigurablePpi, P2: ConfigurablePpi> PeripheralState |
| 285 | for State<'a, U, T, P1, P2> | ||
| 286 | { | ||
| 245 | type Interrupt = U::Interrupt; | 287 | type Interrupt = U::Interrupt; |
| 246 | |||
| 247 | fn on_interrupt(&mut self) { | 288 | fn on_interrupt(&mut self) { |
| 248 | trace!("irq: start"); | 289 | trace!("irq: start"); |
| 249 | let mut more_work = true; | 290 | loop { |
| 250 | while more_work { | ||
| 251 | more_work = false; | ||
| 252 | match self.rx_state { | 291 | match self.rx_state { |
| 253 | RxState::Idle => { | 292 | RxState::Idle => { |
| 254 | trace!(" irq_rx: in state idle"); | 293 | trace!(" irq_rx: in state idle"); |
| 255 | 294 | ||
| 256 | if self.inner.events_rxdrdy.read().bits() != 0 { | ||
| 257 | trace!(" irq_rx: rxdrdy?????"); | ||
| 258 | self.inner.events_rxdrdy.reset(); | ||
| 259 | } | ||
| 260 | |||
| 261 | if self.inner.events_endrx.read().bits() != 0 { | ||
| 262 | panic!("unexpected endrx"); | ||
| 263 | } | ||
| 264 | |||
| 265 | let buf = self.rx.push_buf(); | 295 | let buf = self.rx.push_buf(); |
| 266 | if buf.len() != 0 { | 296 | if buf.len() != 0 { |
| 267 | trace!(" irq_rx: starting {:?}", buf.len()); | 297 | trace!(" irq_rx: starting {:?}", buf.len()); |
| 268 | self.rx_state = RxState::Receiving; | 298 | self.rx_state = RxState::Receiving; |
| 269 | 299 | ||
| 270 | // Set up the DMA read | 300 | // Set up the DMA read |
| 271 | self.inner.rxd.ptr.write(|w| | 301 | self.uarte.rxd.ptr.write(|w| |
| 272 | // The PTR field is a full 32 bits wide and accepts the full range | 302 | // The PTR field is a full 32 bits wide and accepts the full range |
| 273 | // of values. | 303 | // of values. |
| 274 | unsafe { w.ptr().bits(buf.as_ptr() as u32) }); | 304 | unsafe { w.ptr().bits(buf.as_ptr() as u32) }); |
| 275 | self.inner.rxd.maxcnt.write(|w| | 305 | self.uarte.rxd.maxcnt.write(|w| |
| 276 | // We're giving it the length of the buffer, so no danger of | 306 | // We're giving it the length of the buffer, so no danger of |
| 277 | // accessing invalid memory. We have verified that the length of the | 307 | // accessing invalid memory. We have verified that the length of the |
| 278 | // buffer fits in an `u8`, so the cast to `u8` is also fine. | 308 | // buffer fits in an `u8`, so the cast to `u8` is also fine. |
| @@ -282,60 +312,34 @@ impl<'a, U: Instance> PeripheralState for State<'a, U> { | |||
| 282 | unsafe { w.maxcnt().bits(buf.len() as _) }); | 312 | unsafe { w.maxcnt().bits(buf.len() as _) }); |
| 283 | trace!(" irq_rx: buf {:?} {:?}", buf.as_ptr() as u32, buf.len()); | 313 | trace!(" irq_rx: buf {:?} {:?}", buf.as_ptr() as u32, buf.len()); |
| 284 | 314 | ||
| 285 | // Enable RXRDY interrupt. | ||
| 286 | self.inner.events_rxdrdy.reset(); | ||
| 287 | self.inner.intenset.write(|w| w.rxdrdy().set()); | ||
| 288 | |||
| 289 | // Start UARTE Receive transaction | 315 | // Start UARTE Receive transaction |
| 290 | self.inner.tasks_startrx.write(|w| | 316 | self.uarte.tasks_startrx.write(|w| |
| 291 | // `1` is a valid value to write to task registers. | 317 | // `1` is a valid value to write to task registers. |
| 292 | unsafe { w.bits(1) }); | 318 | unsafe { w.bits(1) }); |
| 293 | } | 319 | } |
| 320 | break; | ||
| 294 | } | 321 | } |
| 295 | RxState::Receiving => { | 322 | RxState::Receiving => { |
| 296 | trace!(" irq_rx: in state receiving"); | 323 | trace!(" irq_rx: in state receiving"); |
| 297 | if self.inner.events_rxdrdy.read().bits() != 0 { | 324 | if self.uarte.events_endrx.read().bits() != 0 { |
| 298 | trace!(" irq_rx: rxdrdy"); | 325 | self.timer.tasks_stop.write(|w| w.tasks_stop().set_bit()); |
| 299 | |||
| 300 | // Disable the RXRDY event interrupt | ||
| 301 | // RXRDY is triggered for every byte, but we only care about whether we have | ||
| 302 | // some bytes or not. So as soon as we have at least one, disable it, to avoid | ||
| 303 | // wasting CPU cycles in interrupts. | ||
| 304 | self.inner.intenclr.write(|w| w.rxdrdy().clear()); | ||
| 305 | |||
| 306 | self.inner.events_rxdrdy.reset(); | ||
| 307 | |||
| 308 | self.rx_waker.wake(); | ||
| 309 | self.rx_state = RxState::ReceivingReady; | ||
| 310 | more_work = true; // in case we also have endrx pending | ||
| 311 | } | ||
| 312 | } | ||
| 313 | RxState::ReceivingReady | RxState::Stopping => { | ||
| 314 | trace!(" irq_rx: in state ReceivingReady"); | ||
| 315 | |||
| 316 | if self.inner.events_rxdrdy.read().bits() != 0 { | ||
| 317 | trace!(" irq_rx: rxdrdy"); | ||
| 318 | self.inner.events_rxdrdy.reset(); | ||
| 319 | } | ||
| 320 | 326 | ||
| 321 | if self.inner.events_endrx.read().bits() != 0 { | 327 | let n: usize = self.uarte.rxd.amount.read().amount().bits() as usize; |
| 322 | let n: usize = self.inner.rxd.amount.read().amount().bits() as usize; | ||
| 323 | trace!(" irq_rx: endrx {:?}", n); | 328 | trace!(" irq_rx: endrx {:?}", n); |
| 324 | self.rx.push(n); | 329 | self.rx.push(n); |
| 325 | 330 | ||
| 326 | self.inner.events_endrx.reset(); | 331 | self.uarte.events_endrx.reset(); |
| 327 | 332 | ||
| 328 | self.rx_waker.wake(); | 333 | self.rx_waker.wake(); |
| 329 | self.rx_state = RxState::Idle; | 334 | self.rx_state = RxState::Idle; |
| 330 | more_work = true; // start another rx if possible | 335 | } else { |
| 336 | break; | ||
| 331 | } | 337 | } |
| 332 | } | 338 | } |
| 333 | } | 339 | } |
| 334 | } | 340 | } |
| 335 | 341 | ||
| 336 | more_work = true; | 342 | loop { |
| 337 | while more_work { | ||
| 338 | more_work = false; | ||
| 339 | match self.tx_state { | 343 | match self.tx_state { |
| 340 | TxState::Idle => { | 344 | TxState::Idle => { |
| 341 | trace!(" irq_tx: in state Idle"); | 345 | trace!(" irq_tx: in state Idle"); |
| @@ -345,11 +349,11 @@ impl<'a, U: Instance> PeripheralState for State<'a, U> { | |||
| 345 | self.tx_state = TxState::Transmitting(buf.len()); | 349 | self.tx_state = TxState::Transmitting(buf.len()); |
| 346 | 350 | ||
| 347 | // Set up the DMA write | 351 | // Set up the DMA write |
| 348 | self.inner.txd.ptr.write(|w| | 352 | self.uarte.txd.ptr.write(|w| |
| 349 | // The PTR field is a full 32 bits wide and accepts the full range | 353 | // The PTR field is a full 32 bits wide and accepts the full range |
| 350 | // of values. | 354 | // of values. |
| 351 | unsafe { w.ptr().bits(buf.as_ptr() as u32) }); | 355 | unsafe { w.ptr().bits(buf.as_ptr() as u32) }); |
| 352 | self.inner.txd.maxcnt.write(|w| | 356 | self.uarte.txd.maxcnt.write(|w| |
| 353 | // We're giving it the length of the buffer, so no danger of | 357 | // We're giving it the length of the buffer, so no danger of |
| 354 | // accessing invalid memory. We have verified that the length of the | 358 | // accessing invalid memory. We have verified that the length of the |
| 355 | // buffer fits in an `u8`, so the cast to `u8` is also fine. | 359 | // buffer fits in an `u8`, so the cast to `u8` is also fine. |
| @@ -359,21 +363,23 @@ impl<'a, U: Instance> PeripheralState for State<'a, U> { | |||
| 359 | unsafe { w.maxcnt().bits(buf.len() as _) }); | 363 | unsafe { w.maxcnt().bits(buf.len() as _) }); |
| 360 | 364 | ||
| 361 | // Start UARTE Transmit transaction | 365 | // Start UARTE Transmit transaction |
| 362 | self.inner.tasks_starttx.write(|w| | 366 | self.uarte.tasks_starttx.write(|w| |
| 363 | // `1` is a valid value to write to task registers. | 367 | // `1` is a valid value to write to task registers. |
| 364 | unsafe { w.bits(1) }); | 368 | unsafe { w.bits(1) }); |
| 365 | } | 369 | } |
| 370 | break; | ||
| 366 | } | 371 | } |
| 367 | TxState::Transmitting(n) => { | 372 | TxState::Transmitting(n) => { |
| 368 | trace!(" irq_tx: in state Transmitting"); | 373 | trace!(" irq_tx: in state Transmitting"); |
| 369 | if self.inner.events_endtx.read().bits() != 0 { | 374 | if self.uarte.events_endtx.read().bits() != 0 { |
| 370 | self.inner.events_endtx.reset(); | 375 | self.uarte.events_endtx.reset(); |
| 371 | 376 | ||
| 372 | trace!(" irq_tx: endtx {:?}", n); | 377 | trace!(" irq_tx: endtx {:?}", n); |
| 373 | self.tx.pop(n); | 378 | self.tx.pop(n); |
| 374 | self.tx_waker.wake(); | 379 | self.tx_waker.wake(); |
| 375 | self.tx_state = TxState::Idle; | 380 | self.tx_state = TxState::Idle; |
| 376 | more_work = true; // start another tx if possible | 381 | } else { |
| 382 | break; | ||
| 377 | } | 383 | } |
| 378 | } | 384 | } |
| 379 | } | 385 | } |
| @@ -388,9 +394,14 @@ mod sealed { | |||
| 388 | impl Instance for crate::pac::UARTE0 {} | 394 | impl Instance for crate::pac::UARTE0 {} |
| 389 | #[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] | 395 | #[cfg(any(feature = "52833", feature = "52840", feature = "9160"))] |
| 390 | impl Instance for crate::pac::UARTE1 {} | 396 | impl Instance for crate::pac::UARTE1 {} |
| 397 | |||
| 398 | pub trait TimerInstance {} | ||
| 399 | impl TimerInstance for crate::pac::TIMER0 {} | ||
| 400 | impl TimerInstance for crate::pac::TIMER1 {} | ||
| 401 | impl TimerInstance for crate::pac::TIMER2 {} | ||
| 391 | } | 402 | } |
| 392 | 403 | ||
| 393 | pub trait Instance: Deref<Target = uarte0::RegisterBlock> + sealed::Instance { | 404 | pub trait Instance: Deref<Target = pac::uarte0::RegisterBlock> + sealed::Instance { |
| 394 | type Interrupt: OwnedInterrupt; | 405 | type Interrupt: OwnedInterrupt; |
| 395 | } | 406 | } |
| 396 | 407 | ||
| @@ -402,3 +413,11 @@ impl Instance for pac::UARTE0 { | |||
| 402 | impl Instance for pac::UARTE1 { | 413 | impl Instance for pac::UARTE1 { |
| 403 | type Interrupt = interrupt::UARTE1Interrupt; | 414 | type Interrupt = interrupt::UARTE1Interrupt; |
| 404 | } | 415 | } |
| 416 | |||
| 417 | pub trait TimerInstance: | ||
| 418 | Deref<Target = pac::timer0::RegisterBlock> + sealed::TimerInstance | ||
| 419 | { | ||
| 420 | } | ||
| 421 | impl TimerInstance for crate::pac::TIMER0 {} | ||
| 422 | impl TimerInstance for crate::pac::TIMER1 {} | ||
| 423 | impl TimerInstance for crate::pac::TIMER2 {} | ||
