Skip to content

Commit 8e9f315

Browse files
authored
Optimize UART buffered read with active detection (#549)
Replace fixed polling with interrupt-driven approach: enable START and RXLVL interrupts to wake when data arrives, check rxidle/start status, then poll. Reduces CPU usage while maintaining responsiveness.
1 parent b5f7c51 commit 8e9f315

File tree

1 file changed

+70
-45
lines changed

1 file changed

+70
-45
lines changed

src/uart.rs

Lines changed: 70 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -911,53 +911,63 @@ impl<'a> UartRx<'a, Async> {
911911
dma::PingPongSelector::BufferB => dma::PingPongSelector::BufferA,
912912
};
913913
}
914-
} else {
915-
// No data available, wait for new data to arrive or error condition
916-
let res = select(
917-
embassy_time::Timer::after_micros(buffer_config.polling_rate),
918-
// detect bus errors
919-
poll_fn(|cx| {
920-
self.info.rx_waker.register(cx.waker());
921-
922-
self.info
923-
.regs
924-
.intenset()
925-
.write(|w| w.framerren().set_bit().parityerren().set_bit().rxnoiseen().set_bit());
926-
self.info.regs.fifointenset().write(|w| w.rxerr().set_bit());
927-
928-
let stat = self.info.regs.stat().read();
929-
let fifointstat = self.info.regs.fifointstat().read();
930-
931-
self.info.regs.stat().write(|w| {
932-
w.framerrint()
933-
.clear_bit_by_one()
934-
.parityerrint()
935-
.clear_bit_by_one()
936-
.rxnoiseint()
937-
.clear_bit_by_one()
938-
});
939-
940-
self.info.regs.fifostat().write(|w| w.rxerr().set_bit());
941-
942-
if stat.framerrint().bit_is_set() {
943-
Poll::Ready(Err(Error::Framing))
944-
} else if stat.parityerrint().bit_is_set() {
945-
Poll::Ready(Err(Error::Parity))
946-
} else if stat.rxnoiseint().bit_is_set() {
947-
Poll::Ready(Err(Error::Noise))
948-
} else if fifointstat.rxerr().bit_is_set() {
949-
Poll::Ready(Err(Error::Overrun))
950-
} else {
951-
Poll::Pending
952-
}
953-
}),
954-
)
955-
.await;
956914

957-
match res {
958-
Either::First(()) | Either::Second(Ok(())) => (),
959-
Either::Second(Err(e)) => return Err(e),
915+
// No need to delay if we already has all the data we requested
916+
if bytes_read < buf.len() {
917+
embassy_time::Timer::after_micros(buffer_config.polling_rate).await;
960918
}
919+
} else {
920+
poll_fn(|cx| {
921+
self.info.rx_waker.register(cx.waker());
922+
923+
self.info.regs.intenset().write(|w| {
924+
w.framerren()
925+
.set_bit()
926+
.parityerren()
927+
.set_bit()
928+
.rxnoiseen()
929+
.set_bit()
930+
.starten()
931+
.set_bit()
932+
});
933+
934+
self.info.regs.fifointenset().write(|w| w.rxerr().set_bit());
935+
936+
let stat = self.info.regs.stat().read();
937+
let fifointstat = self.info.regs.fifointstat().read();
938+
939+
self.info.regs.stat().write(|w| {
940+
w.framerrint()
941+
.clear_bit_by_one()
942+
.parityerrint()
943+
.clear_bit_by_one()
944+
.rxnoiseint()
945+
.clear_bit_by_one()
946+
.start()
947+
.clear_bit_by_one()
948+
});
949+
950+
self.info
951+
.regs
952+
.fifotrig()
953+
.modify(|_, w| unsafe { w.rxlvlena().set_bit().rxlvl().bits(0) });
954+
self.info.regs.fifointenset().write(|w| w.rxlvl().set_bit());
955+
956+
if stat.framerrint().bit_is_set() {
957+
Poll::Ready(Err(Error::Framing))
958+
} else if stat.parityerrint().bit_is_set() {
959+
Poll::Ready(Err(Error::Parity))
960+
} else if stat.rxnoiseint().bit_is_set() {
961+
Poll::Ready(Err(Error::Noise))
962+
} else if fifointstat.rxerr().bit_is_set() {
963+
Poll::Ready(Err(Error::Overrun))
964+
} else if stat.rxidle().bit_is_clear() || stat.start().bit_is_set() {
965+
Poll::Ready(Ok(()))
966+
} else {
967+
Poll::Pending
968+
}
969+
})
970+
.await?;
961971
}
962972
}
963973
Ok(bytes_read)
@@ -1477,16 +1487,31 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
14771487
T::rx_waker().wake();
14781488
}
14791489

1490+
if stat.start().bit_is_set() {
1491+
regs.intenclr().write(|w| w.startclr().set_bit());
1492+
T::rx_waker().wake();
1493+
}
1494+
14801495
let fifointstat = regs.fifointstat().read();
14811496
if fifointstat.txerr().bit_is_set() {
14821497
regs.fifointenclr().write(|w| w.txerr().set_bit());
14831498
T::tx_waker().wake();
14841499
}
14851500

1501+
if fifointstat.txlvl().bit_is_set() {
1502+
regs.fifointenclr().write(|w| w.txlvl().set_bit());
1503+
T::tx_waker().wake();
1504+
}
1505+
14861506
if fifointstat.rxerr().bit_is_set() {
14871507
regs.fifointenclr().write(|w| w.rxerr().set_bit());
14881508
T::rx_waker().wake();
14891509
}
1510+
1511+
if fifointstat.rxlvl().bit_is_set() {
1512+
regs.fifointenclr().write(|w| w.rxlvl().set_bit());
1513+
T::rx_waker().wake();
1514+
}
14901515
}
14911516
}
14921517

0 commit comments

Comments
 (0)