continue improvements
This commit is contained in:
parent
dc7918a696
commit
731fe7ca4f
@ -308,12 +308,6 @@ pub struct Uart<UartInstance, Pins> {
|
|||||||
/// Serial receiver
|
/// Serial receiver
|
||||||
pub struct Rx<Uart>(Uart);
|
pub struct Rx<Uart>(Uart);
|
||||||
|
|
||||||
// Serial receiver, using interrupts to offload reading to the hardware.
|
|
||||||
pub struct RxWithIrq<Uart> {
|
|
||||||
inner: Rx<Uart>,
|
|
||||||
// irq_info: IrqContextTimeoutOrMaxSize,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Serial transmitter
|
/// Serial transmitter
|
||||||
pub struct Tx<Uart>(Uart);
|
pub struct Tx<Uart>(Uart);
|
||||||
|
|
||||||
@ -588,7 +582,7 @@ impl<TxPinInst: TxPin<UartInstance>, RxPinInst: RxPin<UartInstance>, UartInstanc
|
|||||||
) {
|
) {
|
||||||
let (inner, pins) = self.downgrade_internal();
|
let (inner, pins) = self.downgrade_internal();
|
||||||
let (tx, rx) = inner.split();
|
let (tx, rx) = inner.split();
|
||||||
(tx, RxWithIrq { inner: rx }, pins)
|
(tx, RxWithIrq(rx), pins)
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate::delegate! {
|
delegate::delegate! {
|
||||||
@ -715,15 +709,23 @@ pub enum IrqError {
|
|||||||
Uart(IrqUartError),
|
Uart(IrqUartError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Serial receiver, using interrupts to offload reading to the hardware.
|
||||||
|
pub struct RxWithIrq<Uart>(Rx<Uart>);
|
||||||
|
|
||||||
impl<Uart: Instance> RxWithIrq<Uart> {
|
impl<Uart: Instance> RxWithIrq<Uart> {
|
||||||
/// This function should be called once at initialization time if the regular
|
/// This function should be called once at initialization time if the regular
|
||||||
/// [Self::irq_handler] is used to read the UART receiver to enable and start the receiver.
|
/// [Self::irq_handler] is used to read the UART receiver to enable and start the receiver.
|
||||||
pub fn start(&mut self) {
|
pub fn start(&mut self) {
|
||||||
self.inner.enable();
|
self.0.enable();
|
||||||
self.enable_rx_irq_sources(true);
|
self.enable_rx_irq_sources(true);
|
||||||
unsafe { enable_interrupt(Uart::IRQ_RX) };
|
unsafe { enable_interrupt(Uart::IRQ_RX) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn uart(&self) -> &Uart {
|
||||||
|
&self.0 .0
|
||||||
|
}
|
||||||
|
|
||||||
/// This function is used together with the [Self::irq_handler_max_size_or_timeout_based]
|
/// This function is used together with the [Self::irq_handler_max_size_or_timeout_based]
|
||||||
/// function to read packets with a maximum size or variable sized packets by using the
|
/// function to read packets with a maximum size or variable sized packets by using the
|
||||||
/// receive timeout of the hardware.
|
/// receive timeout of the hardware.
|
||||||
@ -747,7 +749,7 @@ impl<Uart: Instance> RxWithIrq<Uart> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn enable_rx_irq_sources(&mut self, timeout: bool) {
|
fn enable_rx_irq_sources(&mut self, timeout: bool) {
|
||||||
self.inner.0.irq_enb().modify(|_, w| {
|
self.uart().irq_enb().modify(|_, w| {
|
||||||
if timeout {
|
if timeout {
|
||||||
w.irq_rx_to().set_bit();
|
w.irq_rx_to().set_bit();
|
||||||
}
|
}
|
||||||
@ -758,7 +760,7 @@ impl<Uart: Instance> RxWithIrq<Uart> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn disable_rx_irq_sources(&mut self) {
|
fn disable_rx_irq_sources(&mut self) {
|
||||||
self.inner.0.irq_enb().modify(|_, w| {
|
self.uart().irq_enb().modify(|_, w| {
|
||||||
w.irq_rx_to().clear_bit();
|
w.irq_rx_to().clear_bit();
|
||||||
w.irq_rx_status().clear_bit();
|
w.irq_rx_status().clear_bit();
|
||||||
w.irq_rx().clear_bit()
|
w.irq_rx().clear_bit()
|
||||||
@ -767,11 +769,7 @@ impl<Uart: Instance> RxWithIrq<Uart> {
|
|||||||
|
|
||||||
pub fn cancel_transfer(&mut self) {
|
pub fn cancel_transfer(&mut self) {
|
||||||
self.disable_rx_irq_sources();
|
self.disable_rx_irq_sources();
|
||||||
self.inner.clear_fifo();
|
self.0.clear_fifo();
|
||||||
}
|
|
||||||
|
|
||||||
pub fn uart(&self) -> &Uart {
|
|
||||||
&self.inner.0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function should be called in the user provided UART interrupt handler.
|
/// This function should be called in the user provided UART interrupt handler.
|
||||||
@ -785,8 +783,8 @@ impl<Uart: Instance> RxWithIrq<Uart> {
|
|||||||
let mut result = IrqResult::default();
|
let mut result = IrqResult::default();
|
||||||
let mut current_idx = 0;
|
let mut current_idx = 0;
|
||||||
|
|
||||||
let irq_end = self.inner.0.irq_end().read();
|
let irq_end = self.uart().irq_end().read();
|
||||||
let enb_status = self.inner.0.enable().read();
|
let enb_status = self.uart().enable().read();
|
||||||
let rx_enabled = enb_status.rxenable().bit_is_set();
|
let rx_enabled = enb_status.rxenable().bit_is_set();
|
||||||
|
|
||||||
// Half-Full interrupt. We have a guaranteed amount of data we can read.
|
// Half-Full interrupt. We have a guaranteed amount of data we can read.
|
||||||
@ -795,19 +793,19 @@ impl<Uart: Instance> RxWithIrq<Uart> {
|
|||||||
// We use this trick/hack because the timeout feature of the peripheral relies on data
|
// We use this trick/hack because the timeout feature of the peripheral relies on data
|
||||||
// being in the RX FIFO. If data continues arriving, another half-full IRQ will fire.
|
// being in the RX FIFO. If data continues arriving, another half-full IRQ will fire.
|
||||||
// If not, the last byte(s) is/are emptied by the timeout interrupt.
|
// If not, the last byte(s) is/are emptied by the timeout interrupt.
|
||||||
let available_bytes = self.inner.0.rxfifoirqtrg().read().bits() as usize;
|
let available_bytes = self.uart().rxfifoirqtrg().read().bits() as usize;
|
||||||
|
|
||||||
// If this interrupt bit is set, the trigger level is available at the very least.
|
// If this interrupt bit is set, the trigger level is available at the very least.
|
||||||
// Read everything as fast as possible
|
// Read everything as fast as possible
|
||||||
for _ in 0..available_bytes {
|
for _ in 0..available_bytes {
|
||||||
buf[current_idx] = (self.inner.0.data().read().bits() & 0xff) as u8;
|
buf[current_idx] = (self.uart().data().read().bits() & 0xff) as u8;
|
||||||
current_idx += 1;
|
current_idx += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timeout, empty the FIFO completely.
|
// Timeout, empty the FIFO completely.
|
||||||
if irq_end.irq_rx_to().bit_is_set() {
|
if irq_end.irq_rx_to().bit_is_set() {
|
||||||
let read_result = self.inner.read();
|
let read_result = self.0.read();
|
||||||
// While there is data in the FIFO, write it into the reception buffer
|
// While there is data in the FIFO, write it into the reception buffer
|
||||||
while let Some(byte) = self.read_handler(&mut result.errors, &read_result) {
|
while let Some(byte) = self.read_handler(&mut result.errors, &read_result) {
|
||||||
buf[current_idx] = byte;
|
buf[current_idx] = byte;
|
||||||
@ -821,8 +819,7 @@ impl<Uart: Instance> RxWithIrq<Uart> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Clear the interrupt status bits
|
// Clear the interrupt status bits
|
||||||
self.inner
|
self.uart()
|
||||||
.0
|
|
||||||
.irq_clr()
|
.irq_clr()
|
||||||
.write(|w| unsafe { w.bits(irq_end.bits()) });
|
.write(|w| unsafe { w.bits(irq_end.bits()) });
|
||||||
Ok(result)
|
Ok(result)
|
||||||
@ -852,8 +849,8 @@ impl<Uart: Instance> RxWithIrq<Uart> {
|
|||||||
}
|
}
|
||||||
let mut result = IrqResultMaxSizeTimeout::default();
|
let mut result = IrqResultMaxSizeTimeout::default();
|
||||||
|
|
||||||
let irq_end = self.inner.0.irq_end().read();
|
let irq_end = self.uart().irq_end().read();
|
||||||
let enb_status = self.inner.0.enable().read();
|
let enb_status = self.uart().enable().read();
|
||||||
let rx_enabled = enb_status.rxenable().bit_is_set();
|
let rx_enabled = enb_status.rxenable().bit_is_set();
|
||||||
|
|
||||||
// Half-Full interrupt. We have a guaranteed amount of data we can read.
|
// Half-Full interrupt. We have a guaranteed amount of data we can read.
|
||||||
@ -862,7 +859,7 @@ impl<Uart: Instance> RxWithIrq<Uart> {
|
|||||||
// We use this trick/hack because the timeout feature of the peripheral relies on data
|
// We use this trick/hack because the timeout feature of the peripheral relies on data
|
||||||
// being in the RX FIFO. If data continues arriving, another half-full IRQ will fire.
|
// being in the RX FIFO. If data continues arriving, another half-full IRQ will fire.
|
||||||
// If not, the last byte(s) is/are emptied by the timeout interrupt.
|
// If not, the last byte(s) is/are emptied by the timeout interrupt.
|
||||||
let available_bytes = self.inner.0.rxfifoirqtrg().read().bits() as usize;
|
let available_bytes = self.uart().rxfifoirqtrg().read().bits() as usize;
|
||||||
|
|
||||||
let bytes_to_read = core::cmp::min(
|
let bytes_to_read = core::cmp::min(
|
||||||
available_bytes.saturating_sub(1),
|
available_bytes.saturating_sub(1),
|
||||||
@ -872,7 +869,7 @@ impl<Uart: Instance> RxWithIrq<Uart> {
|
|||||||
// If this interrupt bit is set, the trigger level is available at the very least.
|
// If this interrupt bit is set, the trigger level is available at the very least.
|
||||||
// Read everything as fast as possible
|
// Read everything as fast as possible
|
||||||
for _ in 0..bytes_to_read {
|
for _ in 0..bytes_to_read {
|
||||||
buf[context.rx_idx] = (self.inner.0.data().read().bits() & 0xff) as u8;
|
buf[context.rx_idx] = (self.uart().data().read().bits() & 0xff) as u8;
|
||||||
context.rx_idx += 1;
|
context.rx_idx += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -888,7 +885,7 @@ impl<Uart: Instance> RxWithIrq<Uart> {
|
|||||||
if context.rx_idx == context.max_len {
|
if context.rx_idx == context.max_len {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
let read_result = self.inner.read();
|
let read_result = self.0.read();
|
||||||
if let Some(byte) = self.read_handler(&mut result.errors, &read_result) {
|
if let Some(byte) = self.read_handler(&mut result.errors, &read_result) {
|
||||||
buf[context.rx_idx] = byte;
|
buf[context.rx_idx] = byte;
|
||||||
context.rx_idx += 1;
|
context.rx_idx += 1;
|
||||||
@ -906,8 +903,7 @@ impl<Uart: Instance> RxWithIrq<Uart> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Clear the interrupt status bits
|
// Clear the interrupt status bits
|
||||||
self.inner
|
self.uart()
|
||||||
.0
|
|
||||||
.irq_clr()
|
.irq_clr()
|
||||||
.write(|w| unsafe { w.bits(irq_end.bits()) });
|
.write(|w| unsafe { w.bits(irq_end.bits()) });
|
||||||
Ok(result)
|
Ok(result)
|
||||||
@ -943,7 +939,7 @@ impl<Uart: Instance> RxWithIrq<Uart> {
|
|||||||
|
|
||||||
fn check_for_errors(&self, errors: &mut IrqUartError) {
|
fn check_for_errors(&self, errors: &mut IrqUartError) {
|
||||||
// Read status register again, might have changed since reading received data
|
// Read status register again, might have changed since reading received data
|
||||||
let rx_status = self.inner.0.rxstatus().read();
|
let rx_status = self.uart().rxstatus().read();
|
||||||
if rx_status.rxovr().bit_is_set() {
|
if rx_status.rxovr().bit_is_set() {
|
||||||
errors.overflow = true;
|
errors.overflow = true;
|
||||||
}
|
}
|
||||||
@ -961,7 +957,7 @@ impl<Uart: Instance> RxWithIrq<Uart> {
|
|||||||
context: &mut IrqContextTimeoutOrMaxSize,
|
context: &mut IrqContextTimeoutOrMaxSize,
|
||||||
) {
|
) {
|
||||||
self.disable_rx_irq_sources();
|
self.disable_rx_irq_sources();
|
||||||
self.inner.disable();
|
self.0.disable();
|
||||||
res.bytes_read = context.rx_idx;
|
res.bytes_read = context.rx_idx;
|
||||||
res.complete = true;
|
res.complete = true;
|
||||||
context.mode = IrqReceptionMode::Idle;
|
context.mode = IrqReceptionMode::Idle;
|
||||||
@ -969,7 +965,7 @@ impl<Uart: Instance> RxWithIrq<Uart> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn release(self) -> Uart {
|
pub fn release(self) -> Uart {
|
||||||
self.inner.release()
|
self.0.release()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user