aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimo Kröger <[email protected]>2023-01-05 18:45:58 +0100
committerTimo Kröger <[email protected]>2023-01-05 18:45:58 +0100
commit1096a9746c0843e4a26fcec3fca7f9d6d9d57f01 (patch)
tree93fe51a391cb60198b76f4e1b3cc405e7bc0d948
parent840a75674b632485d5b45cfece27870ded0edfcd (diff)
rp: Improve BufferedUart interrupt handling
* Only clear interrupt flags that have fired (so that we do not lose any error flags) * Enable RX interrupt when a read is requested, disable it when the RX buffer is full * Rework TX interrupt handling: its "edge" triggered by a FIFO threshold
-rw-r--r--embassy-rp/src/uart/buffered.rs79
1 files changed, 58 insertions, 21 deletions
diff --git a/embassy-rp/src/uart/buffered.rs b/embassy-rp/src/uart/buffered.rs
index 6465a20c6..b9fc33eae 100644
--- a/embassy-rp/src/uart/buffered.rs
+++ b/embassy-rp/src/uart/buffered.rs
@@ -7,6 +7,7 @@ use embassy_hal_common::atomic_ring_buffer::RingBuffer;
7use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
8 8
9use super::*; 9use super::*;
10use crate::RegExt;
10 11
11pub struct State { 12pub struct State {
12 tx_waker: AtomicWaker, 13 tx_waker: AtomicWaker,
@@ -57,6 +58,19 @@ fn init<'d, T: Instance + 'd>(
57 let len = rx_buffer.len(); 58 let len = rx_buffer.len();
58 unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) }; 59 unsafe { state.rx_buf.init(rx_buffer.as_mut_ptr(), len) };
59 60
61 // From the datasheet:
62 // "The transmit interrupt is based on a transition through a level, rather
63 // than on the level itself. When the interrupt and the UART is enabled
64 // before any data is written to the transmit FIFO the interrupt is not set.
65 // The interrupt is only set, after written data leaves the single location
66 // of the transmit FIFO and it becomes empty."
67 //
68 // This means we can leave the interrupt enabled the whole time as long as
69 // we clear it after it happens. The downside is that the we manually have
70 // to pend the ISR when we want data transmission to start.
71 let regs = T::regs();
72 unsafe { regs.uartimsc().write_set(|w| w.set_txim(true)) };
73
60 irq.set_handler(on_interrupt::<T>); 74 irq.set_handler(on_interrupt::<T>);
61 irq.unpend(); 75 irq.unpend();
62 irq.enable(); 76 irq.enable();
@@ -159,8 +173,6 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
159 173
160 fn read<'a>(buf: &'a mut [u8]) -> impl Future<Output = Result<usize, Error>> + 'a { 174 fn read<'a>(buf: &'a mut [u8]) -> impl Future<Output = Result<usize, Error>> + 'a {
161 poll_fn(move |cx| { 175 poll_fn(move |cx| {
162 unsafe { T::Interrupt::steal() }.pend();
163
164 let state = T::state(); 176 let state = T::state();
165 let mut rx_reader = unsafe { state.rx_buf.reader() }; 177 let mut rx_reader = unsafe { state.rx_buf.reader() };
166 let n = rx_reader.pop(|data| { 178 let n = rx_reader.pop(|data| {
@@ -173,14 +185,22 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
173 return Poll::Pending; 185 return Poll::Pending;
174 } 186 }
175 187
188 // (Re-)Enable the interrupt to receive more data in case it was
189 // disabled because the buffer was full.
190 let regs = T::regs();
191 unsafe {
192 regs.uartimsc().write_set(|w| {
193 w.set_rxim(true);
194 w.set_rtim(true);
195 });
196 }
197
176 Poll::Ready(Ok(n)) 198 Poll::Ready(Ok(n))
177 }) 199 })
178 } 200 }
179 201
180 fn fill_buf<'a>() -> impl Future<Output = Result<&'a [u8], Error>> { 202 fn fill_buf<'a>() -> impl Future<Output = Result<&'a [u8], Error>> {
181 poll_fn(move |cx| { 203 poll_fn(move |cx| {
182 unsafe { T::Interrupt::steal() }.pend();
183
184 let state = T::state(); 204 let state = T::state();
185 let mut rx_reader = unsafe { state.rx_buf.reader() }; 205 let mut rx_reader = unsafe { state.rx_buf.reader() };
186 let (p, n) = rx_reader.pop_buf(); 206 let (p, n) = rx_reader.pop_buf();
@@ -198,6 +218,16 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
198 let state = T::state(); 218 let state = T::state();
199 let mut rx_reader = unsafe { state.rx_buf.reader() }; 219 let mut rx_reader = unsafe { state.rx_buf.reader() };
200 rx_reader.pop_done(amt); 220 rx_reader.pop_done(amt);
221
222 // (Re-)Enable the interrupt to receive more data in case it was
223 // disabled because the buffer was full.
224 let regs = T::regs();
225 unsafe {
226 regs.uartimsc().write_set(|w| {
227 w.set_rxim(true);
228 w.set_rtim(true);
229 });
230 }
201 } 231 }
202} 232}
203 233
@@ -250,6 +280,10 @@ impl<'d, T: Instance> BufferedUartTx<'d, T> {
250 return Poll::Pending; 280 return Poll::Pending;
251 } 281 }
252 282
283 // The TX interrupt only triggers when the there was data in the
284 // FIFO and the number of bytes drops below a threshold. When the
285 // FIFO was empty we have to manually pend the interrupt to shovel
286 // TX data from the buffer into the FIFO.
253 unsafe { T::Interrupt::steal() }.pend(); 287 unsafe { T::Interrupt::steal() }.pend();
254 Poll::Ready(Ok(n)) 288 Poll::Ready(Ok(n))
255 }) 289 })
@@ -299,14 +333,22 @@ impl<'d, T: Instance> Drop for BufferedUartTx<'d, T> {
299} 333}
300 334
301pub(crate) unsafe fn on_interrupt<T: Instance>(_: *mut ()) { 335pub(crate) unsafe fn on_interrupt<T: Instance>(_: *mut ()) {
302 trace!("on_interrupt");
303
304 let r = T::regs(); 336 let r = T::regs();
305 let s = T::state(); 337 let s = T::state();
306 338
307 unsafe { 339 unsafe {
340 // Clear TX and error interrupt flags
341 // RX interrupt flags are cleared by reading from the FIFO.
308 let ris = r.uartris().read(); 342 let ris = r.uartris().read();
309 let mut mis = r.uartimsc().read(); 343 r.uarticr().write(|w| {
344 w.set_txic(ris.txris());
345 w.set_feic(ris.feris());
346 w.set_peic(ris.peris());
347 w.set_beic(ris.beris());
348 w.set_oeic(ris.oeris());
349 });
350
351 trace!("on_interrupt ris={=u32:#X}", ris.0);
310 352
311 // Errors 353 // Errors
312 if ris.feris() { 354 if ris.feris() {
@@ -321,13 +363,6 @@ pub(crate) unsafe fn on_interrupt<T: Instance>(_: *mut ()) {
321 if ris.oeris() { 363 if ris.oeris() {
322 warn!("Overrun error"); 364 warn!("Overrun error");
323 } 365 }
324 // Clear any error flags
325 r.uarticr().write(|w| {
326 w.set_feic(true);
327 w.set_peic(true);
328 w.set_beic(true);
329 w.set_oeic(true);
330 });
331 366
332 // RX 367 // RX
333 let mut rx_writer = s.rx_buf.writer(); 368 let mut rx_writer = s.rx_buf.writer();
@@ -345,8 +380,12 @@ pub(crate) unsafe fn on_interrupt<T: Instance>(_: *mut ()) {
345 s.rx_waker.wake(); 380 s.rx_waker.wake();
346 } 381 }
347 // Disable any further RX interrupts when the buffer becomes full. 382 // Disable any further RX interrupts when the buffer becomes full.
348 mis.set_rxim(!s.rx_buf.is_full()); 383 if s.rx_buf.is_full() {
349 mis.set_rtim(!s.rx_buf.is_full()); 384 r.uartimsc().write_clear(|w| {
385 w.set_rxim(true);
386 w.set_rtim(true);
387 });
388 }
350 389
351 // TX 390 // TX
352 let mut tx_reader = s.tx_buf.reader(); 391 let mut tx_reader = s.tx_buf.reader();
@@ -363,11 +402,9 @@ pub(crate) unsafe fn on_interrupt<T: Instance>(_: *mut ()) {
363 tx_reader.pop_done(n_written); 402 tx_reader.pop_done(n_written);
364 s.tx_waker.wake(); 403 s.tx_waker.wake();
365 } 404 }
366 // Disable the TX interrupt when we do not have more data to send. 405 // The TX interrupt only triggers once when the FIFO threshold is
367 mis.set_txim(!s.tx_buf.is_empty()); 406 // crossed. No need to disable it when the buffer becomes empty
368 407 // as it does re-trigger anymore once we have cleared it.
369 // Update interrupt mask.
370 r.uartimsc().write_value(mis);
371 } 408 }
372} 409}
373 410