rp: Disable RX interrupts when ring buffer is full
When data is in the RX fifo the RX timeout interrupt goes high again even after clearing it. The result is a deadlock because execution is stuck in the interrupt handler. No other code can run to clear the receive buffer. Enable and disable RX interrupts based on the buffer fill level. Use the same approach for the TX code path.
This commit is contained in:
parent
a24037edf9
commit
840a75674b
@ -49,15 +49,6 @@ fn init<'d, T: Instance + 'd>(
|
|||||||
rx_buffer: &'d mut [u8],
|
rx_buffer: &'d mut [u8],
|
||||||
config: Config,
|
config: Config,
|
||||||
) {
|
) {
|
||||||
let regs = T::regs();
|
|
||||||
unsafe {
|
|
||||||
regs.uartimsc().modify(|w| {
|
|
||||||
w.set_rxim(true);
|
|
||||||
w.set_rtim(true);
|
|
||||||
w.set_txim(true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
super::Uart::<'d, T, Async>::init(tx, rx, rts, cts, config);
|
super::Uart::<'d, T, Async>::init(tx, rx, rts, cts, config);
|
||||||
|
|
||||||
let state = T::state();
|
let state = T::state();
|
||||||
@ -168,6 +159,8 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
|
|||||||
|
|
||||||
fn read<'a>(buf: &'a mut [u8]) -> impl Future<Output = Result<usize, Error>> + 'a {
|
fn read<'a>(buf: &'a mut [u8]) -> impl Future<Output = Result<usize, Error>> + 'a {
|
||||||
poll_fn(move |cx| {
|
poll_fn(move |cx| {
|
||||||
|
unsafe { T::Interrupt::steal() }.pend();
|
||||||
|
|
||||||
let state = T::state();
|
let state = T::state();
|
||||||
let mut rx_reader = unsafe { state.rx_buf.reader() };
|
let mut rx_reader = unsafe { state.rx_buf.reader() };
|
||||||
let n = rx_reader.pop(|data| {
|
let n = rx_reader.pop(|data| {
|
||||||
@ -186,6 +179,8 @@ impl<'d, T: Instance> BufferedUartRx<'d, T> {
|
|||||||
|
|
||||||
fn fill_buf<'a>() -> impl Future<Output = Result<&'a [u8], Error>> {
|
fn fill_buf<'a>() -> impl Future<Output = Result<&'a [u8], Error>> {
|
||||||
poll_fn(move |cx| {
|
poll_fn(move |cx| {
|
||||||
|
unsafe { T::Interrupt::steal() }.pend();
|
||||||
|
|
||||||
let state = T::state();
|
let state = T::state();
|
||||||
let mut rx_reader = unsafe { state.rx_buf.reader() };
|
let mut rx_reader = unsafe { state.rx_buf.reader() };
|
||||||
let (p, n) = rx_reader.pop_buf();
|
let (p, n) = rx_reader.pop_buf();
|
||||||
@ -310,40 +305,31 @@ pub(crate) unsafe fn on_interrupt<T: Instance>(_: *mut ()) {
|
|||||||
let s = T::state();
|
let s = T::state();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// RX
|
|
||||||
|
|
||||||
let ris = r.uartris().read();
|
let ris = r.uartris().read();
|
||||||
// Clear interrupt flags
|
let mut mis = r.uartimsc().read();
|
||||||
r.uarticr().write(|w| {
|
|
||||||
w.set_rxic(true);
|
|
||||||
w.set_rtic(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
if ris.peris() {
|
// Errors
|
||||||
warn!("Parity error");
|
|
||||||
r.uarticr().write(|w| {
|
|
||||||
w.set_peic(true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if ris.feris() {
|
if ris.feris() {
|
||||||
warn!("Framing error");
|
warn!("Framing error");
|
||||||
r.uarticr().write(|w| {
|
}
|
||||||
w.set_feic(true);
|
if ris.peris() {
|
||||||
});
|
warn!("Parity error");
|
||||||
}
|
}
|
||||||
if ris.beris() {
|
if ris.beris() {
|
||||||
warn!("Break error");
|
warn!("Break error");
|
||||||
r.uarticr().write(|w| {
|
|
||||||
w.set_beic(true);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if ris.oeris() {
|
if ris.oeris() {
|
||||||
warn!("Overrun error");
|
warn!("Overrun error");
|
||||||
|
}
|
||||||
|
// Clear any error flags
|
||||||
r.uarticr().write(|w| {
|
r.uarticr().write(|w| {
|
||||||
|
w.set_feic(true);
|
||||||
|
w.set_peic(true);
|
||||||
|
w.set_beic(true);
|
||||||
w.set_oeic(true);
|
w.set_oeic(true);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
|
// RX
|
||||||
let mut rx_writer = s.rx_buf.writer();
|
let mut rx_writer = s.rx_buf.writer();
|
||||||
let rx_buf = rx_writer.push_slice();
|
let rx_buf = rx_writer.push_slice();
|
||||||
let mut n_read = 0;
|
let mut n_read = 0;
|
||||||
@ -358,20 +344,13 @@ pub(crate) unsafe fn on_interrupt<T: Instance>(_: *mut ()) {
|
|||||||
rx_writer.push_done(n_read);
|
rx_writer.push_done(n_read);
|
||||||
s.rx_waker.wake();
|
s.rx_waker.wake();
|
||||||
}
|
}
|
||||||
|
// Disable any further RX interrupts when the buffer becomes full.
|
||||||
|
mis.set_rxim(!s.rx_buf.is_full());
|
||||||
|
mis.set_rtim(!s.rx_buf.is_full());
|
||||||
|
|
||||||
// TX
|
// TX
|
||||||
let mut tx_reader = s.tx_buf.reader();
|
let mut tx_reader = s.tx_buf.reader();
|
||||||
let tx_buf = tx_reader.pop_slice();
|
let tx_buf = tx_reader.pop_slice();
|
||||||
if tx_buf.len() == 0 {
|
|
||||||
// Disable interrupt until we have something to transmit again
|
|
||||||
r.uartimsc().modify(|w| {
|
|
||||||
w.set_txim(false);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
r.uartimsc().modify(|w| {
|
|
||||||
w.set_txim(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut n_written = 0;
|
let mut n_written = 0;
|
||||||
for tx_byte in tx_buf.iter_mut() {
|
for tx_byte in tx_buf.iter_mut() {
|
||||||
if r.uartfr().read().txff() {
|
if r.uartfr().read().txff() {
|
||||||
@ -384,7 +363,11 @@ pub(crate) unsafe fn on_interrupt<T: Instance>(_: *mut ()) {
|
|||||||
tx_reader.pop_done(n_written);
|
tx_reader.pop_done(n_written);
|
||||||
s.tx_waker.wake();
|
s.tx_waker.wake();
|
||||||
}
|
}
|
||||||
}
|
// Disable the TX interrupt when we do not have more data to send.
|
||||||
|
mis.set_txim(!s.tx_buf.is_empty());
|
||||||
|
|
||||||
|
// Update interrupt mask.
|
||||||
|
r.uartimsc().write_value(mis);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user