mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-10-02 22:55:26 +00:00
Adding errors for receive and transmit read/write async (#1445)
* Adding errors for receive and transmit read/write async * rebase and fix ups --------- Co-authored-by: konsulten <nordmarkclaes@gmail.com>
This commit is contained in:
parent
1a5ca65eed
commit
89a3d56b15
@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- `GpioPin::steal` unsafe API (#1363)
|
- `GpioPin::steal` unsafe API (#1363)
|
||||||
- Inherent implementions of GPIO pin `set_low`, `is_low`, etc.
|
- Inherent implementions of GPIO pin `set_low`, `is_low`, etc.
|
||||||
- Warn users when attempting to build using the `dev` profile (#1420)
|
- Warn users when attempting to build using the `dev` profile (#1420)
|
||||||
|
- Async uart now reports interrupt errors(overflow, glitch, frame error, parity) back to user of read/write. uart clock decimal part configured for c2,c3,s3 (#1168, #1445)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
@ -101,6 +101,12 @@ pub enum Error {
|
|||||||
/// The RX FIFO overflowed
|
/// The RX FIFO overflowed
|
||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
RxFifoOvf,
|
RxFifoOvf,
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
RxGlitchDetected,
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
RxFrameError,
|
||||||
|
#[cfg(feature = "async")]
|
||||||
|
RxParityError,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "embedded-hal")]
|
#[cfg(feature = "embedded-hal")]
|
||||||
@ -544,6 +550,12 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Setting err_wr_mask stops uart from storing data when data is wrong according
|
||||||
|
// to reference manual
|
||||||
|
T::register_block()
|
||||||
|
.conf0()
|
||||||
|
.modify(|_, w| w.err_wr_mask().set_bit());
|
||||||
|
|
||||||
// Reset Tx/Rx FIFOs
|
// Reset Tx/Rx FIFOs
|
||||||
serial.txfifo_reset();
|
serial.txfifo_reset();
|
||||||
serial.rxfifo_reset();
|
serial.rxfifo_reset();
|
||||||
@ -861,9 +873,8 @@ where
|
|||||||
// we force the clock source to be APB and don't use the decimal part of the
|
// we force the clock source to be APB and don't use the decimal part of the
|
||||||
// divider
|
// divider
|
||||||
let clk = clocks.apb_clock.to_Hz();
|
let clk = clocks.apb_clock.to_Hz();
|
||||||
let max_div = 0b1111_1111_1111 - 1;
|
let max_div = 0b1111_1111_1111; // 12 bit clkdiv
|
||||||
let clk_div = ((clk) + (max_div * baudrate) - 1) / (max_div * baudrate);
|
let clk_div = ((clk) + (max_div * baudrate) - 1) / (max_div * baudrate);
|
||||||
|
|
||||||
T::register_block().clk_conf().write(|w| unsafe {
|
T::register_block().clk_conf().write(|w| unsafe {
|
||||||
w.sclk_sel()
|
w.sclk_sel()
|
||||||
.bits(1) // APB
|
.bits(1) // APB
|
||||||
@ -879,13 +890,12 @@ where
|
|||||||
.bit(true)
|
.bit(true)
|
||||||
});
|
});
|
||||||
|
|
||||||
let clk = clk / clk_div;
|
let divider = (clk << 4) / (baudrate * clk_div);
|
||||||
let divider = clk / baudrate;
|
let divider_integer = (divider >> 4) as u16;
|
||||||
let divider = divider as u16;
|
let divider_frag = (divider & 0xf) as u8;
|
||||||
|
|
||||||
T::register_block()
|
T::register_block()
|
||||||
.clkdiv()
|
.clkdiv()
|
||||||
.write(|w| unsafe { w.clkdiv().bits(divider).frag().bits(0) });
|
.write(|w| unsafe { w.clkdiv().bits(divider_integer).frag().bits(divider_frag) });
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(esp32c6, esp32h2))]
|
#[cfg(any(esp32c6, esp32h2))]
|
||||||
@ -1579,6 +1589,9 @@ mod asynch {
|
|||||||
RxCmdCharDetected,
|
RxCmdCharDetected,
|
||||||
RxFifoOvf,
|
RxFifoOvf,
|
||||||
RxFifoTout,
|
RxFifoTout,
|
||||||
|
RxGlitchDetected,
|
||||||
|
RxFrameError,
|
||||||
|
RxParityError,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A future that resolves when the passed interrupt is triggered,
|
/// A future that resolves when the passed interrupt is triggered,
|
||||||
@ -1606,11 +1619,11 @@ mod asynch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn event_bit_is_clear(&self) -> bool {
|
fn get_triggered_events(&self) -> EnumSet<RxEvent> {
|
||||||
let interrupts_enabled = T::register_block().int_ena().read();
|
let interrupts_enabled = T::register_block().int_ena().read();
|
||||||
let mut event_triggered = false;
|
let mut events_triggered = EnumSet::new();
|
||||||
for event in self.events {
|
for event in self.events {
|
||||||
event_triggered |= match event {
|
let event_triggered = match event {
|
||||||
RxEvent::RxFifoFull => interrupts_enabled.rxfifo_full().bit_is_clear(),
|
RxEvent::RxFifoFull => interrupts_enabled.rxfifo_full().bit_is_clear(),
|
||||||
RxEvent::RxCmdCharDetected => {
|
RxEvent::RxCmdCharDetected => {
|
||||||
interrupts_enabled.at_cmd_char_det().bit_is_clear()
|
interrupts_enabled.at_cmd_char_det().bit_is_clear()
|
||||||
@ -1618,14 +1631,20 @@ mod asynch {
|
|||||||
|
|
||||||
RxEvent::RxFifoOvf => interrupts_enabled.rxfifo_ovf().bit_is_clear(),
|
RxEvent::RxFifoOvf => interrupts_enabled.rxfifo_ovf().bit_is_clear(),
|
||||||
RxEvent::RxFifoTout => interrupts_enabled.rxfifo_tout().bit_is_clear(),
|
RxEvent::RxFifoTout => interrupts_enabled.rxfifo_tout().bit_is_clear(),
|
||||||
|
RxEvent::RxGlitchDetected => interrupts_enabled.glitch_det().bit_is_clear(),
|
||||||
|
RxEvent::RxFrameError => interrupts_enabled.frm_err().bit_is_clear(),
|
||||||
|
RxEvent::RxParityError => interrupts_enabled.parity_err().bit_is_clear(),
|
||||||
|
};
|
||||||
|
if event_triggered {
|
||||||
|
events_triggered |= event;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
event_triggered
|
events_triggered
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> core::future::Future for UartRxFuture<'d, T> {
|
impl<'d, T: Instance> core::future::Future for UartRxFuture<'d, T> {
|
||||||
type Output = ();
|
type Output = EnumSet<RxEvent>;
|
||||||
|
|
||||||
fn poll(
|
fn poll(
|
||||||
mut self: core::pin::Pin<&mut Self>,
|
mut self: core::pin::Pin<&mut Self>,
|
||||||
@ -1640,14 +1659,18 @@ mod asynch {
|
|||||||
RxEvent::RxCmdCharDetected => w.at_cmd_char_det().set_bit(),
|
RxEvent::RxCmdCharDetected => w.at_cmd_char_det().set_bit(),
|
||||||
RxEvent::RxFifoOvf => w.rxfifo_ovf().set_bit(),
|
RxEvent::RxFifoOvf => w.rxfifo_ovf().set_bit(),
|
||||||
RxEvent::RxFifoTout => w.rxfifo_tout().set_bit(),
|
RxEvent::RxFifoTout => w.rxfifo_tout().set_bit(),
|
||||||
|
RxEvent::RxGlitchDetected => w.glitch_det().set_bit(),
|
||||||
|
RxEvent::RxFrameError => w.frm_err().set_bit(),
|
||||||
|
RxEvent::RxParityError => w.parity_err().set_bit(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
w
|
w
|
||||||
});
|
});
|
||||||
self.registered = true;
|
self.registered = true;
|
||||||
}
|
}
|
||||||
if self.event_bit_is_clear() {
|
let events = self.get_triggered_events();
|
||||||
Poll::Ready(())
|
if !events.is_empty() {
|
||||||
|
Poll::Ready(events)
|
||||||
} else {
|
} else {
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
}
|
}
|
||||||
@ -1666,6 +1689,9 @@ mod asynch {
|
|||||||
RxEvent::RxCmdCharDetected => {
|
RxEvent::RxCmdCharDetected => {
|
||||||
int_ena.modify(|_, w| w.at_cmd_char_det().clear_bit())
|
int_ena.modify(|_, w| w.at_cmd_char_det().clear_bit())
|
||||||
}
|
}
|
||||||
|
RxEvent::RxGlitchDetected => int_ena.modify(|_, w| w.glitch_det().clear_bit()),
|
||||||
|
RxEvent::RxFrameError => int_ena.modify(|_, w| w.frm_err().clear_bit()),
|
||||||
|
RxEvent::RxParityError => int_ena.modify(|_, w| w.parity_err().clear_bit()),
|
||||||
RxEvent::RxFifoOvf => int_ena.modify(|_, w| w.rxfifo_ovf().clear_bit()),
|
RxEvent::RxFifoOvf => int_ena.modify(|_, w| w.rxfifo_ovf().clear_bit()),
|
||||||
RxEvent::RxFifoTout => int_ena.modify(|_, w| w.rxfifo_tout().clear_bit()),
|
RxEvent::RxFifoTout => int_ena.modify(|_, w| w.rxfifo_tout().clear_bit()),
|
||||||
}
|
}
|
||||||
@ -1682,7 +1708,7 @@ mod asynch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn event_bit_is_clear(&self) -> bool {
|
fn get_triggered_events(&self) -> bool {
|
||||||
let interrupts_enabled = T::register_block().int_ena().read();
|
let interrupts_enabled = T::register_block().int_ena().read();
|
||||||
let mut event_triggered = false;
|
let mut event_triggered = false;
|
||||||
for event in self.events {
|
for event in self.events {
|
||||||
@ -1716,7 +1742,7 @@ mod asynch {
|
|||||||
self.registered = true;
|
self.registered = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.event_bit_is_clear() {
|
if self.get_triggered_events() {
|
||||||
Poll::Ready(())
|
Poll::Ready(())
|
||||||
} else {
|
} else {
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
@ -1862,14 +1888,18 @@ mod asynch {
|
|||||||
///
|
///
|
||||||
/// # Ok
|
/// # Ok
|
||||||
/// When successful, returns the number of bytes written to buf.
|
/// When successful, returns the number of bytes written to buf.
|
||||||
/// This method will never return Ok(0), unless buf.len() == 0.
|
/// This method will never return Ok(0)
|
||||||
pub async fn read_async(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
pub async fn read_async(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
|
||||||
if buf.len() == 0 {
|
if buf.len() == 0 {
|
||||||
return Ok(0);
|
return Err(Error::InvalidArgument);
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut events = RxEvent::RxFifoFull | RxEvent::RxFifoOvf;
|
let mut events = RxEvent::RxFifoFull
|
||||||
|
| RxEvent::RxFifoOvf
|
||||||
|
| RxEvent::RxFrameError
|
||||||
|
| RxEvent::RxGlitchDetected
|
||||||
|
| RxEvent::RxParityError;
|
||||||
|
|
||||||
if self.at_cmd_config.is_some() {
|
if self.at_cmd_config.is_some() {
|
||||||
events |= RxEvent::RxCmdCharDetected;
|
events |= RxEvent::RxCmdCharDetected;
|
||||||
@ -1878,10 +1908,21 @@ mod asynch {
|
|||||||
if self.rx_timeout_config.is_some() {
|
if self.rx_timeout_config.is_some() {
|
||||||
events |= RxEvent::RxFifoTout;
|
events |= RxEvent::RxFifoTout;
|
||||||
}
|
}
|
||||||
UartRxFuture::<T>::new(events).await;
|
let events_happened = UartRxFuture::<T>::new(events).await;
|
||||||
|
// always drain the fifo, if an error has occurred the data is lost
|
||||||
let read_bytes = self.drain_fifo(buf);
|
let read_bytes = self.drain_fifo(buf);
|
||||||
if read_bytes > 0 {
|
// check error events
|
||||||
|
for event_happened in events_happened {
|
||||||
|
match event_happened {
|
||||||
|
RxEvent::RxFifoOvf => return Err(Error::RxFifoOvf),
|
||||||
|
RxEvent::RxGlitchDetected => return Err(Error::RxGlitchDetected),
|
||||||
|
RxEvent::RxFrameError => return Err(Error::RxFrameError),
|
||||||
|
RxEvent::RxParityError => return Err(Error::RxParityError),
|
||||||
|
RxEvent::RxFifoFull | RxEvent::RxCmdCharDetected | RxEvent::RxFifoTout => {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// Unfortunately, the uart's rx-timeout counter counts up whenever there is
|
// Unfortunately, the uart's rx-timeout counter counts up whenever there is
|
||||||
// data in the fifo, even if the interrupt is disabled and the status bit
|
// data in the fifo, even if the interrupt is disabled and the status bit
|
||||||
// cleared. Since we do not drain the fifo in the interrupt handler, we need to
|
// cleared. Since we do not drain the fifo in the interrupt handler, we need to
|
||||||
@ -1890,6 +1931,7 @@ mod asynch {
|
|||||||
.int_clr()
|
.int_clr()
|
||||||
.write(|w| w.rxfifo_tout().clear_bit_by_one());
|
.write(|w| w.rxfifo_tout().clear_bit_by_one());
|
||||||
|
|
||||||
|
if read_bytes > 0 {
|
||||||
return Ok(read_bytes);
|
return Ok(read_bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1959,7 +2001,10 @@ mod asynch {
|
|||||||
let rx_wake = interrupts.rxfifo_full().bit_is_set()
|
let rx_wake = interrupts.rxfifo_full().bit_is_set()
|
||||||
|| interrupts.rxfifo_ovf().bit_is_set()
|
|| interrupts.rxfifo_ovf().bit_is_set()
|
||||||
|| interrupts.rxfifo_tout().bit_is_set()
|
|| interrupts.rxfifo_tout().bit_is_set()
|
||||||
|| interrupts.at_cmd_char_det().bit_is_set();
|
|| interrupts.at_cmd_char_det().bit_is_set()
|
||||||
|
|| interrupts.glitch_det().bit_is_set()
|
||||||
|
|| interrupts.frm_err().bit_is_set()
|
||||||
|
|| interrupts.parity_err().bit_is_set();
|
||||||
let tx_wake = interrupts.tx_done().bit_is_set() || interrupts.txfifo_empty().bit_is_set();
|
let tx_wake = interrupts.tx_done().bit_is_set() || interrupts.txfifo_empty().bit_is_set();
|
||||||
uart.int_clr().write(|w| unsafe { w.bits(interrupt_bits) });
|
uart.int_clr().write(|w| unsafe { w.bits(interrupt_bits) });
|
||||||
uart.int_ena()
|
uart.int_ena()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user