Skip to content

Commit fb1f6a6

Browse files
authored
Merge pull request #73 from jonas-schievink/serial-irq
Improve the UART IRQ / Event API
2 parents 32bc900 + f528951 commit fb1f6a6

File tree

1 file changed

+104
-44
lines changed

1 file changed

+104
-44
lines changed

src/serial.rs

Lines changed: 104 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ pub use crate::{
2828
gpio::gpiob::*,
2929
gpio::gpioc::*,
3030
gpio::gpiod::*,
31-
gpio::gpioe::*,
31+
gpio::gpioe::*,
3232
pac::{LPUART1, USART1, USART4, USART5},
3333
};
3434

@@ -52,11 +52,19 @@ pub enum Error {
5252

5353
/// Interrupt event
5454
pub enum Event {
55-
/// New data has been received
55+
/// New data has been received.
56+
///
57+
/// This event is cleared by reading a character from the UART.
5658
Rxne,
57-
/// New data can be sent
59+
/// New data can be sent.
60+
///
61+
/// This event is cleared by writing a character to the UART.
62+
///
63+
/// Note that this event does not mean that the character in the TX buffer
64+
/// is fully transmitted. It only means that the TX buffer is ready to take
65+
/// another character to be transmitted.
5866
Txe,
59-
/// Idle line state detected
67+
/// Idle line state detected.
6068
Idle,
6169
}
6270

@@ -181,7 +189,7 @@ impl_pins!(
181189
USART4, PC10, PC11, AF6;
182190
USART4, PE8, PE9, AF6;
183191
USART5, PB3, PB4, AF6;
184-
USART5, PE10, PE11, AF6;
192+
USART5, PE10, PE11, AF6;
185193
);
186194

187195
/// Serial abstraction
@@ -330,13 +338,47 @@ macro_rules! usart {
330338
}
331339
}
332340

333-
/// Clears interrupt flag
334-
pub fn clear_irq(&mut self, event: Event) {
335-
if let Event::Rxne = event {
336-
self.usart.rqr.write(|w| w.rxfrq().discard())
341+
/// Returns a pending and enabled `Event`.
342+
///
343+
/// Multiple `Event`s can be signaled at the same time. In that case, an arbitrary
344+
/// pending event will be returned. Clearing the event condition will cause this
345+
/// method to return the other pending event(s).
346+
///
347+
/// For an event to be returned by this method, it must first be enabled by calling
348+
/// `listen`.
349+
///
350+
/// This method will never clear a pending event. If the event condition is not
351+
/// resolved by the user, it will be returned again by the next call to
352+
/// `pending_event`.
353+
pub fn pending_event(&self) -> Option<Event> {
354+
let cr1 = self.usart.cr1.read();
355+
let isr = self.usart.isr.read();
356+
357+
if cr1.rxneie().bit_is_set() && isr.rxne().bit_is_set() {
358+
// Give highest priority to RXNE to help with avoiding overrun
359+
Some(Event::Rxne)
360+
} else if cr1.txeie().bit_is_set() && isr.txe().bit_is_set() {
361+
Some(Event::Txe)
362+
} else if cr1.idleie().bit_is_set() && isr.idle().bit_is_set() {
363+
Some(Event::Idle)
364+
} else {
365+
None
337366
}
338367
}
339368

369+
/// Checks for reception errors that may have occurred.
370+
///
371+
/// Note that multiple errors can be signaled at the same time. In that case,
372+
/// calling this function repeatedly will return the remaining errors.
373+
pub fn check_errors(&mut self) -> Result<(), Error> {
374+
self.rx.check_errors()
375+
}
376+
377+
/// Clears any signaled errors without returning them.
378+
pub fn clear_errors(&mut self) {
379+
self.rx.clear_errors()
380+
}
381+
340382
pub fn split(self) -> (Tx<$USARTX>, Rx<$USARTX>) {
341383
(self.tx, self.rx)
342384
}
@@ -366,7 +408,49 @@ macro_rules! usart {
366408
}
367409
}
368410

369-
#[cfg(any(feature = "stm32l0x2", feature = "stm32l0x3"))]
411+
impl Rx<$USARTX> {
412+
/// Checks for reception errors that may have occurred.
413+
///
414+
/// Note that multiple errors can be signaled at the same time. In that case,
415+
/// calling this function repeatedly will return the remaining errors.
416+
pub fn check_errors(&mut self) -> Result<(), Error> {
417+
let isr = unsafe { (*$USARTX::ptr()).isr.read() };
418+
let icr = unsafe { &(*$USARTX::ptr()).icr };
419+
420+
// We don't want to drop any errors, so check each error bit in sequence. If
421+
// any bit is set, clear it and return its error.
422+
if isr.pe().bit_is_set() {
423+
icr.write(|w| {w.pecf().set_bit()});
424+
return Err(Error::Parity.into());
425+
} else if isr.fe().bit_is_set() {
426+
icr.write(|w| {w.fecf().set_bit()});
427+
return Err(Error::Framing.into());
428+
} else if isr.nf().bit_is_set() {
429+
icr.write(|w| {w.ncf().set_bit()});
430+
return Err(Error::Noise.into());
431+
} else if isr.ore().bit_is_set() {
432+
icr.write(|w| {w.orecf().set_bit()});
433+
return Err(Error::Overrun.into());
434+
}
435+
436+
Ok(())
437+
}
438+
439+
/// Clears any signaled errors without returning them.
440+
pub fn clear_errors(&mut self) {
441+
let icr = unsafe { &(*$USARTX::ptr()).icr };
442+
443+
icr.write(|w| w
444+
.pecf().set_bit()
445+
.fecf().set_bit()
446+
.ncf().set_bit()
447+
.orecf().set_bit()
448+
);
449+
}
450+
}
451+
452+
/// DMA operations.
453+
#[cfg(any(feature = "stm32l0x2", feature = "stm32l0x3"))]
370454
impl Rx<$USARTX> {
371455
pub fn read_all<Buffer, Channel>(self,
372456
dma: &mut dma::Handle,
@@ -423,44 +507,20 @@ macro_rules! usart {
423507
type Error = Error;
424508

425509
fn read(&mut self) -> nb::Result<u8, Error> {
510+
self.check_errors()?;
511+
426512
// NOTE(unsafe) atomic read with no side effects
427513
let isr = unsafe { (*$USARTX::ptr()).isr.read() };
428514

429-
// Check for any errors
430-
let _err = if isr.pe().bit_is_set() {
431-
Some(Error::Parity)
432-
} else if isr.fe().bit_is_set() {
433-
Some(Error::Framing)
434-
} else if isr.nf().bit_is_set() {
435-
Some(Error::Noise)
436-
} else if isr.ore().bit_is_set() {
437-
Some(Error::Overrun)
438-
} else {
439-
None
440-
};
441-
442-
if let Some(_err) = _err {
443-
// Some error occured. Clear the error flags by writing to ICR
444-
// followed by a read from the rdr register
515+
// Check if a byte is available
516+
if isr.rxne().bit_is_set() {
517+
// Read the received byte
445518
// NOTE(read_volatile) see `write_volatile` below
446-
unsafe {
447-
(*$USARTX::ptr()).icr.write(|w| {w.pecf().set_bit()});
448-
(*$USARTX::ptr()).icr.write(|w| {w.fecf().set_bit()});
449-
(*$USARTX::ptr()).icr.write(|w| {w.ncf().set_bit()});
450-
(*$USARTX::ptr()).icr.write(|w| {w.orecf().set_bit()});
451-
}
452-
Err(nb::Error::WouldBlock)
519+
Ok(unsafe {
520+
ptr::read_volatile(&(*$USARTX::ptr()).rdr as *const _ as *const _)
521+
})
453522
} else {
454-
// Check if a byte is available
455-
if isr.rxne().bit_is_set() {
456-
// Read the received byte
457-
// NOTE(read_volatile) see `write_volatile` below
458-
Ok(unsafe {
459-
ptr::read_volatile(&(*$USARTX::ptr()).rdr as *const _ as *const _)
460-
})
461-
} else {
462-
Err(nb::Error::WouldBlock)
463-
}
523+
Err(nb::Error::WouldBlock)
464524
}
465525
}
466526
}
@@ -569,7 +629,7 @@ usart! {
569629
USART1: (usart1, apb2enr, usart1en, apb1_clk, Serial1Ext),
570630
USART2: (usart2, apb1enr, usart2en, apb1_clk, Serial2Ext),
571631
USART4: (usart4, apb1enr, usart4en, apb1_clk, Serial4Ext),
572-
USART5: (usart5, apb1enr, usart5en, apb1_clk, Serial5Ext),
632+
USART5: (usart5, apb1enr, usart5en, apb1_clk, Serial5Ext),
573633
}
574634

575635
impl<USART> fmt::Write for Serial<USART>

0 commit comments

Comments
 (0)